@@ -16,6 +16,7 @@ import Data.Foldable (forM_)
17import Language.PureScript.AST.Declarations
17import Language.PureScript.AST.Declarations
18import Language.PureScript.AST.SourcePos
18import Language.PureScript.AST.SourcePos
19+import Language.PureScript.Crash
19import Language.PureScript.Names as P
20import Language.PureScript.Names as P
21import Language.PureScript.Errors
22import Language.PureScript.Errors
@@ -30,6 +31,19 @@ data Name
30 | TypeName (Qualified ProperName)
31 | TypeName (Qualified ProperName)
31 | DctorName (Qualified ProperName)
32 | DctorName (Qualified ProperName)
32 | ClassName (Qualified ProperName)
33 | ClassName (Qualified ProperName)
36+getIdentName :: Name -> Maybe Ident
37+getIdentName (IdentName (Qualified _ name)) = Just name
38+getIdentName _ = Nothing
40+getTypeName :: Name -> Maybe ProperName
41+getTypeName (TypeName (Qualified _ name)) = Just name
42+getTypeName _ = Nothing
44+getClassName :: Name -> Maybe ProperName
45+getClassName (ClassName (Qualified _ name)) = Just name
46+getClassName _ = Nothing
34-- | Map of module name to list of imported names from that module which have been used.
48-- | Map of module name to list of imported names from that module which have been used.
35type UsedImports = M.Map ModuleName [Name]
49type UsedImports = M.Map ModuleName [Name]
@@ -44,11 +58,21 @@ findUnusedImports (Module _ _ _ mdecls mexports) env usedImps = do
44 forM_ (M.toAscList imps) $ \(mni, decls) -> unless (mni `elem` alwaysUsedModules) $
58 forM_ (M.toAscList imps) $ \(mni, decls) -> unless (mni `elem` alwaysUsedModules) $
45 forM_ decls $ \(ss, declType, qualifierName) ->
59 forM_ decls $ \(ss, declType, qualifierName) ->
46 censor (onErrorMessages $ addModuleLocError ss) $ unless (qnameUsed qualifierName) $
60 censor (onErrorMessages $ addModuleLocError ss) $ unless (qnameUsed qualifierName) $
47− let names = sugarNames mni ++ M.findWithDefault [] mni usedImps
61+ let names = nub $ sugarNames mni ++ M.findWithDefault [] mni usedImps
48 usedNames = mapMaybe (matchName (typeForDCtor mni) qualifierName) names
62 usedNames = mapMaybe (matchName (typeForDCtor mni) qualifierName) names
49 usedDctors = mapMaybe (matchDctor qualifierName) names
63 usedDctors = mapMaybe (matchDctor qualifierName) names
50 in case declType of
64 in case declType of
51− Implicit -> when (null usedNames) $ tell $ errorMessage $ UnusedImport mni
65+ Implicit _ | null usedNames -> tell $ errorMessage $ UnusedImport mni
67+ let classRefs = TypeClassRef <$> mapMaybe getClassName names
68+ valueRefs = ValueRef <$> mapMaybe getIdentName names
69+ types = mapMaybe getTypeName names
70+ typesWithDctors = reconstructTypeRefs mni usedDctors
71+ typesWithoutDctors = filter (`M.notMember` typesWithDctors) types
73+ = map (flip TypeRef (Just [])) typesWithoutDctors
74+ ++ map (\(ty, ds) -> TypeRef ty (Just ds)) (M.toList typesWithDctors)
75+ in tell $ errorMessage $ ImplicitImport mni (classRefs ++ typesRefs ++ valueRefs)
52 Explicit declrefs -> do
76 Explicit declrefs -> do
53 let idents = nub (mapMaybe runDeclRef declrefs)
77 let idents = nub (mapMaybe runDeclRef declrefs)
54 let diff = idents \\ usedNames
78 let diff = idents \\ usedNames
@@ -76,6 +100,20 @@ findUnusedImports (Module _ _ _ mdecls mexports) env usedImps = do
76 sugarNames (ModuleName [ProperName n]) | n == C.prelude = [ IdentName $ Qualified Nothing (Ident C.bind) ]
100 sugarNames (ModuleName [ProperName n]) | n == C.prelude = [ IdentName $ Qualified Nothing (Ident C.bind) ]
77 sugarNames _ = []
101 sugarNames _ = []
103+ reconstructTypeRefs :: ModuleName -> [ProperName] -> M.Map ProperName [ProperName]
104+ reconstructTypeRefs mni = foldr accumDctors M.empty
106+ accumDctors dctor = M.alter (Just . maybe [dctor] (dctor :)) (findTypeForDctor mni dctor)
108+ findTypeForDctor :: ModuleName -> ProperName -> ProperName
109+ findTypeForDctor mn dctor =
110+ case mn `M.lookup` env of
111+ Just (_, _, exps) ->
112+ case find (elem dctor . snd . fst) (exportedTypes exps) of
113+ Just ((ty, _), _) -> ty
114+ Nothing -> internalError $ "missing type for data constructor " ++ runProperName dctor ++ " in findTypeForDctor"
115+ Nothing -> internalError $ "missing module " ++ runModuleName mn ++ " in findTypeForDctor"
79 -- rely on exports being elaborated by this point
117 -- rely on exports being elaborated by this point
80 alwaysUsedModules :: [ ModuleName ]
118 alwaysUsedModules :: [ ModuleName ]
81 alwaysUsedModules = ModuleName [ProperName C.prim] : maybe [] (mapMaybe extractModule) mexports
119 alwaysUsedModules = ModuleName [ProperName C.prim] : maybe [] (mapMaybe extractModule) mexports
@@ -121,7 +159,7 @@ runDeclRef :: DeclarationRef -> Maybe String
121runDeclRef (PositionedDeclarationRef _ _ ref) = runDeclRef ref
159runDeclRef (PositionedDeclarationRef _ _ ref) = runDeclRef ref
122runDeclRef (ValueRef ident) = Just $ showIdent ident
160runDeclRef (ValueRef ident) = Just $ showIdent ident
123runDeclRef (TypeRef pn _) = Just $ runProperName pn
161runDeclRef (TypeRef pn _) = Just $ runProperName pn
124−runDeclRef (TypeClassRef pn) = Just $ runProperName pn
162+runDeclRef (TypeClassRef pn) = Just $ "class " ++ runProperName pn
125runDeclRef _ = Nothing
163runDeclRef _ = Nothing
127getTypeRef :: DeclarationRef -> Maybe (ProperName, Maybe [ProperName])
165getTypeRef :: DeclarationRef -> Maybe (ProperName, Maybe [ProperName])