@@ -16,6 +16,7 @@ import Data.Foldable (forM_)
1616
1717import Language.PureScript.AST.Declarations
1818import Language.PureScript.AST.SourcePos
19+import Language.PureScript.Crash
1920import Language.PureScript.Names as P
2021
2122import Language.PureScript.Errors
@@ -30,6 +31,19 @@ data Name
3031 | TypeName (Qualified ProperName)
3132 | DctorName (Qualified ProperName)
3233 | ClassName (Qualified ProperName)
34+ deriving (Eq)
35+
36+getIdentName :: Name -> Maybe Ident
37+getIdentName (IdentName (Qualified _ name)) = Just name
38+getIdentName _ = Nothing
39+
40+getTypeName :: Name -> Maybe ProperName
41+getTypeName (TypeName (Qualified _ name)) = Just name
42+getTypeName _ = Nothing
43+
44+getClassName :: Name -> Maybe ProperName
45+getClassName (ClassName (Qualified _ name)) = Just name
46+getClassName _ = Nothing
3347
3448-- | Map of module name to list of imported names from that module which have been used.
3549type UsedImports = M.Map ModuleName [Name]
@@ -44,11 +58,21 @@ findUnusedImports (Module _ _ _ mdecls mexports) env usedImps = do
4458 forM_ (M.toAscList imps) $ \(mni, decls) -> unless (mni `elem` alwaysUsedModules) $
4559 forM_ decls $ \(ss, declType, qualifierName) ->
4660 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
4862 usedNames = mapMaybe (matchName (typeForDCtor mni) qualifierName) names
4963 usedDctors = mapMaybe (matchDctor qualifierName) names
5064 in case declType of
51− Implicit -> when (null usedNames) $ tell $ errorMessage $ UnusedImport mni
65+ Implicit _ | null usedNames -> tell $ errorMessage $ UnusedImport mni
66+ Implicit False ->
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
72+ typesRefs
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)
5276 Explicit declrefs -> do
5377 let idents = nub (mapMaybe runDeclRef declrefs)
5478 let diff = idents \\ usedNames
@@ -76,6 +100,20 @@ findUnusedImports (Module _ _ _ mdecls mexports) env usedImps = do
76100 sugarNames (ModuleName [ProperName n]) | n == C.prelude = [ IdentName $ Qualified Nothing (Ident C.bind) ]
77101 sugarNames _ = []
78102
103+ reconstructTypeRefs :: ModuleName -> [ProperName] -> M.Map ProperName [ProperName]
104+ reconstructTypeRefs mni = foldr accumDctors M.empty
105+ where
106+ accumDctors dctor = M.alter (Just . maybe [dctor] (dctor :)) (findTypeForDctor mni dctor)
107+
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"
116+
79117 -- rely on exports being elaborated by this point
80118 alwaysUsedModules :: [ ModuleName ]
81119 alwaysUsedModules = ModuleName [ProperName C.prim] : maybe [] (mapMaybe extractModule) mexports
@@ -121,7 +159,7 @@ runDeclRef :: DeclarationRef -> Maybe String
121159runDeclRef (PositionedDeclarationRef _ _ ref) = runDeclRef ref
122160runDeclRef (ValueRef ident) = Just $ showIdent ident
123161runDeclRef (TypeRef pn _) = Just $ runProperName pn
124−runDeclRef (TypeClassRef pn) = Just $ runProperName pn
162+runDeclRef (TypeClassRef pn) = Just $ "class " ++ runProperName pn
125163runDeclRef _ = Nothing
126164
127165getTypeRef :: DeclarationRef -> Maybe (ProperName, Maybe [ProperName])