Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions examples/failing/DuplicateModule.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- @shouldFailWith DuplicateModule
module M1 where
1 change: 1 addition & 0 deletions examples/failing/DuplicateModule/M1.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module M1 where
1 change: 1 addition & 0 deletions purescript.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ extra-source-files: examples/passing/*.purs
, examples/failing/ConflictingImports2/*.purs
, examples/failing/ConflictingQualifiedImports/*.purs
, examples/failing/ConflictingQualifiedImports2/*.purs
, examples/failing/DuplicateModule/*.purs
, examples/failing/ExportConflictClass/*.purs
, examples/failing/ExportConflictCtor/*.purs
, examples/failing/ExportConflictType/*.purs
Expand Down
7 changes: 5 additions & 2 deletions src/Language/PureScript/AST/Declarations.hs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ data SimpleErrorMessage
| MultipleValueOpFixities (OpName 'ValueOpName)
| MultipleTypeOpFixities (OpName 'TypeOpName)
| OrphanTypeDeclaration Ident
| RedefinedModule ModuleName [SourceSpan]
| RedefinedIdent Ident
| OverlappingNamesInLet
| UnknownName (Qualified Name)
Expand All @@ -59,7 +58,7 @@ data SimpleErrorMessage
| ScopeShadowing Name (Maybe ModuleName) [ModuleName]
| DeclConflict Name Name
| ExportConflict (Qualified Name) (Qualified Name)
| DuplicateModuleName ModuleName
| DuplicateModule ModuleName [SourceSpan]
| DuplicateTypeArgument String
| InvalidDoBind
| InvalidDoLet
Expand Down Expand Up @@ -177,6 +176,10 @@ data Module = Module SourceSpan [Comment] ModuleName [Declaration] (Maybe [Decla
getModuleName :: Module -> ModuleName
getModuleName (Module _ _ name _ _) = name

-- | Return a module's source span.
getModuleSourceSpan :: Module -> SourceSpan
getModuleSourceSpan (Module ss _ _ _ _) = ss

-- |
-- Add an import declaration for a module if it does not already explicitly import it.
--
Expand Down
13 changes: 5 additions & 8 deletions src/Language/PureScript/Errors.hs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ errorCode em = case unwrapErrorMessage em of
MultipleValueOpFixities{} -> "MultipleValueOpFixities"
MultipleTypeOpFixities{} -> "MultipleTypeOpFixities"
OrphanTypeDeclaration{} -> "OrphanTypeDeclaration"
RedefinedModule{} -> "RedefinedModule"
RedefinedIdent{} -> "RedefinedIdent"
OverlappingNamesInLet -> "OverlappingNamesInLet"
UnknownName{} -> "UnknownName"
Expand All @@ -102,7 +101,7 @@ errorCode em = case unwrapErrorMessage em of
ScopeShadowing{} -> "ScopeShadowing"
DeclConflict{} -> "DeclConflict"
ExportConflict{} -> "ExportConflict"
DuplicateModuleName{} -> "DuplicateModuleName"
DuplicateModule{} -> "DuplicateModule"
DuplicateTypeArgument{} -> "DuplicateTypeArgument"
InvalidDoBind -> "InvalidDoBind"
InvalidDoLet -> "InvalidDoLet"
Expand Down Expand Up @@ -486,10 +485,6 @@ prettyPrintSingleError (PPEOptions codeColor full level showWiki) e = flip evalS
line $ "There are multiple fixity/precedence declarations for type operator " ++ markCode (showOp op)
renderSimpleErrorMessage (OrphanTypeDeclaration nm) =
line $ "The type declaration for " ++ markCode (showIdent nm) ++ " should be followed by its definition."
renderSimpleErrorMessage (RedefinedModule name filenames) =
paras [ line ("The module " ++ markCode (runModuleName name) ++ " has been defined multiple times:")
, indent . paras $ map (line . displaySourceSpan) filenames
]
renderSimpleErrorMessage (RedefinedIdent name) =
line $ "The value " ++ markCode (showIdent name) ++ " has been defined multiple times"
renderSimpleErrorMessage (UnknownName name) =
Expand Down Expand Up @@ -519,8 +514,10 @@ prettyPrintSingleError (PPEOptions codeColor full level showWiki) e = flip evalS
line $ "Declaration for " ++ printName (Qualified Nothing new) ++ " conflicts with an existing " ++ nameType existing ++ " of the same name."
renderSimpleErrorMessage (ExportConflict new existing) =
line $ "Export for " ++ printName new ++ " conflicts with " ++ runName existing
renderSimpleErrorMessage (DuplicateModuleName mn) =
line $ "Module " ++ markCode (runModuleName mn) ++ " has been defined multiple times."
renderSimpleErrorMessage (DuplicateModule mn ss) =
paras [ line ("Module " ++ markCode (runModuleName mn) ++ " has been defined multiple times:")
, indent . paras $ map (line . displaySourceSpan) ss
]
renderSimpleErrorMessage (CycleInDeclaration nm) =
line $ "The value of " ++ markCode (showIdent nm) ++ " is undefined here, so this reference is not allowed."
renderSimpleErrorMessage (CycleInModules mns) =
Expand Down
26 changes: 13 additions & 13 deletions src/Language/PureScript/Make.hs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ import Data.Aeson (encode, decode)
import qualified Data.Aeson as Aeson
import Data.ByteString.Builder (toLazyByteString, stringUtf8)
import Data.Either (partitionEithers)
import Data.Function (on)
import Data.Foldable (for_)
import Data.List (foldl', sort)
import Data.List (foldl', sortBy, groupBy)
import Data.Maybe (fromMaybe, catMaybes)
import Data.String (fromString)
import Data.Time.Clock
Expand Down Expand Up @@ -191,18 +192,17 @@ make ma@MakeActions{..} ms = do
where
checkModuleNamesAreUnique :: m ()
checkModuleNamesAreUnique =
case findDuplicate (map getModuleName ms) of
Nothing -> return ()
Just mn -> throwError . errorMessage $ DuplicateModuleName mn

-- Verify that a list of values has unique keys
findDuplicate :: (Ord a) => [a] -> Maybe a
findDuplicate = go . sort
where
go (x : y : xs)
| x == y = Just x
| otherwise = go (y : xs)
go _ = Nothing
for_ (findDuplicates getModuleName ms) $ \mss ->
throwError . flip foldMap mss $ \ms' ->
let mn = getModuleName (head ms')
in errorMessage $ DuplicateModule mn (map getModuleSourceSpan ms')

-- Find all groups of duplicate values in a list based on a projection.
findDuplicates :: Ord b => (a -> b) -> [a] -> Maybe [[a]]
findDuplicates f xs =
case filter ((> 1) . length) . groupBy ((==) `on` f) . sortBy (compare `on` f) $ xs of
[] -> Nothing
xss -> Just xss

-- Sort a list so its elements appear in the same order as in another list.
inOrderOf :: (Ord a) => [a] -> [a] -> [a]
Expand Down
15 changes: 6 additions & 9 deletions src/Language/PureScript/Sugar/Names.hs
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,12 @@ desugarImportsWithEnv externs modules = do
exportedRefs f = M.fromList $ (, efModuleName) <$> mapMaybe f efExports

updateEnv :: ([Module], Env) -> Module -> m ([Module], Env)
updateEnv (ms, env) m@(Module ss _ mn _ refs) =
case mn `M.lookup` env of
Just m' -> throwError . errorMessage $ RedefinedModule mn [envModuleSourceSpan m', ss]
Nothing -> do
members <- findExportable m
let env' = M.insert mn (ss, primImports, members) env
(m', imps) <- resolveImports env' m
exps <- maybe (return members) (resolveExports env' ss mn imps members) refs
return (m' : ms, M.insert mn (ss, imps, exps) env)
updateEnv (ms, env) m@(Module ss _ mn _ refs) = do
members <- findExportable m
let env' = M.insert mn (ss, primImports, members) env

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to check if a module already exists in the name environment anymore since it will be caught during Make and the error raised there.

(m', imps) <- resolveImports env' m
exps <- maybe (return members) (resolveExports env' ss mn imps members) refs
return (m' : ms, M.insert mn (ss, imps, exps) env)

renameInModule' :: Env -> Module -> m Module
renameInModule' env m@(Module _ _ mn _ _) =
Expand Down