Get rid of some stuttering in comments and docs
[ghc.git] / compiler / rename / RnUnbound.hs
1 {-
2
3 This module contains helper functions for reporting and creating
4 unbound variables.
5
6 -}
7 module RnUnbound ( mkUnboundName
8 , mkUnboundNameRdr
9 , isUnboundName
10 , reportUnboundName
11 , unknownNameSuggestions
12 , WhereLooking(..)
13 , unboundName
14 , unboundNameX
15 , perhapsForallMsg ) where
16
17 import GhcPrelude
18
19 import RdrName
20 import HscTypes
21 import TcRnMonad
22 import Name
23 import Module
24 import SrcLoc
25 import Outputable
26 import PrelNames ( mkUnboundName, forall_tv_RDR, isUnboundName )
27 import Util
28 import Maybes
29 import DynFlags
30 import FastString
31 import Data.List
32 import Data.Function ( on )
33
34 {-
35 ************************************************************************
36 * *
37 What to do when a lookup fails
38 * *
39 ************************************************************************
40 -}
41
42 data WhereLooking = WL_Any -- Any binding
43 | WL_Global -- Any top-level binding (local or imported)
44 | WL_LocalTop -- Any top-level binding in this module
45 | WL_LocalOnly
46 -- Only local bindings
47 -- (pattern synonyms declaractions,
48 -- see Note [Renaming pattern synonym variables])
49
50 mkUnboundNameRdr :: RdrName -> Name
51 mkUnboundNameRdr rdr = mkUnboundName (rdrNameOcc rdr)
52
53 reportUnboundName :: RdrName -> RnM Name
54 reportUnboundName rdr = unboundName WL_Any rdr
55
56 unboundName :: WhereLooking -> RdrName -> RnM Name
57 unboundName wl rdr = unboundNameX wl rdr Outputable.empty
58
59 unboundNameX :: WhereLooking -> RdrName -> SDoc -> RnM Name
60 unboundNameX where_look rdr_name extra
61 = do { dflags <- getDynFlags
62 ; let show_helpful_errors = gopt Opt_HelpfulErrors dflags
63 what = pprNonVarNameSpace (occNameSpace (rdrNameOcc rdr_name))
64 err = unknownNameErr what rdr_name $$ extra
65 ; if not show_helpful_errors
66 then addErr err
67 else do { local_env <- getLocalRdrEnv
68 ; global_env <- getGlobalRdrEnv
69 ; impInfo <- getImports
70 ; let suggestions = unknownNameSuggestions_ where_look
71 dflags global_env local_env impInfo rdr_name
72 ; addErr (err $$ suggestions) }
73 ; return (mkUnboundNameRdr rdr_name) }
74
75 unknownNameErr :: SDoc -> RdrName -> SDoc
76 unknownNameErr what rdr_name
77 = vcat [ hang (text "Not in scope:")
78 2 (what <+> quotes (ppr rdr_name))
79 , extra ]
80 where
81 extra | rdr_name == forall_tv_RDR = perhapsForallMsg
82 | otherwise = Outputable.empty
83
84 type HowInScope = Either SrcSpan ImpDeclSpec
85 -- Left loc => locally bound at loc
86 -- Right ispec => imported as specified by ispec
87
88
89 -- | Called from the typechecker (TcErrors) when we find an unbound variable
90 unknownNameSuggestions :: DynFlags
91 -> GlobalRdrEnv -> LocalRdrEnv -> ImportAvails
92 -> RdrName -> SDoc
93 unknownNameSuggestions = unknownNameSuggestions_ WL_Any
94
95 unknownNameSuggestions_ :: WhereLooking -> DynFlags
96 -> GlobalRdrEnv -> LocalRdrEnv -> ImportAvails
97 -> RdrName -> SDoc
98 unknownNameSuggestions_ where_look dflags global_env local_env imports tried_rdr_name =
99 similarNameSuggestions where_look dflags global_env local_env tried_rdr_name $$
100 importSuggestions where_look imports tried_rdr_name $$
101 extensionSuggestions tried_rdr_name
102
103
104 similarNameSuggestions :: WhereLooking -> DynFlags
105 -> GlobalRdrEnv -> LocalRdrEnv
106 -> RdrName -> SDoc
107 similarNameSuggestions where_look dflags global_env
108 local_env tried_rdr_name
109 = case suggest of
110 [] -> Outputable.empty
111 [p] -> perhaps <+> pp_item p
112 ps -> sep [ perhaps <+> text "one of these:"
113 , nest 2 (pprWithCommas pp_item ps) ]
114 where
115 all_possibilities :: [(String, (RdrName, HowInScope))]
116 all_possibilities
117 = [ (showPpr dflags r, (r, Left loc))
118 | (r,loc) <- local_possibilities local_env ]
119 ++ [ (showPpr dflags r, rp) | (r, rp) <- global_possibilities global_env ]
120
121 suggest = fuzzyLookup (showPpr dflags tried_rdr_name) all_possibilities
122 perhaps = text "Perhaps you meant"
123
124 pp_item :: (RdrName, HowInScope) -> SDoc
125 pp_item (rdr, Left loc) = pp_ns rdr <+> quotes (ppr rdr) <+> loc' -- Locally defined
126 where loc' = case loc of
127 UnhelpfulSpan l -> parens (ppr l)
128 RealSrcSpan l -> parens (text "line" <+> int (srcSpanStartLine l))
129 pp_item (rdr, Right is) = pp_ns rdr <+> quotes (ppr rdr) <+> -- Imported
130 parens (text "imported from" <+> ppr (is_mod is))
131
132 pp_ns :: RdrName -> SDoc
133 pp_ns rdr | ns /= tried_ns = pprNameSpace ns
134 | otherwise = Outputable.empty
135 where ns = rdrNameSpace rdr
136
137 tried_occ = rdrNameOcc tried_rdr_name
138 tried_is_sym = isSymOcc tried_occ
139 tried_ns = occNameSpace tried_occ
140 tried_is_qual = isQual tried_rdr_name
141
142 correct_name_space occ = nameSpacesRelated (occNameSpace occ) tried_ns
143 && isSymOcc occ == tried_is_sym
144 -- Treat operator and non-operators as non-matching
145 -- This heuristic avoids things like
146 -- Not in scope 'f'; perhaps you meant '+' (from Prelude)
147
148 local_ok = case where_look of { WL_Any -> True
149 ; WL_LocalOnly -> True
150 ; _ -> False }
151 local_possibilities :: LocalRdrEnv -> [(RdrName, SrcSpan)]
152 local_possibilities env
153 | tried_is_qual = []
154 | not local_ok = []
155 | otherwise = [ (mkRdrUnqual occ, nameSrcSpan name)
156 | name <- localRdrEnvElts env
157 , let occ = nameOccName name
158 , correct_name_space occ]
159
160 gre_ok :: GlobalRdrElt -> Bool
161 gre_ok = case where_look of
162 WL_LocalTop -> isLocalGRE
163 WL_LocalOnly -> const False
164 _ -> const True
165
166 global_possibilities :: GlobalRdrEnv -> [(RdrName, (RdrName, HowInScope))]
167 global_possibilities global_env
168 | tried_is_qual = [ (rdr_qual, (rdr_qual, how))
169 | gre <- globalRdrEnvElts global_env
170 , gre_ok gre
171 , let name = gre_name gre
172 occ = nameOccName name
173 , correct_name_space occ
174 , (mod, how) <- quals_in_scope gre
175 , let rdr_qual = mkRdrQual mod occ ]
176
177 | otherwise = [ (rdr_unqual, pair)
178 | gre <- globalRdrEnvElts global_env
179 , gre_ok gre
180 , let name = gre_name gre
181 occ = nameOccName name
182 rdr_unqual = mkRdrUnqual occ
183 , correct_name_space occ
184 , pair <- case (unquals_in_scope gre, quals_only gre) of
185 (how:_, _) -> [ (rdr_unqual, how) ]
186 ([], pr:_) -> [ pr ] -- See Note [Only-quals]
187 ([], []) -> [] ]
188
189 -- Note [Only-quals]
190 -- The second alternative returns those names with the same
191 -- OccName as the one we tried, but live in *qualified* imports
192 -- e.g. if you have:
193 --
194 -- > import qualified Data.Map as Map
195 -- > foo :: Map
196 --
197 -- then we suggest @Map.Map@.
198
199 --------------------
200 unquals_in_scope :: GlobalRdrElt -> [HowInScope]
201 unquals_in_scope (GRE { gre_name = n, gre_lcl = lcl, gre_imp = is })
202 | lcl = [ Left (nameSrcSpan n) ]
203 | otherwise = [ Right ispec
204 | i <- is, let ispec = is_decl i
205 , not (is_qual ispec) ]
206
207 --------------------
208 quals_in_scope :: GlobalRdrElt -> [(ModuleName, HowInScope)]
209 -- Ones for which the qualified version is in scope
210 quals_in_scope (GRE { gre_name = n, gre_lcl = lcl, gre_imp = is })
211 | lcl = case nameModule_maybe n of
212 Nothing -> []
213 Just m -> [(moduleName m, Left (nameSrcSpan n))]
214 | otherwise = [ (is_as ispec, Right ispec)
215 | i <- is, let ispec = is_decl i ]
216
217 --------------------
218 quals_only :: GlobalRdrElt -> [(RdrName, HowInScope)]
219 -- Ones for which *only* the qualified version is in scope
220 quals_only (GRE { gre_name = n, gre_imp = is })
221 = [ (mkRdrQual (is_as ispec) (nameOccName n), Right ispec)
222 | i <- is, let ispec = is_decl i, is_qual ispec ]
223
224 -- | Generate helpful suggestions if a qualified name Mod.foo is not in scope.
225 importSuggestions :: WhereLooking -> ImportAvails -> RdrName -> SDoc
226 importSuggestions where_look imports rdr_name
227 | WL_LocalOnly <- where_look = Outputable.empty
228 | not (isQual rdr_name || isUnqual rdr_name) = Outputable.empty
229 | null interesting_imports
230 , Just name <- mod_name
231 = hsep
232 [ text "No module named"
233 , quotes (ppr name)
234 , text "is imported."
235 ]
236 | is_qualified
237 , null helpful_imports
238 , [(mod,_)] <- interesting_imports
239 = hsep
240 [ text "Module"
241 , quotes (ppr mod)
242 , text "does not export"
243 , quotes (ppr occ_name) <> dot
244 ]
245 | is_qualified
246 , null helpful_imports
247 , mods <- map fst interesting_imports
248 = hsep
249 [ text "Neither"
250 , quotedListWithNor (map ppr mods)
251 , text "exports"
252 , quotes (ppr occ_name) <> dot
253 ]
254 | [(mod,imv)] <- helpful_imports_non_hiding
255 = fsep
256 [ text "Perhaps you want to add"
257 , quotes (ppr occ_name)
258 , text "to the import list"
259 , text "in the import of"
260 , quotes (ppr mod)
261 , parens (ppr (imv_span imv)) <> dot
262 ]
263 | not (null helpful_imports_non_hiding)
264 = fsep
265 [ text "Perhaps you want to add"
266 , quotes (ppr occ_name)
267 , text "to one of these import lists:"
268 ]
269 $$
270 nest 2 (vcat
271 [ quotes (ppr mod) <+> parens (ppr (imv_span imv))
272 | (mod,imv) <- helpful_imports_non_hiding
273 ])
274 | [(mod,imv)] <- helpful_imports_hiding
275 = fsep
276 [ text "Perhaps you want to remove"
277 , quotes (ppr occ_name)
278 , text "from the explicit hiding list"
279 , text "in the import of"
280 , quotes (ppr mod)
281 , parens (ppr (imv_span imv)) <> dot
282 ]
283 | not (null helpful_imports_hiding)
284 = fsep
285 [ text "Perhaps you want to remove"
286 , quotes (ppr occ_name)
287 , text "from the hiding clauses"
288 , text "in one of these imports:"
289 ]
290 $$
291 nest 2 (vcat
292 [ quotes (ppr mod) <+> parens (ppr (imv_span imv))
293 | (mod,imv) <- helpful_imports_hiding
294 ])
295 | otherwise
296 = Outputable.empty
297 where
298 is_qualified = isQual rdr_name
299 (mod_name, occ_name) = case rdr_name of
300 Unqual occ_name -> (Nothing, occ_name)
301 Qual mod_name occ_name -> (Just mod_name, occ_name)
302 _ -> error "importSuggestions: dead code"
303
304
305 -- What import statements provide "Mod" at all
306 -- or, if this is an unqualified name, are not qualified imports
307 interesting_imports = [ (mod, imp)
308 | (mod, mod_imports) <- moduleEnvToList (imp_mods imports)
309 , Just imp <- return $ pick (importedByUser mod_imports)
310 ]
311
312 -- We want to keep only one for each original module; preferably one with an
313 -- explicit import list (for no particularly good reason)
314 pick :: [ImportedModsVal] -> Maybe ImportedModsVal
315 pick = listToMaybe . sortBy (compare `on` prefer) . filter select
316 where select imv = case mod_name of Just name -> imv_name imv == name
317 Nothing -> not (imv_qualified imv)
318 prefer imv = (imv_is_hiding imv, imv_span imv)
319
320 -- Which of these would export a 'foo'
321 -- (all of these are restricted imports, because if they were not, we
322 -- wouldn't have an out-of-scope error in the first place)
323 helpful_imports = filter helpful interesting_imports
324 where helpful (_,imv)
325 = not . null $ lookupGlobalRdrEnv (imv_all_exports imv) occ_name
326
327 -- Which of these do that because of an explicit hiding list resp. an
328 -- explicit import list
329 (helpful_imports_hiding, helpful_imports_non_hiding)
330 = partition (imv_is_hiding . snd) helpful_imports
331
332 extensionSuggestions :: RdrName -> SDoc
333 extensionSuggestions rdrName
334 | rdrName == mkUnqual varName (fsLit "mdo") ||
335 rdrName == mkUnqual varName (fsLit "rec")
336 = text "Perhaps you meant to use RecursiveDo"
337 | otherwise = Outputable.empty
338
339 perhapsForallMsg :: SDoc
340 perhapsForallMsg
341 = vcat [ text "Perhaps you intended to use ExplicitForAll or similar flag"
342 , text "to enable explicit-forall syntax: forall <tvs>. <type>"]