@@ -47,11 +47,13 @@ import Control.Monad
4747import Control.Monad.Error (throwError, catchError)
4848import Control.Monad.State.Strict
4949
50+import Data.Function
5051import Data.Maybe
5152import qualified Data.List.Split as Spl
5253import Data.List
5354import Data.Monoid
5455import Data.Char
56+import Data.Ord
5557import qualified Data.Map as M
5658import qualified Data.HashSet as HS
5759import qualified Data.Text as T
@@ -92,12 +94,13 @@ moduleHeader = try (do reserved "module"
9294{- | Parses an import statement
9395 Import ::= 'import' Identifier_t ';'?;
9496 -}
95−import_ :: IdrisParser (String, Maybe String)
96−import_ = do reserved "import"
97+import_ :: IdrisParser (String, Maybe String, FC)
98+import_ = do fc <- getFC
99+ reserved "import"
97100 id <- identifier
98101 newName <- optional (reserved "as" *> identifier)
99102 option ';' (lchar ';')
100− return (toPath id, toPath <$> newName)
103+ return (toPath id, toPath <$> newName, fc)
101104 <?> "import statement"
102105 where toPath = foldl1' (</>) . Spl.splitOn "."
103106
@@ -936,7 +939,7 @@ parseTactic :: IState -> String -> Result PTactic
936939parseTactic st = runparser (fullTactic defaultSyntax) st "(input)"
937940
938941-- | Parse module header and imports
939−parseImports :: FilePath -> String -> Idris ([String], [(String, Maybe String)], Maybe Delta)
942+parseImports :: FilePath -> String -> Idris ([String], [(String, Maybe String, FC)], Maybe Delta)
940943parseImports fname input
941944 = do i <- getIState
942945 case parseString (runInnerParser (evalStateT imports i)) (Directed (UTF8.fromString fname) 0 0 0 0) input of
@@ -944,7 +947,7 @@ parseImports fname input
944947 Success (x, i) -> do -- Discard state updates (there should be
945948 -- none anyway)
946949 return x
947− where imports :: IdrisParser (([String], [(String, Maybe String)], Maybe Delta), IState)
950+ where imports :: IdrisParser (([String], [(String, Maybe String, FC)], Maybe Delta), IState)
948951 imports = do whiteSpace
949952 mname <- moduleHeader
950953 ps <- many import_
@@ -1056,15 +1059,21 @@ loadSource h lidr f
10561059 file_in <- runIO $ readFile f
10571060 file <- if lidr then tclift $ unlit f file_in else return file_in
10581061 (mname, imports, pos) <- parseImports f file
1059− let modules = map fst imports
1060− modAliases = M.fromList
1061− [(prep alias, prep realName) | (realName, Just alias) <- imports]
1062+
1063+ -- process and check module aliases
1064+ let modAliases = M.fromList
1065+ [(prep alias, prep realName) | (realName, Just alias, fc) <- imports]
10621066 prep = map T.pack . reverse . Spl.splitOn "/"
1063− logLvl 3 $ "Module aliases: " ++ show (M.toList modAliases)
1067+ aliasNames = [(alias, fc) | (_, Just alias, fc) <- imports]
1068+ histogram = groupBy ((==) `on` fst) . sortBy (comparing fst) $ aliasNames
1069+ case map head . filter ((/= 1) . length) $ histogram of
1070+ [] -> logLvl 3 $ "Module aliases: " ++ show (M.toList modAliases)
1071+ (n,fc):_ -> throwError . At fc . Msg $ "import alias not unique: " ++ show n
1072+
10641073 i <- getIState
10651074 putIState (i { default_access = Hidden, module_aliases = modAliases })
10661075 clearIBC -- start a new .ibc file
1067− mapM_ (addIBC . IBCImport) modules
1076+ mapM_ (addIBC . IBCImport) [realName | (realName, alias, fc) <- imports]
10681077 let syntax = defaultSyntax{ syn_namespace = reverse mname }
10691078 ds' <- parseProg syntax f file pos
10701079 unless (null ds') $ do