@@ -14,6 +14,7 @@
14{-# LANGUAGE FlexibleContexts #-}
14{-# LANGUAGE FlexibleContexts #-}
15{-# LANGUAGE ScopedTypeVariables #-}
15{-# LANGUAGE ScopedTypeVariables #-}
16{-# LANGUAGE TupleSections #-}
16{-# LANGUAGE TupleSections #-}
17+{-# LANGUAGE LambdaCase #-}
18module Language.PureScript.Sugar.Names.Imports
19module Language.PureScript.Sugar.Names.Imports
19 ( resolveImports
20 ( resolveImports
@@ -24,9 +25,10 @@ module Language.PureScript.Sugar.Names.Imports
24import Prelude ()
25import Prelude ()
25import Prelude.Compat
26import Prelude.Compat
27−import Data.List (find, delete)
28+import Data.List (find, delete, (\\))
28import Data.Maybe (fromMaybe, isJust, isNothing, fromJust)
29import Data.Maybe (fromMaybe, isJust, isNothing, fromJust)
29import Data.Foldable (traverse_, for_)
30import Data.Foldable (traverse_, for_)
31+import Data.Traversable (for)
31import Control.Arrow (first)
33import Control.Arrow (first)
32import Control.Monad
34import Control.Monad
@@ -64,33 +66,48 @@ findImports = foldM (go Nothing) M.empty
64 checkImportRef (ModuleRef name) = throwError . errorMessage $ ImportHidingModule name
66 checkImportRef (ModuleRef name) = throwError . errorMessage $ ImportHidingModule name
65 checkImportRef _ = return ()
67 checkImportRef _ = return ()
69+type ImportDef = (Maybe SourceSpan, ImportDeclarationType, Maybe ModuleName)
68-- Constructs a set of imports for a module.
72-- Constructs a set of imports for a module.
70−resolveImports :: (Applicative m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) => Env -> Module -> m Imports
74+resolveImports :: forall m. (Applicative m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) => Env -> Module -> m Imports
71resolveImports env (Module _ _ currentModule decls _) =
75resolveImports env (Module _ _ currentModule decls _) =
72 warnAndRethrow (addHint (ErrorInModule currentModule)) $ do
76 warnAndRethrow (addHint (ErrorInModule currentModule)) $ do
73 imports <- findImports decls
77 imports <- findImports decls
75 for_ (M.toList imports) $ \(mn, imps) -> do
79 for_ (M.toList imports) $ \(mn, imps) -> do
76− let unqual = filter (\(_, _, q) -> isJust q) (reverse imps)
81+ -- Better ordering for the warnings: the list is in last-import-first
82+ -- order, but we want the first appearence of an import to be the primary,
83+ -- and warnings to appear for later imports
84+ let imps' = reverse imps
78− when (length imps > 1) $ for_ (selfCartesianSubset imps) $
86+ warned <- foldM (checkDuplicateImports mn) [] (selfCartesianSubset imps')
79− \((_, t1, q1), (pos, t2, q2)) ->
87+
80− when (t1 == t2 && q1 == q2) $
88+ let unqual = filter (\(_, _, q) -> isJust q) (imps' \\ warned)
81− maybe id warnWithPosition pos $
82− tell . errorMessage $ DuplicateImport mn t2 q2
90+ warned' <- (warned ++) <$>
84− when (length unqual > 1) $
91+ if (length unqual < 2)
85− case find (\(_, typ, _) -> typ == Implicit) unqual of
93+ else case find (\(_, typ, _) -> typ == Implicit) unqual of
87− for_ (delete i unqual) $ \(pos, typ, _) ->
95+ for (delete i unqual) $ \i'@(pos, typ, _) -> do
88− maybe id warnWithPosition pos $
89− tell $ errorMessage $ RedundantUnqualifiedImport mn typ
96+ warn pos $ RedundantUnqualifiedImport mn typ
90 Nothing ->
98 Nothing ->
91− for_ (tail unqual) $ \(pos, _, _) ->
99+ for (tail unqual) $ \i@(pos, _, _) -> do
92− maybe id warnWithPosition pos $
93− tell $ errorMessage $ DuplicateSelectiveImport mn
100+ warn pos $ DuplicateSelectiveImport mn
103+ for_ (imps' \\ warned') $ \(pos, typ, _) ->
104+ let (dupeRefs, dupeDctors) = findDuplicateRefs $ case typ of
105+ Explicit refs -> refs
108+ in warnDupeRefs pos dupeRefs >> warnDupeDctors pos dupeDctors
95 let scope = M.insert currentModule [(Nothing, Implicit, Nothing)] imports
112 let scope = M.insert currentModule [(Nothing, Implicit, Nothing)] imports
96 foldM (resolveModuleImport currentModule env) nullImports (M.toList scope)
113 foldM (resolveModuleImport currentModule env) nullImports (M.toList scope)
@@ -100,6 +117,31 @@ resolveImports env (Module _ _ currentModule decls _) =
100 selfCartesianSubset (x : xs) = [(x, y) | y <- xs] ++ selfCartesianSubset xs
117 selfCartesianSubset (x : xs) = [(x, y) | y <- xs] ++ selfCartesianSubset xs
101 selfCartesianSubset [] = []
118 selfCartesianSubset [] = []
120+ checkDuplicateImports :: ModuleName -> [ImportDef] -> (ImportDef, ImportDef) -> m [ImportDef]
121+ checkDuplicateImports mn xs ((_, t1, q1), (pos, t2, q2)) =
122+ if (t1 == t2 && q1 == q2)
124+ warn pos $ DuplicateImport mn t2 q2
125+ return $ (pos, t2, q2) : xs
128+ warnDupeRefs :: Maybe SourceSpan -> [DeclarationRef] -> m ()
129+ warnDupeRefs pos = traverse_ $ \case
130+ TypeRef name _ -> warnDupe pos $ "type " ++ runProperName name
131+ ValueRef name -> warnDupe pos $ "value " ++ runIdent name
132+ TypeClassRef name -> warnDupe pos $ "class " ++ runProperName name
133+ ModuleRef name -> warnDupe pos $ "module " ++ runModuleName name
136+ warnDupeDctors :: Maybe SourceSpan -> [ProperName] -> m ()
137+ warnDupeDctors pos = traverse_ (warnDupe pos . ("data constructor " ++) . runProperName)
139+ warnDupe :: Maybe SourceSpan -> String -> m ()
140+ warnDupe pos ref = warn pos $ DuplicateImportRef ref
142+ warn :: Maybe SourceSpan -> SimpleErrorMessage -> m ()
143+ warn pos msg = maybe id warnWithPosition pos $ tell . errorMessage $ msg
103-- | Constructs a set of imports for a single module import.
145-- | Constructs a set of imports for a single module import.
104resolveModuleImport ::
146resolveModuleImport ::
105 forall m. (Applicative m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) =>
147 forall m. (Applicative m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) =>