@@ -1,4 +1,5 @@
1{-# LANGUAGE FlexibleContexts #-}
1{-# LANGUAGE FlexibleContexts #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
3module Language.PureScript.Sugar.Names.Env
4module Language.PureScript.Sugar.Names.Env
4 ( Imports(..)
5 ( Imports(..)
@@ -14,14 +15,18 @@ module Language.PureScript.Sugar.Names.Env
14 , exportTypeClass
15 , exportTypeClass
15 , exportValue
16 , exportValue
16 , getExports
17 , getExports
18+ , checkImportConflicts
21+import Data.Function (on)
22+import Data.List (groupBy, sortBy, nub)
19import qualified Data.Map as M
23import qualified Data.Map as M
21import Control.Monad
25import Control.Monad
22import Control.Monad.Error.Class (MonadError(..))
26import Control.Monad.Error.Class (MonadError(..))
24import Language.PureScript.AST
28import Language.PureScript.AST
29+import Language.PureScript.Crash
25import Language.PureScript.Names
30import Language.PureScript.Names
26import Language.PureScript.Environment
31import Language.PureScript.Environment
27import Language.PureScript.Errors
32import Language.PureScript.Errors
@@ -34,19 +39,19 @@ data Imports = Imports
35 -- Local names for types within a module mapped to to their qualified names
40 -- Local names for types within a module mapped to to their qualified names
37− importedTypes :: M.Map (Qualified ProperName) (Qualified ProperName, ModuleName)
42+ importedTypes :: M.Map (Qualified ProperName) [(Qualified ProperName, ModuleName)]
39 -- Local names for data constructors within a module mapped to to their qualified names
44 -- Local names for data constructors within a module mapped to to their qualified names
41− , importedDataConstructors :: M.Map (Qualified ProperName) (Qualified ProperName, ModuleName)
46+ , importedDataConstructors :: M.Map (Qualified ProperName) [(Qualified ProperName, ModuleName)]
43 -- Local names for classes within a module mapped to to their qualified names
48 -- Local names for classes within a module mapped to to their qualified names
45− , importedTypeClasses :: M.Map (Qualified ProperName) (Qualified ProperName, ModuleName)
50+ , importedTypeClasses :: M.Map (Qualified ProperName) [(Qualified ProperName, ModuleName)]
47 -- Local names for values within a module mapped to to their qualified names
52 -- Local names for values within a module mapped to to their qualified names
49− , importedValues :: M.Map (Qualified Ident) (Qualified Ident, ModuleName)
54+ , importedValues :: M.Map (Qualified Ident) [(Qualified Ident, ModuleName)]
51 -- The list of modules that have been imported into the current scope.
56 -- The list of modules that have been imported into the current scope.
@@ -132,15 +137,17 @@ primEnv = M.singleton
133exportType :: (MonadError MultipleErrors m) => Exports -> ProperName -> [ProperName] -> ModuleName -> m Exports
138exportType :: (MonadError MultipleErrors m) => Exports -> ProperName -> [ProperName] -> ModuleName -> m Exports
134exportType exps name dctors mn = do
139exportType exps name dctors mn = do
135− let exTypes = exportedTypes exps
140+ let exTypes' = exportedTypes exps
141+ let exTypes = filter ((/= mn) . snd) exTypes'
136 let exDctors = (snd . fst) `concatMap` exTypes
142 let exDctors = (snd . fst) `concatMap` exTypes
137 let exClasses = exportedTypeClasses exps
143 let exClasses = exportedTypeClasses exps
138− when (any (\((name', _), _) -> name == name') exTypes) $ throwConflictError ConflictingTypeDecls name
145+ when (any ((== name) . fst . fst) exTypes) $ throwConflictError ConflictingTypeDecls name
139 when (any ((== name) . fst) exClasses) $ throwConflictError TypeConflictsWithClass name
146 when (any ((== name) . fst) exClasses) $ throwConflictError TypeConflictsWithClass name
140 forM_ dctors $ \dctor -> do
147 forM_ dctors $ \dctor -> do
141 when (dctor `elem` exDctors) $ throwConflictError ConflictingCtorDecls dctor
148 when (dctor `elem` exDctors) $ throwConflictError ConflictingCtorDecls dctor
142 when (any ((== dctor) . fst) exClasses) $ throwConflictError CtorConflictsWithClass dctor
149 when (any ((== dctor) . fst) exClasses) $ throwConflictError CtorConflictsWithClass dctor
143− return $ exps { exportedTypes = ((name, dctors), mn) : exTypes }
150+ return $ exps { exportedTypes = nub $ ((name, dctors), mn) : exTypes' }
146-- Safely adds a class to some exports, returning an error if a conflict occurs.
153-- Safely adds a class to some exports, returning an error if a conflict occurs.
@@ -149,7 +156,7 @@ exportTypeClass :: (MonadError MultipleErrors m) => Exports -> ProperName -> Mod
149exportTypeClass exps name mn = do
156exportTypeClass exps name mn = do
150 let exTypes = exportedTypes exps
157 let exTypes = exportedTypes exps
151 let exDctors = (snd . fst) `concatMap` exTypes
158 let exDctors = (snd . fst) `concatMap` exTypes
152− when (any (\((name', _), _) -> name == name') exTypes) $ throwConflictError ClassConflictsWithType name
159+ when (any ((== name) . fst . fst) exTypes) $ throwConflictError ClassConflictsWithType name
153 when (name `elem` exDctors) $ throwConflictError ClassConflictsWithCtor name
160 when (name `elem` exDctors) $ throwConflictError ClassConflictsWithCtor name
154 classes <- addExport DuplicateClassExport name mn (exportedTypeClasses exps)
161 classes <- addExport DuplicateClassExport name mn (exportedTypeClasses exps)
155 return $ exps { exportedTypeClasses = classes }
162 return $ exps { exportedTypeClasses = classes }
@@ -168,9 +175,9 @@ exportValue exps name mn = do
169addExport :: (MonadError MultipleErrors m, Eq a) => (a -> SimpleErrorMessage) -> a -> ModuleName -> [(a, ModuleName)] -> m [(a, ModuleName)]
176addExport :: (MonadError MultipleErrors m, Eq a) => (a -> SimpleErrorMessage) -> a -> ModuleName -> [(a, ModuleName)] -> m [(a, ModuleName)]
170addExport what name mn exports =
177addExport what name mn exports =
171− if any ((== name) . fst) exports
178+ if any (\(name', mn') -> name == name' && mn /= mn') exports
172 then throwConflictError what name
179 then throwConflictError what name
173− else return $ (name, mn) : exports
180+ else return $ nub $ (name, mn) : exports
176-- Raises an error for when there is more than one definition for something.
183-- Raises an error for when there is more than one definition for something.
@@ -181,3 +188,26 @@ throwConflictError conflict = throwError . errorMessage . conflict
181-- Gets the exports for a module, or an error message if the module doesn't exist
188-- Gets the exports for a module, or an error message if the module doesn't exist
182getExports :: (MonadError MultipleErrors m) => Env -> ModuleName -> m Exports
189getExports :: (MonadError MultipleErrors m) => Env -> ModuleName -> m Exports
183getExports env mn = maybe (throwError . errorMessage $ UnknownModule mn) (return . envModuleExports) $ M.lookup mn env
190getExports env mn = maybe (throwError . errorMessage $ UnknownModule mn) (return . envModuleExports) $ M.lookup mn env
193+-- When reading a value from the imports, check that there are no conflicts in
198+ . (MonadError MultipleErrors m, Ord a)
200+ -> [(Qualified a, ModuleName)]
202+checkImportConflicts render xs =
203+ let byOrig = groupBy ((==) `on` snd) . sortBy (compare `on` snd) $ xs
205+ if length byOrig > 1
206+ then throwError . errorMessage $ ScopeConflict (render' (fst . head $ xs)) (map (getQual . fst . head) byOrig)
209+ getQual :: Qualified a -> ModuleName
210+ getQual (Qualified (Just mn) _) = mn
211+ getQual _ = internalError "unexpected unqualified name in checkImportConflicts"
212+ render' :: Qualified a -> String
213+ render' (Qualified _ a) = render a