summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorroland <rsx@bluewin.ch>2018-11-04 16:45:29 +0100
committerKrzysztof Gogolewski <krz.gogolewski@gmail.com>2018-11-04 16:45:29 +0100
commit1a3b9bd0b674ad16a41b942c738b8f34564bcd8d (patch)
tree6796e7d78d7c56c1c357dc431a66f35242ffa9f0
parent2c959a1894311e59cd2fd469c1967491c1e488f3 (diff)
downloadhaskell-1a3b9bd0b674ad16a41b942c738b8f34564bcd8d.tar.gz
Fix for Trac #15611: Scope errors lie about what modules are imported.
Summary: For the error message: Not in scope X.Y Module X does not export Y No module named ‘X’ is imported: there are 2 cases, where we don't show the last "no module named is imported" line: 1. If the module X has been imported. 2. If the module X is the current module. There are 2 subcases: 2.1 If the unknown module name is in a input source file, then we can use the getModule function to get the current module name. 2.2 If the unknown module name has been entered by the user in GHCi, then the getModule function returns something like "interactive:Ghci1", and we have to check the current module in the last added entry of the HomePackageTable. Test Plan: make test TESTS="T15611a T15611b" Reviewers: monoidal, hvr, thomie, dfeuer, bgamari, DavidEichmann Reviewed By: monoidal, DavidEichmann Subscribers: rwbarton, carter GHC Trac Issues: #15611 Differential Revision: https://phabricator.haskell.org/D5284
-rw-r--r--compiler/rename/RnUnbound.hs53
-rw-r--r--compiler/typecheck/TcErrors.hs4
-rw-r--r--testsuite/tests/module/mod62.stderr1
-rw-r--r--testsuite/tests/rename/should_fail/T15611a.hs2
-rw-r--r--testsuite/tests/rename/should_fail/T15611a.stderr1
-rw-r--r--testsuite/tests/rename/should_fail/T15611b.hs1
-rw-r--r--testsuite/tests/rename/should_fail/T15611b.script2
-rw-r--r--testsuite/tests/rename/should_fail/T15611b.stderr1
-rw-r--r--testsuite/tests/rename/should_fail/T5892b.stderr4
-rw-r--r--testsuite/tests/rename/should_fail/all.T2
-rw-r--r--testsuite/tests/rename/should_fail/rnfail034.stderr1
11 files changed, 60 insertions, 12 deletions
diff --git a/compiler/rename/RnUnbound.hs b/compiler/rename/RnUnbound.hs
index ce5d0dc315..97d3fd7279 100644
--- a/compiler/rename/RnUnbound.hs
+++ b/compiler/rename/RnUnbound.hs
@@ -24,13 +24,14 @@ import Name
import Module
import SrcLoc
import Outputable
-import PrelNames ( mkUnboundName, forall_tv_RDR, isUnboundName )
+import PrelNames ( mkUnboundName, forall_tv_RDR, isUnboundName, getUnique)
import Util
import Maybes
import DynFlags
import FastString
import Data.List
import Data.Function ( on )
+import UniqDFM (udfmToList)
{-
************************************************************************
@@ -67,8 +68,11 @@ unboundNameX where_look rdr_name extra
else do { local_env <- getLocalRdrEnv
; global_env <- getGlobalRdrEnv
; impInfo <- getImports
+ ; currmod <- getModule
+ ; hpt <- getHpt
; let suggestions = unknownNameSuggestions_ where_look
- dflags global_env local_env impInfo rdr_name
+ dflags hpt currmod global_env local_env impInfo
+ rdr_name
; addErr (err $$ suggestions) }
; return (mkUnboundNameRdr rdr_name) }
@@ -89,16 +93,19 @@ type HowInScope = Either SrcSpan ImpDeclSpec
-- | Called from the typechecker (TcErrors) when we find an unbound variable
unknownNameSuggestions :: DynFlags
+ -> HomePackageTable -> Module
-> GlobalRdrEnv -> LocalRdrEnv -> ImportAvails
-> RdrName -> SDoc
unknownNameSuggestions = unknownNameSuggestions_ WL_Any
unknownNameSuggestions_ :: WhereLooking -> DynFlags
+ -> HomePackageTable -> Module
-> GlobalRdrEnv -> LocalRdrEnv -> ImportAvails
-> RdrName -> SDoc
-unknownNameSuggestions_ where_look dflags global_env local_env imports tried_rdr_name =
+unknownNameSuggestions_ where_look dflags hpt curr_mod global_env local_env
+ imports tried_rdr_name =
similarNameSuggestions where_look dflags global_env local_env tried_rdr_name $$
- importSuggestions where_look imports tried_rdr_name $$
+ importSuggestions where_look hpt curr_mod imports tried_rdr_name $$
extensionSuggestions tried_rdr_name
@@ -223,12 +230,15 @@ similarNameSuggestions where_look dflags global_env
| i <- is, let ispec = is_decl i, is_qual ispec ]
-- | Generate helpful suggestions if a qualified name Mod.foo is not in scope.
-importSuggestions :: WhereLooking -> ImportAvails -> RdrName -> SDoc
-importSuggestions where_look imports rdr_name
+importSuggestions :: WhereLooking
+ -> HomePackageTable -> Module
+ -> ImportAvails -> RdrName -> SDoc
+importSuggestions where_look hpt currMod imports rdr_name
| WL_LocalOnly <- where_look = Outputable.empty
| not (isQual rdr_name || isUnqual rdr_name) = Outputable.empty
| null interesting_imports
, Just name <- mod_name
+ , showNotImportedLine (fromJust mod_name)
= hsep
[ text "No module named"
, quotes (ppr name)
@@ -245,6 +255,7 @@ importSuggestions where_look imports rdr_name
]
| is_qualified
, null helpful_imports
+ , not (null interesting_imports)
, mods <- map fst interesting_imports
= hsep
[ text "Neither"
@@ -330,6 +341,19 @@ importSuggestions where_look imports rdr_name
(helpful_imports_hiding, helpful_imports_non_hiding)
= partition (imv_is_hiding . snd) helpful_imports
+ -- See note [showNotImportedLine]
+ showNotImportedLine :: ModuleName -> Bool -- #15611
+ showNotImportedLine modnam
+ | modnam `elem`
+ fmap moduleName (moduleEnvKeys (imp_mods imports)) = False -- 1
+ | moduleName currMod == modnam = False -- 2.1
+ | isLastLoadedMod modnam hptUniques = False -- 2.2
+ | otherwise = True
+ where
+ hptUniques = map fst (udfmToList hpt)
+ isLastLoadedMod _ [] = False
+ isLastLoadedMod modnam uniqs = last uniqs == getUnique modnam
+
extensionSuggestions :: RdrName -> SDoc
extensionSuggestions rdrName
| rdrName == mkUnqual varName (fsLit "mdo") ||
@@ -341,3 +365,20 @@ perhapsForallMsg :: SDoc
perhapsForallMsg
= vcat [ text "Perhaps you intended to use ExplicitForAll or similar flag"
, text "to enable explicit-forall syntax: forall <tvs>. <type>"]
+
+{- Note [showNotImportedLine] -- #15611
+For the error message:
+ Not in scope X.Y
+ Module X does not export Y
+ No module named ‘X’ is imported:
+there are 2 cases, where we hide the last "no module is imported" line:
+1. If the module X has been imported.
+2. If the module X is the current module. There are 2 subcases:
+ 2.1 If the unknown module name is in a input source file,
+ then we can use the getModule function to get the current module name.
+ (See test T15611a)
+ 2.2 If the unknown module name has been entered by the user in GHCi,
+ then the getModule function returns something like "interactive:Ghci1",
+ and we have to check the current module in the last added entry of
+ the HomePackageTable. (See test T15611b)
+-}
diff --git a/compiler/typecheck/TcErrors.hs b/compiler/typecheck/TcErrors.hs
index 1fd98f1aa5..c692b7b905 100644
--- a/compiler/typecheck/TcErrors.hs
+++ b/compiler/typecheck/TcErrors.hs
@@ -1091,7 +1091,9 @@ mkHoleError _ _ ct@(CHoleCan { cc_hole = ExprHole (OutOfScope occ rdr_env0) })
-- in-scope variables in the message, and note inaccessible exact matches
= do { dflags <- getDynFlags
; imp_info <- getImports
- ; let suggs_msg = unknownNameSuggestions dflags rdr_env0
+ ; curr_mod <- getModule
+ ; hpt <- getHpt
+ ; let suggs_msg = unknownNameSuggestions dflags hpt curr_mod rdr_env0
(tcl_rdr lcl_env) imp_info rdr
; rdr_env <- getGlobalRdrEnv
; splice_locs <- getTopLevelSpliceLocs
diff --git a/testsuite/tests/module/mod62.stderr b/testsuite/tests/module/mod62.stderr
index 3a6f415946..0a2ceff6d9 100644
--- a/testsuite/tests/module/mod62.stderr
+++ b/testsuite/tests/module/mod62.stderr
@@ -4,4 +4,3 @@ mod62.hs:3:9: error: Qualified name in binding position: M.y
mod62.hs:3:22: error:
Not in scope: ‘M.y’
Perhaps you meant ‘M.x’ (line 3)
- No module named ‘M’ is imported.
diff --git a/testsuite/tests/rename/should_fail/T15611a.hs b/testsuite/tests/rename/should_fail/T15611a.hs
new file mode 100644
index 0000000000..df1bb2f08c
--- /dev/null
+++ b/testsuite/tests/rename/should_fail/T15611a.hs
@@ -0,0 +1,2 @@
+main :: IO ()
+main = Main.foo
diff --git a/testsuite/tests/rename/should_fail/T15611a.stderr b/testsuite/tests/rename/should_fail/T15611a.stderr
new file mode 100644
index 0000000000..ebeb83b5f2
--- /dev/null
+++ b/testsuite/tests/rename/should_fail/T15611a.stderr
@@ -0,0 +1 @@
+T15611a.hs:2:8: Not in scope: ‘Main.foo’
diff --git a/testsuite/tests/rename/should_fail/T15611b.hs b/testsuite/tests/rename/should_fail/T15611b.hs
new file mode 100644
index 0000000000..0ab721d1d1
--- /dev/null
+++ b/testsuite/tests/rename/should_fail/T15611b.hs
@@ -0,0 +1 @@
+module T15611b where
diff --git a/testsuite/tests/rename/should_fail/T15611b.script b/testsuite/tests/rename/should_fail/T15611b.script
new file mode 100644
index 0000000000..d2b1fb1458
--- /dev/null
+++ b/testsuite/tests/rename/should_fail/T15611b.script
@@ -0,0 +1,2 @@
+:l T15611b
+T15611b.foo
diff --git a/testsuite/tests/rename/should_fail/T15611b.stderr b/testsuite/tests/rename/should_fail/T15611b.stderr
new file mode 100644
index 0000000000..609ab4c041
--- /dev/null
+++ b/testsuite/tests/rename/should_fail/T15611b.stderr
@@ -0,0 +1 @@
+<interactive>:2:1: Not in scope: ‘T15611b.foo’
diff --git a/testsuite/tests/rename/should_fail/T5892b.stderr b/testsuite/tests/rename/should_fail/T5892b.stderr
index 0f93c21f68..d55d0cb8e1 100644
--- a/testsuite/tests/rename/should_fail/T5892b.stderr
+++ b/testsuite/tests/rename/should_fail/T5892b.stderr
@@ -1,4 +1,2 @@
-T5892b.hs:11:7: error:
- Not in scope: ‘T5892b.subForest’
- No module named ‘T5892b’ is imported.
+T5892b.hs:11:7: error: Not in scope: ‘T5892b.subForest’
diff --git a/testsuite/tests/rename/should_fail/all.T b/testsuite/tests/rename/should_fail/all.T
index 6debe7b917..9ca330f873 100644
--- a/testsuite/tests/rename/should_fail/all.T
+++ b/testsuite/tests/rename/should_fail/all.T
@@ -138,5 +138,7 @@ test('T15539', normal, compile_fail, [''])
test('T15487', normal, multimod_compile_fail, ['T15487','-v0'])
test('T15659', normal, compile_fail, [''])
test('T15607', normal, compile_fail, [''])
+test('T15611a', normal, compile_fail, [''])
+test('T15611b', normal, ghci_script, ['T15611b.script'])
test('ExplicitForAllRules2', normal, compile_fail, [''])
diff --git a/testsuite/tests/rename/should_fail/rnfail034.stderr b/testsuite/tests/rename/should_fail/rnfail034.stderr
index 63e6eb5037..a5219c138b 100644
--- a/testsuite/tests/rename/should_fail/rnfail034.stderr
+++ b/testsuite/tests/rename/should_fail/rnfail034.stderr
@@ -4,4 +4,3 @@ rnfail034.hs:4:11: error: Qualified name in binding position: M.y
rnfail034.hs:4:26: error:
Not in scope: ‘M.y’
Perhaps you meant ‘M.g’ (line 4)
- No module named ‘M’ is imported.