on master help sign in
Give name hints in certain docs errors
86acf58Evan Czaplicki
elm-compiler.cabal+1
@@ -93,6 +93,7 @@ Library
93 Reporting.Error,
93 Reporting.Error,
94 Reporting.Error.Canonicalize,
94 Reporting.Error.Canonicalize,
95 Reporting.Error.Docs,
95 Reporting.Error.Docs,
96+ Reporting.Error.Helpers,
96 Reporting.Error.Syntax,
97 Reporting.Error.Syntax,
97 Reporting.Error.Type,
98 Reporting.Error.Type,
98 Reporting.PrettyPrint,
99 Reporting.PrettyPrint,
src/Canonicalize.hs+2−1
@@ -23,6 +23,7 @@ import qualified Docs.Centralize as Docs
23import qualified Reporting.Annotation as A
23import qualified Reporting.Annotation as A
24import qualified Reporting.Error as Error
24import qualified Reporting.Error as Error
25import qualified Reporting.Error.Canonicalize as CError
25import qualified Reporting.Error.Canonicalize as CError
26+import qualified Reporting.Error.Helpers as ErrorHelp
26import qualified Reporting.Result as R
27import qualified Reporting.Result as R
27import qualified Reporting.Warning as Warning
28import qualified Reporting.Warning as Warning
28import qualified Canonicalize.Declaration as Decls
29import qualified Canonicalize.Declaration as Decls
@@ -197,7 +198,7 @@ resolveExports fullList (Var.Listing partialList open) =
197
198
198 notFound region possibilities name =
199 notFound region possibilities name =
199 A.A region $ CError.Export name $
200 A.A region $ CError.Export name $
200− CError.nearbyNames id name possibilities
201+ ErrorHelp.nearbyNames id name possibilities
201
202
202
203
203-- GROUPING VALUES
204-- GROUPING VALUES
src/Canonicalize/Setup.hs+1
@@ -17,6 +17,7 @@ import qualified AST.Variable as Var
17import Elm.Utils ((|>))
17import Elm.Utils ((|>))
18import qualified Reporting.Annotation as A
18import qualified Reporting.Annotation as A
19import qualified Reporting.Error.Canonicalize as Error
19import qualified Reporting.Error.Canonicalize as Error
20+import qualified Reporting.Error.Helpers as Error
20import qualified Reporting.Region as R
21import qualified Reporting.Region as R
21import qualified Canonicalize.Environment as Env
22import qualified Canonicalize.Environment as Env
22import qualified Canonicalize.Result as Result
23import qualified Canonicalize.Result as Result
src/Canonicalize/Variable.hs+1
@@ -11,6 +11,7 @@ import qualified AST.Type as Type
11import qualified AST.Variable as Var
11import qualified AST.Variable as Var
12import qualified Reporting.Annotation as A
12import qualified Reporting.Annotation as A
13import qualified Reporting.Error.Canonicalize as Error
13import qualified Reporting.Error.Canonicalize as Error
14+import qualified Reporting.Error.Helpers as Error
14import qualified Reporting.Region as R
15import qualified Reporting.Region as R
15import qualified Canonicalize.Environment as Env
16import qualified Canonicalize.Environment as Env
16import qualified Canonicalize.Result as Result
17import qualified Canonicalize.Result as Result
src/Docs/Check.hs+14−7
@@ -18,6 +18,7 @@ import Parse.Helpers
18 )
18 )
19import qualified Reporting.Annotation as A
19import qualified Reporting.Annotation as A
20import qualified Reporting.Error.Docs as Error
20import qualified Reporting.Error.Docs as Error
21+import qualified Reporting.Error.Helpers as Error (nearbyNames)
21import qualified Reporting.Region as R
22import qualified Reporting.Region as R
22import qualified Reporting.Result as R
23import qualified Reporting.Result as R
23
24
@@ -115,18 +116,24 @@ checkModuleComment :: R.Region -> [Var.Value] -> [A.Located String] -> Result w
115checkModuleComment docRegion exports locatedDocNames =
116checkModuleComment docRegion exports locatedDocNames =
116 let
117 let
117 exportNames =
118 exportNames =
118− Map.fromList (map (\v -> (valueName v, ())) exports)
119+ map valueName exports
119
120
120− docNames =
121+ exportDict =
122+ Map.fromList (map (\name -> (name, ())) exportNames)
123+
124+ docDict =
121 Map.fromList (map (\(A.A region name) -> (name, region)) locatedDocNames)
125 Map.fromList (map (\(A.A region name) -> (name, region)) locatedDocNames)
122
126
127+ extraNameError (name, region) =
128+ R.throw region (Error.OnlyInDocs name (Error.nearbyNames id name exportNames))
129+
123 docErrors =
130 docErrors =
124− Map.difference docNames exportNames
131+ Map.difference docDict exportDict
125 |> Map.toList
132 |> Map.toList
126− |> T.traverse (\(name, region) -> R.throw region (Error.OnlyInDocs name))
133+ |> T.traverse extraNameError
127
134
128 namesOnlyInExports =
135 namesOnlyInExports =
129− Map.difference exportNames docNames
136+ Map.difference exportDict docDict
130 |> Map.toList
137 |> Map.toList
131 |> map fst
138 |> map fst
132
139
@@ -137,8 +144,8 @@ checkModuleComment docRegion exports locatedDocNames =
137 R.throw docRegion (Error.OnlyInExports namesOnlyInExports)
144 R.throw docRegion (Error.OnlyInExports namesOnlyInExports)
138 in
145 in
139 (\_ _ -> ())
146 (\_ _ -> ())
140− <$> docErrors
147+ <$> exportErrors
141− <*> exportErrors
148+ <*> docErrors
142
149
143
150
144commentedNames :: R.Region -> String -> [A.Located String]
151commentedNames :: R.Region -> String -> [A.Located String]
src/Reporting/Error/Canonicalize.hs+8−41
@@ -1,15 +1,12 @@
1{-# OPTIONS_GHC -Wall #-}
1{-# OPTIONS_GHC -Wall #-}
2module Reporting.Error.Canonicalize where
2module Reporting.Error.Canonicalize where
3
3
4−import Data.Function (on)
5−import qualified Data.List as List
6−import qualified Text.EditDistance as Dist
7import qualified Text.PrettyPrint as P
4import qualified Text.PrettyPrint as P
8
5
9import qualified AST.Module as Module
6import qualified AST.Module as Module
10import qualified AST.Type as Type
7import qualified AST.Type as Type
11import qualified AST.Variable as Var
8import qualified AST.Variable as Var
12−import Elm.Utils ((|>))
9+import qualified Reporting.Error.Helpers as Help
13import qualified Reporting.PrettyPrint as P
10import qualified Reporting.PrettyPrint as P
14import qualified Reporting.Region as Region
11import qualified Reporting.Region as Region
15import qualified Reporting.Report as Report
12import qualified Reporting.Report as Report
@@ -109,25 +106,6 @@ port name isInbound rootType localType maybeMessage =
109 Port (PortError name isInbound rootType localType maybeMessage)
106 Port (PortError name isInbound rootType localType maybeMessage)
110
107
111
108
112−-- NEARBY NAMES
113−
114−nearbyNames :: (a -> String) -> a -> [a] -> [a]
115−nearbyNames format name names =
116− let editDistance =
117− if length (format name) < 3 then 1 else 2
118− in
119− names
120− |> map (\x -> (distance (format name) (format x), x))
121− |> List.sortBy (compare `on` fst)
122− |> filter ( (<= editDistance) . abs . fst )
123− |> map snd
124−
125−
126−distance :: String -> String -> Int
127−distance x y =
128− Dist.restrictedDamerauLevenshteinDistance Dist.defaultEditCosts x y
129−
130−
131-- TO REPORT
109-- TO REPORT
132
110
133namingError :: String -> String -> Report.Report
111namingError :: String -> String -> Report.Report
@@ -145,26 +123,26 @@ toReport dealiaser err =
145 Ambiguous ->
123 Ambiguous ->
146 namingError
124 namingError
147 ("This usage of " ++ var ++ " is ambiguous.")
125 ("This usage of " ++ var ++ " is ambiguous.")
148− (maybeYouWant suggestions)
126+ (Help.maybeYouWant suggestions)
149
127
150 UnknownQualifier qualifier localName ->
128 UnknownQualifier qualifier localName ->
151 namingError
129 namingError
152 ("Cannot find " ++ var ++ ".")
130 ("Cannot find " ++ var ++ ".")
153 ( "The qualifier `" ++ qualifier ++ "` is not in scope. "
131 ( "The qualifier `" ++ qualifier ++ "` is not in scope. "
154− ++ maybeYouWant (map (\modul -> modul ++ "." ++ localName) suggestions)
132+ ++ Help.maybeYouWant (map (\modul -> modul ++ "." ++ localName) suggestions)
155 )
133 )
156
134
157 QualifiedUnknown qualifier localName ->
135 QualifiedUnknown qualifier localName ->
158 namingError
136 namingError
159 ("Cannot find " ++ var ++ ".")
137 ("Cannot find " ++ var ++ ".")
160 ( "`" ++ qualifier ++ "` does not expose `" ++ localName ++ "`. "
138 ( "`" ++ qualifier ++ "` does not expose `" ++ localName ++ "`. "
161− ++ maybeYouWant (map (\v -> qualifier ++ "." ++ v) suggestions)
139+ ++ Help.maybeYouWant (map (\v -> qualifier ++ "." ++ v) suggestions)
162 )
140 )
163
141
164 ExposedUnknown ->
142 ExposedUnknown ->
165 namingError
143 namingError
166 ("Cannot find " ++ var)
144 ("Cannot find " ++ var)
167− (maybeYouWant suggestions)
145+ (Help.maybeYouWant suggestions)
168
146
169 Pattern patternError ->
147 Pattern patternError ->
170 case patternError of
148 case patternError of
@@ -205,17 +183,17 @@ toReport dealiaser err =
205 ModuleNotFound suggestions ->
183 ModuleNotFound suggestions ->
206 namingError
184 namingError
207 ("Could not find a module named `" ++ moduleName ++ "`")
185 ("Could not find a module named `" ++ moduleName ++ "`")
208− (maybeYouWant (map Module.nameToString suggestions))
186+ (Help.maybeYouWant (map Module.nameToString suggestions))
209
187
210 ValueNotFound value suggestions ->
188 ValueNotFound value suggestions ->
211 namingError
189 namingError
212 ("Module `" ++ moduleName ++ "` does not expose `" ++ value ++ "`")
190 ("Module `" ++ moduleName ++ "` does not expose `" ++ value ++ "`")
213− (maybeYouWant suggestions)
191+ (Help.maybeYouWant suggestions)
214
192
215 Export name suggestions ->
193 Export name suggestions ->
216 namingError
194 namingError
217 ("Could not export `" ++ name ++ "` which is not defined in this module.")
195 ("Could not export `" ++ name ++ "` which is not defined in this module.")
218− (maybeYouWant suggestions)
196+ (Help.maybeYouWant suggestions)
219
197
220 Port (PortError name isInbound _rootType localType maybeMessage) ->
198 Port (PortError name isInbound _rootType localType maybeMessage) ->
221 let
199 let
@@ -250,17 +228,6 @@ argMismatchReport kind var expected actual =
250 Report.simple "ARGUMENT" preHint postHint
228 Report.simple "ARGUMENT" preHint postHint
251
229
252
230
253−maybeYouWant :: [String] -> String
254−maybeYouWant suggestions =
255− case suggestions of
256− [] ->
257− ""
258−
259− _:_ ->
260− "Maybe you want one of the following?\n"
261− ++ concatMap ("\n "++) (take 4 suggestions)
262−
263−
264extractSuggestions :: Error -> Maybe [String]
231extractSuggestions :: Error -> Maybe [String]
265extractSuggestions err =
232extractSuggestions err =
266 case err of
233 case err of
src/Reporting/Error/Docs.hs+4−3
@@ -1,12 +1,13 @@
1{-# OPTIONS_GHC -Wall #-}
1{-# OPTIONS_GHC -Wall #-}
2module Reporting.Error.Docs where
2module Reporting.Error.Docs where
3
3
4+import qualified Reporting.Error.Helpers as Help
4import qualified Reporting.Report as Report
5import qualified Reporting.Report as Report
5
6
6
7
7data Error
8data Error
8 = NoDocs
9 = NoDocs
9− | OnlyInDocs String
10+ | OnlyInDocs String [String]
10 | OnlyInExports [String]
11 | OnlyInExports [String]
11 | NoComment String
12 | NoComment String
12 | NoType String
13 | NoType String
@@ -24,10 +25,10 @@ toReport err =
24 )
25 )
25 "Learn how at <http://package.elm-lang.org/help/documentation-format>"
26 "Learn how at <http://package.elm-lang.org/help/documentation-format>"
26
27
27− OnlyInDocs name ->
28+ OnlyInDocs name suggestions ->
28 Report.simple "DOCUMENTATION ERROR"
29 Report.simple "DOCUMENTATION ERROR"
29 ("Your module documentation includes `" ++ name ++ "` which is not exported.")
30 ("Your module documentation includes `" ++ name ++ "` which is not exported.")
30− "Is it misspelled? Should it be exported?"
31+ ("Is it misspelled? Should it be exported? " ++ Help.maybeYouWant suggestions)
31
32
32 OnlyInExports names ->
33 OnlyInExports names ->
33 Report.simple
34 Report.simple
src/Reporting/Error/Helpers.hsnew file+39
@@ -0,0 +1,39 @@
1+{-# OPTIONS_GHC -Wall #-}
2+module Reporting.Error.Helpers where
3+
4+import Data.Function (on)
5+import qualified Data.List as List
6+import qualified Text.EditDistance as Dist
7+
8+import Elm.Utils ((|>))
9+
10+
11+-- NEARBY NAMES
12+
13+nearbyNames :: (a -> String) -> a -> [a] -> [a]
14+nearbyNames format name names =
15+ let editDistance =
16+ if length (format name) < 3 then 1 else 2
17+ in
18+ names
19+ |> map (\x -> (distance (format name) (format x), x))
20+ |> List.sortBy (compare `on` fst)
21+ |> filter ( (<= editDistance) . abs . fst )
22+ |> map snd
23+
24+
25+distance :: String -> String -> Int
26+distance x y =
27+ Dist.restrictedDamerauLevenshteinDistance Dist.defaultEditCosts x y
28+
29+
30+maybeYouWant :: [String] -> String
31+maybeYouWant suggestions =
32+ case suggestions of
33+ [] ->
34+ ""
35+
36+ _:_ ->
37+ "Maybe you want one of the following?\n"
38+ ++ concatMap ("\n "++) (take 4 suggestions)
39+