1
+ {-# LANGUAGE CPP #-}
1
2
{-# LANGUAGE TupleSections #-}
2
3
3
4
module Refact.Apply
4
- ( runRefactoring
5
- , applyRefactorings
5
+ ( applyRefactorings
6
+ , runRefactoring
7
+ , parseExtensions
6
8
) where
7
9
8
- import Language.Haskell.GHC.ExactPrint.Parsers (parseModuleWithOptions )
10
+ import Data.List
11
+ import GHC.LanguageExtensions.Type (Extension (.. ))
9
12
import Refact.Fixity
10
13
import Refact.Internal
11
14
import Refact.Types
12
15
16
+ #if __GLASGOW_HASKELL__ <= 806
17
+ import DynFlags (FlagSpec (flagSpecFlag , flagSpecName ), xFlags )
18
+ #else
19
+ import Language.Haskell.GhclibParserEx.GHC.Driver.Session (impliedXFlags , readExtension )
20
+ #endif
21
+
13
22
-- | Apply a set of refactorings as supplied by hlint
14
23
applyRefactorings
15
24
:: Maybe (Int , Int )
@@ -25,8 +34,106 @@ applyRefactorings
25
34
-- prior to it which has an overlapping source span and is not filtered out.
26
35
-> FilePath
27
36
-- ^ Target file
37
+ -> ([Extension ], [Extension ])
38
+ -- ^ Enabled and disabled extensions. These are in addition to the @LANGUAGE@ pragmas
39
+ -- in the target file. When they conflict with the @LANGUAGE@ pragmas, pragmas win.
28
40
-> IO String
29
- applyRefactorings optionsPos inp file = do
41
+ applyRefactorings optionsPos inp file exts = do
30
42
(as, m) <- either (onError " apply" ) (uncurry applyFixities)
31
- =<< parseModuleWithOptions rigidLayout file
43
+ =<< parseModuleWithArgs exts file
32
44
apply optionsPos False ((mempty ,) <$> inp) file Silent as m
45
+
46
+ -- | Parse the input into (enabled extensions, disabled extensions, invalid input).
47
+ -- Implied extensions are automatically added. For example, @FunctionalDependencies@
48
+ -- implies @MultiParamTypeClasses@, and @RebindableSyntax@ implies @NoImplicitPrelude@.
49
+ --
50
+ -- The input is processed from left to right. An extension (e.g., @StarIsType@)
51
+ -- may be overridden later (e.g., by @NoStarIsType@).
52
+ --
53
+ -- Extensions that appear earlier in the input will appear later in the output.
54
+ -- Implied extensions appear in the end. If an extension occurs multiple times in the input,
55
+ -- the last one is used.
56
+ --
57
+ -- >>> parseExtensions ["GADTs", "RebindableSyntax", "StarIsType", "GADTs", "InvalidExtension", "NoStarIsType"]
58
+ -- ([GADTs, RebindableSyntax, GADTSyntax, MonoLocalBinds], [StarIsType, ImplicitPrelude], ["InvalidExtension"])
59
+ parseExtensions :: [String ] -> ([Extension ], [Extension ], [String ])
60
+ parseExtensions = addImplied . foldl' f mempty
61
+ where
62
+ f :: ([Extension ], [Extension ], [String ]) -> String -> ([Extension ], [Extension ], [String ])
63
+ f (ys, ns, is) (' N' : ' o' : s) | Just ext <- readExtension s =
64
+ (delete ext ys, ext : delete ext ns, is)
65
+ f (ys, ns, is) s | Just ext <- readExtension s =
66
+ (ext : delete ext ys, delete ext ns, is)
67
+ f (ys, ns, is) s = (ys, ns, s : is)
68
+
69
+ addImplied :: ([Extension ], [Extension ], [String ]) -> ([Extension ], [Extension ], [String ])
70
+ addImplied (ys, ns, is) = (ys ++ impliedOn, ns ++ impliedOff, is)
71
+ where
72
+ impliedOn = [b | ext <- ys, (a, True , b) <- impliedXFlags, a == ext]
73
+ impliedOff = [b | ext <- ys, (a, False , b) <- impliedXFlags, a == ext]
74
+
75
+ #if __GLASGOW_HASKELL__ <= 806
76
+ readExtension :: String -> Maybe Extension
77
+ readExtension s = flagSpecFlag <$> find ((== s) . flagSpecName) xFlags
78
+
79
+ -- | Copied from "Language.Haskell.GhclibParserEx.GHC.Driver.Session", in order to
80
+ -- support GHC 8.6
81
+ impliedXFlags :: [(Extension , Bool , Extension )]
82
+ impliedXFlags
83
+ -- See Note [Updating flag description in the User's Guide]
84
+ = [ (RankNTypes , True , ExplicitForAll )
85
+ , (QuantifiedConstraints , True , ExplicitForAll )
86
+ , (ScopedTypeVariables , True , ExplicitForAll )
87
+ , (LiberalTypeSynonyms , True , ExplicitForAll )
88
+ , (ExistentialQuantification , True , ExplicitForAll )
89
+ , (FlexibleInstances , True , TypeSynonymInstances )
90
+ , (FunctionalDependencies , True , MultiParamTypeClasses )
91
+ , (MultiParamTypeClasses , True , ConstrainedClassMethods ) -- c.f. #7854
92
+ , (TypeFamilyDependencies , True , TypeFamilies )
93
+
94
+ , (RebindableSyntax , False , ImplicitPrelude ) -- NB: turn off!
95
+
96
+ , (DerivingVia , True , DerivingStrategies )
97
+
98
+ , (GADTs , True , GADTSyntax )
99
+ , (GADTs , True , MonoLocalBinds )
100
+ , (TypeFamilies , True , MonoLocalBinds )
101
+
102
+ , (TypeFamilies , True , KindSignatures ) -- Type families use kind signatures
103
+ , (PolyKinds , True , KindSignatures ) -- Ditto polymorphic kinds
104
+
105
+ -- TypeInType is now just a synonym for a couple of other extensions.
106
+ , (TypeInType , True , DataKinds )
107
+ , (TypeInType , True , PolyKinds )
108
+ , (TypeInType , True , KindSignatures )
109
+
110
+ -- AutoDeriveTypeable is not very useful without DeriveDataTypeable
111
+ , (AutoDeriveTypeable , True , DeriveDataTypeable )
112
+
113
+ -- We turn this on so that we can export associated type
114
+ -- type synonyms in subordinates (e.g. MyClass(type AssocType))
115
+ , (TypeFamilies , True , ExplicitNamespaces )
116
+ , (TypeOperators , True , ExplicitNamespaces )
117
+
118
+ , (ImpredicativeTypes , True , RankNTypes )
119
+
120
+ -- Record wild-cards implies field disambiguation
121
+ -- Otherwise if you write (C {..}) you may well get
122
+ -- stuff like " 'a' not in scope ", which is a bit silly
123
+ -- if the compiler has just filled in field 'a' of constructor 'C'
124
+ , (RecordWildCards , True , DisambiguateRecordFields )
125
+
126
+ , (ParallelArrays , True , ParallelListComp )
127
+
128
+ , (JavaScriptFFI , True , InterruptibleFFI )
129
+
130
+ , (DeriveTraversable , True , DeriveFunctor )
131
+ , (DeriveTraversable , True , DeriveFoldable )
132
+
133
+ -- Duplicate record fields require field disambiguation
134
+ , (DuplicateRecordFields , True , DisambiguateRecordFields )
135
+
136
+ , (TemplateHaskell , True , TemplateHaskellQuotes )
137
+ , (Strict , True , StrictData )
138
+ ]
139
+ #endif
0 commit comments