@@ -16,8 +16,8 @@ module Language.PureScript.Sugar.Names (
1616 rename
1717) where
1818
19−import Control.Applicative ((<$>))
20−import Control.Monad (foldM, liftM)
19+import Control.Applicative ((<$>), (<*>))
20+import Control.Monad (forM_, unless, foldM, liftM)
2121import Data.Generics (extM, mkM, everywhereM)
2222import Data.List (intersect)
2323import qualified Data.Map as M
@@ -178,24 +178,53 @@ findImports = foldl findImports' M.empty
178178-- TODO: check explicit imports actually exist
179179--
180180resolveImports :: ExportEnvironment -> Module -> Either String ImportEnvironment
181−resolveImports env (Module currentModule decls) = do
182− types <- resolve exportedTypes (resolveDefs typeImports)
183− dataConstructors <- resolve exportedDataConstructors resolveDcons
184− typeClasses <- resolve exportedTypeClasses (resolveDefs classImports)
185− return $ ImportEnvironment types dataConstructors typeClasses
181+resolveImports env (Module currentModule decls) = ImportEnvironment
182+ <$> resolve (exportedTypes env) (resolveDefs typeImports)
183+ <*> resolve (exportedDataConstructors env) resolveDcons
184+ <*> resolve (exportedTypeClasses env) (resolveDefs classImports)
186185 where
186+ -- A Map from module name to imports from that module, where Nothing indicates everything is to be imported
187+ scope :: M.Map ModuleName (Maybe ExplicitImports)
187188 scope = M.insert currentModule Nothing (findImports decls)
188− resolve get f = foldM f M.empty (M.toList $ get env)
189− resolveDefs filt result (mn, names) = case M.lookup mn scope of
190− Just Nothing -> foldM (resolveDef mn) result (S.toList names)
191− Just (Just expl) -> foldM (resolveDef mn) result (S.toList names `intersect` filt expl)
192− Nothing -> Right result
189+
190+ -- Resolve all exported names in a set by applying a type-specific resolver function
191+ resolve :: M.Map ModuleName (S.Set id) ->
192+ (M.Map ProperName (Qualified ProperName) -> (ModuleName, S.Set id) -> Either String (M.Map ProperName (Qualified ProperName))) ->
193+ Either String (M.Map ProperName (Qualified ProperName))
194+ resolve m f = foldM f M.empty (M.toList m)
195+
196+ -- Resolve a single name by adding it to the Map with a specified ModuleName, checking first
197+ -- that the name does not currently exist in scope.
198+ resolveDef :: (Ord id, Show id) => ModuleName ->
199+ M.Map id (Qualified id) ->
200+ id ->
201+ Either String (M.Map id (Qualified id))
193202 resolveDef mn result name = case M.lookup name result of
194203 Nothing -> return $ M.insert name (Qualified (Just mn) name) result
195204 Just x@(Qualified (Just mn') _) -> Left $ "Module '" ++ show currentModule ++
196205 if mn' == currentModule || mn == currentModule
197206 then "' defines '" ++ show name ++ "' which conflicts with imported definition '" ++ show (Qualified (Just mn) name) ++ "'"
198207 else "' has conflicting imports for '" ++ show name ++ "': '" ++ show x ++ "', '" ++ show (Qualified (Just mn) name) ++ "'"
208+
209+ -- Resolve a set of ProperName exports for a specific imported set of names
210+ -- This function is used to resolve both types and type classes, hence the filter function as
211+ -- its first argument
212+ resolveDefs :: (ExplicitImports -> [ProperName]) ->
213+ M.Map ProperName (Qualified ProperName) ->
214+ (ModuleName, S.Set ProperName) ->
215+ Either String (M.Map ProperName (Qualified ProperName))
216+ resolveDefs filt result (mn, names) = case M.lookup mn scope of
217+ Just Nothing -> foldM (resolveDef mn) result (S.toList names)
218+ Just (Just expl) -> do
219+ forM_ (filt expl) $ \name ->
220+ unless (name `S.member` names) $ Left $ runProperName name ++ " is explicitly imported but not defined"
221+ foldM (resolveDef mn) result (S.toList names `intersect` filt expl)
222+ Nothing -> Right result
223+
224+ -- Resolve a set of data constructors keyed by their type constructor
225+ resolveDcons :: M.Map ProperName (Qualified ProperName) ->
226+ (ModuleName, S.Set (ProperName, [ProperName])) ->
227+ Either String (M.Map ProperName (Qualified ProperName))
199228 resolveDcons result (mn, tcons) = case M.lookup mn scope of
200229 Just Nothing -> foldM (foldM $ resolveDef mn) result (snd `map` S.toList tcons)
201230 Just (Just expl) -> foldM (foldM $ resolveDef mn) result (snd `map` selectedTcons)