diff --git a/src/Base/TopEnv.hs b/src/Base/TopEnv.hs index b0d4445b62e3445e955124de118ead9576168530..3a4561e560f8a561cc061aa3d5f31c16167459c0 100644 --- a/src/Base/TopEnv.hs +++ b/src/Base/TopEnv.hs @@ -45,12 +45,12 @@ module Base.TopEnv , qualRebindTopEnv, unbindTopEnv, qualUnbindTopEnv , lookupTopEnv, qualLookupTopEnv, qualElemTopEnv , allImports, moduleImports, localBindings, allLocalBindings, allBindings - , allEntities + , allEntities, allBoundQualIdents ) where import Control.Arrow (second) import qualified Data.Map as Map - (Map, empty, insert, findWithDefault, lookup, toList) + (Map, empty, insert, findWithDefault, lookup, toList, keys) import Curry.Base.Ident import Base.Messages (internalError) @@ -179,3 +179,6 @@ allBindings (TopEnv env) = [(x, y) | (x, ys) <- Map.toList env, (_, y) <- ys] allEntities :: TopEnv a -> [a] allEntities (TopEnv env) = [ y | (_, ys) <- Map.toList env, (_, y) <- ys] + +allBoundQualIdents :: TopEnv a -> [QualIdent] +allBoundQualIdents (TopEnv env) = Map.keys env diff --git a/src/Checks/WarnCheck.hs b/src/Checks/WarnCheck.hs index f228109c3aff20085055588a35886f4ccd756efe..350ece7b61fc1b7b7d3def62a0db7ebf111a74f3 100644 --- a/src/Checks/WarnCheck.hs +++ b/src/Checks/WarnCheck.hs @@ -30,7 +30,7 @@ import qualified Data.IntSet as IntSet (IntSet, empty, insert, notMember, singleton, union, unions) import qualified Data.Map as Map (empty, insert, lookup, (!)) import Data.Maybe - (catMaybes, fromMaybe, listToMaybe) + (catMaybes, fromMaybe, listToMaybe, isJust) import Data.List ((\\), intersect, intersectBy, nub, sort, unionBy) import Data.Char @@ -50,6 +50,7 @@ import Base.Messages (Message, spanInfoMessage, internalError) import Base.NestEnv ( NestEnv, emptyEnv, localNestEnv, nestEnv, unnestEnv , qualBindNestEnv, qualInLocalNestEnv, qualLookupNestEnv , qualModifyNestEnv) +import Base.TopEnv (allBoundQualIdents) import Base.Types import Base.Utils (findMultiples) @@ -114,9 +115,12 @@ getModuleIdent = gets moduleId modifyScope :: (ScopeEnv -> ScopeEnv) -> WCM () modifyScope f = modify $ \s -> s { scope = f $ scope s } +warnsFor :: WarnFlag -> WCM Bool +warnsFor f = gets $ \s -> f `elem` warnFlags s + warnFor :: WarnFlag -> WCM () -> WCM () warnFor f act = do - warn <- gets $ \s -> f `elem` warnFlags s + warn <- warnsFor f when warn act report :: Message -> WCM () @@ -976,8 +980,11 @@ warnNondetOverlapping spi loc = spanInfoMessage spi $ -- ----------------------------------------------------------------------------- checkShadowing :: Ident -> WCM () -checkShadowing x = warnFor WarnNameShadowing $ - shadowsVar x >>= maybe ok (report . warnShadowing x) +checkShadowing x = do + warnFor WarnNameShadowing $ + shadowsVar x >>= maybe ok (report . warnShadowing x) + warnFor WarnImportNameShadowing $ + shadowsImport x >>= maybe ok (report . warnShadowing x) reportUnusedVars :: WCM () reportUnusedVars = reportAllUnusedVars WarnUnusedBindings @@ -1137,9 +1144,22 @@ shadows qid s = do getVariable info where sc = scope s +importShadows :: QualIdent -> WcState -> Maybe Ident +importShadows qid s = do + guard $ not (qualInLocalNestEnv qid sc) + let qids = allBoundQualIdents $ valueEnv s + listToMaybe $ map unqualify $ filter isMatchingImport qids + where sc = scope s + isMatchingImport qid' = unqualify qid' == unqualify qid + && isJust (qidModule qid') + && qidModule qid' /= Just (moduleId s) + shadowsVar :: Ident -> WCM (Maybe Ident) shadowsVar v = gets (shadows $ commonId v) +shadowsImport :: Ident -> WCM (Maybe Ident) +shadowsImport v = gets (importShadows $ commonId v) + visitId :: Ident -> WCM () visitId v = modifyScope (qualModifyNestEnv visitVariable (commonId v)) diff --git a/src/CompilerOpts.hs b/src/CompilerOpts.hs index 244a712b9b5b0fc8ce701c9d0005624ead17c106..3441bc34fb13986784ccc6bb04c942895f96389b 100644 --- a/src/CompilerOpts.hs +++ b/src/CompilerOpts.hs @@ -214,6 +214,7 @@ data WarnFlag | WarnUnusedGlobalBindings -- ^ Warn for unused global bindings | WarnUnusedBindings -- ^ Warn for unused local bindings | WarnNameShadowing -- ^ Warn for name shadowing + | WarnImportNameShadowing -- ^ Warn for shadowing of imported names | WarnOverlapping -- ^ Warn for overlapping rules/alternatives | WarnIncompletePatterns -- ^ Warn for incomplete pattern matching | WarnMissingSignatures -- ^ Warn for missing type signatures @@ -245,6 +246,8 @@ warnFlags = , "unused bindings" ) , ( WarnNameShadowing , "name-shadowing" , "name shadowing" ) + , ( WarnImportNameShadowing , "import-name-shadowing" + , "import name shadowing" ) , ( WarnOverlapping , "overlapping" , "overlapping function rules" ) , ( WarnIncompletePatterns , "incomplete-patterns" diff --git a/test/TestFrontend.hs b/test/TestFrontend.hs index 79aef4584e61f8856e930aeca10b33d7a48b64f3..73a6b1b947f4fb2748c2aff2ff686bfc33d5d922 100644 --- a/test/TestFrontend.hs +++ b/test/TestFrontend.hs @@ -62,6 +62,7 @@ runTest opts test errorMsgs = wOpts = CO.optWarnOpts opts wFlags = CO.WarnUnusedBindings : CO.WarnUnusedGlobalBindings + : CO.WarnImportNameShadowing : CO.wnWarnFlags wOpts opts' = opts { CO.optForce = True , CO.optWarnOpts = wOpts @@ -350,6 +351,8 @@ warnInfos = map (uncurry mkFailTest) ) , ("ShadowingSymbols", [ "Unused declaration of variable `x'", "Shadowing symbol `x'"]) + , ("ShadowingImports", + [ "Shadowing symbol `failed'", "Shadowing symbol `isAlpha'" ]) , ("TabCharacter", [ "Tab character"]) , ("UnexportedFunction", diff --git a/test/warning/ShadowingImports.curry b/test/warning/ShadowingImports.curry new file mode 100644 index 0000000000000000000000000000000000000000..a5b9ecda742c34b32811242bdf311c9981ff3e4f --- /dev/null +++ b/test/warning/ShadowingImports.curry @@ -0,0 +1,5 @@ +module ShadowingImports where + +f failed = failed + +g c = let isAlpha = c in isAlpha