purescript 0.4.10.2 → 0.4.11
raw patch · 20 files changed
+306/−238 lines, 20 files
Files
- purescript.cabal +2/−1
- src/Language/PureScript.hs +5/−4
- src/Language/PureScript/Declarations.hs +6/−3
- src/Language/PureScript/Errors.hs +111/−0
- src/Language/PureScript/Optimizer.hs +4/−2
- src/Language/PureScript/Optimizer/Inliner.hs +9/−1
- src/Language/PureScript/Optimizer/Unused.hs +11/−1
- src/Language/PureScript/Parser/Declarations.hs +1/−1
- src/Language/PureScript/Sugar.hs +2/−1
- src/Language/PureScript/Sugar/BindingGroups.hs +7/−6
- src/Language/PureScript/Sugar/CaseDeclarations.hs +11/−7
- src/Language/PureScript/Sugar/DoNotation.hs +6/−5
- src/Language/PureScript/Sugar/Names.hs +69/−72
- src/Language/PureScript/Sugar/Operators.hs +21/−16
- src/Language/PureScript/Sugar/TypeClasses.hs +7/−6
- src/Language/PureScript/Sugar/TypeDeclarations.hs +12/−7
- src/Language/PureScript/TypeChecker.hs +2/−1
- src/Language/PureScript/TypeChecker/Kinds.hs +4/−3
- src/Language/PureScript/TypeChecker/Monad.hs +4/−90
- src/Language/PureScript/TypeChecker/Types.hs +12/−11
purescript.cabal view
@@ -1,5 +1,5 @@ name: purescript-version: 0.4.10.2+version: 0.4.11 cabal-version: >=1.8 build-type: Custom license: MIT@@ -32,6 +32,7 @@ Language.PureScript.Options Language.PureScript.Declarations Language.PureScript.Environment+ Language.PureScript.Errors Language.PureScript.Kinds Language.PureScript.Names Language.PureScript.Types
src/Language/PureScript.hs view
@@ -28,6 +28,7 @@ import Language.PureScript.Options as P import Language.PureScript.ModuleDependencies as P import Language.PureScript.Environment as P+import Language.PureScript.Errors as P import Language.PureScript.DeadCodeElimination as P import qualified Language.PureScript.Constants as C@@ -70,9 +71,9 @@ compile' :: Environment -> Options -> [Module] -> Either String (String, String, Environment) compile' env opts ms = do (sorted, _) <- sortModules $ if optionsNoPrelude opts then ms else (map importPrelude ms)- desugared <- desugar sorted+ desugared <- stringifyErrorStack True $ desugar sorted (elaborated, env') <- runCheck' opts env $ forM desugared $ typeCheckModule mainModuleIdent- regrouped <- createBindingGroupsModule . collapseBindingGroupsModule $ elaborated+ regrouped <- stringifyErrorStack True $ createBindingGroupsModule . collapseBindingGroupsModule $ elaborated let entryPoints = moduleNameFromString `map` optionsModules opts let elim = if null entryPoints then regrouped else eliminateDeadCode entryPoints regrouped let codeGenModules = moduleNameFromString `map` optionsCodeGenModules opts@@ -184,7 +185,7 @@ marked <- rebuildIfNecessary (reverseDependencies graph) toRebuild sorted - desugared <- liftError $ zip (map fst marked) <$> desugar (map snd marked)+ desugared <- liftError $ stringifyErrorStack True $ zip (map fst marked) <$> desugar (map snd marked) go initEnvironment desugared @@ -202,7 +203,7 @@ (Module _ elaborated _, env') <- liftError . runCheck' opts env $ typeCheckModule Nothing m - regrouped <- liftError . createBindingGroups moduleName' . collapseBindingGroups $ elaborated+ regrouped <- liftError . stringifyErrorStack True . createBindingGroups moduleName' . collapseBindingGroups $ elaborated let mod' = Module moduleName' regrouped exps js = moduleToJs opts mod' env'
src/Language/PureScript/Declarations.hs view
@@ -45,11 +45,14 @@ -- Source position information -- data SourcePos = SourcePos- {+ { -- |+ -- Source name+ --+ sourceName :: String -- | -- Line number --- sourcePosLine :: Int+ , sourcePosLine :: Int -- | -- Column number --@@ -57,7 +60,7 @@ } deriving (D.Data, D.Typeable) instance Show SourcePos where- show sp = "line " ++ show (sourcePosLine sp) ++ ", column " ++ show (sourcePosColumn sp)+ show sp = (sourceName sp) ++ " line " ++ show (sourcePosLine sp) ++ ", column " ++ show (sourcePosColumn sp) -- | -- Fixity data for infix operators
+ src/Language/PureScript/Errors.hs view
@@ -0,0 +1,111 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.Error+-- Copyright : (c) 2013-14 Phil Freeman, (c) 2014 Gary Burgess, and other contributors+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++{-# LANGUAGE GeneralizedNewtypeDeriving, FlexibleContexts #-}++module Language.PureScript.Errors where++import Data.List (intercalate)+import Data.Monoid++import Control.Monad.Error++import Language.PureScript.Declarations+import Language.PureScript.Pretty+import Language.PureScript.Types++-- |+-- Type for sources of type checking errors+--+data ErrorSource+ -- |+ -- An error which originated at a Value+ --+ = ValueError Value+ -- |+ -- An error which originated at a Type+ --+ | TypeError Type deriving (Show)++-- |+-- Compilation errors+--+data CompileError = CompileError {+ -- |+ -- Error message+ --+ compileErrorMessage :: String+ -- |+ -- The value where the error occurred+ --+ , compileErrorValue :: Maybe ErrorSource+ -- |+ -- Optional source position information+ --+ , compileErrorPosition :: Maybe SourcePos+ } deriving (Show)++-- |+-- A stack trace for an error+--+newtype ErrorStack = ErrorStack { runErrorStack :: [CompileError] } deriving (Show, Monoid)++instance Error ErrorStack where+ strMsg s = ErrorStack [CompileError s Nothing Nothing]+ noMsg = ErrorStack []++prettyPrintErrorStack :: Bool -> ErrorStack -> String+prettyPrintErrorStack printFullStack (ErrorStack es) =+ case mconcat $ map (Last . compileErrorPosition) es of+ Last (Just sourcePos) -> "Error at " ++ show sourcePos ++ ": \n" ++ prettyPrintErrorStack'+ _ -> prettyPrintErrorStack'+ where+ prettyPrintErrorStack' :: String+ prettyPrintErrorStack'+ | printFullStack = intercalate "\n" (map showError (filter isErrorNonEmpty es))+ | otherwise =+ let+ es' = filter isErrorNonEmpty es+ in case length es' of+ 1 -> showError (head es')+ _ -> showError (head es') ++ "\n" ++ showError (last es')++stringifyErrorStack :: Bool -> Either ErrorStack a -> Either String a+stringifyErrorStack printFullStack = either (Left . prettyPrintErrorStack printFullStack) Right++isErrorNonEmpty :: CompileError -> Bool+isErrorNonEmpty = not . null . compileErrorMessage++showError :: CompileError -> String+showError (CompileError msg Nothing _) = msg+showError (CompileError msg (Just (ValueError val)) _) = "Error in value " ++ prettyPrintValue val ++ ":\n" ++ msg+showError (CompileError msg (Just (TypeError ty)) _) = "Error in type " ++ prettyPrintType ty ++ ":\n" ++ msg++mkErrorStack :: String -> Maybe ErrorSource -> ErrorStack+mkErrorStack msg t = ErrorStack [CompileError msg t Nothing]++positionError :: SourcePos -> ErrorStack+positionError pos = ErrorStack [CompileError "" Nothing (Just pos)]++-- |+-- Rethrow an error with a more detailed error message in the case of failure+--+rethrow :: (MonadError e m) => (e -> e) -> m a -> m a+rethrow f = flip catchError $ \e -> throwError (f e)++-- |+-- Rethrow an error with source position information+--+rethrowWithPosition :: (MonadError ErrorStack m) => SourcePos -> m a -> m a+rethrowWithPosition pos = rethrow (positionError pos <>)
src/Language/PureScript/Optimizer.hs view
@@ -53,19 +53,21 @@ -- optimize :: Options -> JS -> JS optimize opts | optionsNoOptimizations opts = id- | otherwise = untilFixedPoint $ applyAll+ | otherwise = untilFixedPoint (applyAll [ collapseNestedBlocks , tco opts , magicDo opts , removeUnusedVariables+ , removeCodeAfterReturnStatements , unThunk , etaConvert+ , evaluateIifes , inlineVariables , inlineOperator (C.$) $ \f x -> JSApp f [x] , inlineOperator (C.#) $ \x f -> JSApp f [x] , inlineOperator (C.!!) $ flip JSIndexer , inlineOperator (C.++) $ JSBinary Add- , inlineCommonOperators ]+ , inlineCommonOperators ]) untilFixedPoint :: (Eq a) => (a -> a) -> a -> a untilFixedPoint f = go
src/Language/PureScript/Optimizer/Inliner.hs view
@@ -18,7 +18,8 @@ inlineOperator, inlineCommonOperators, etaConvert,- unThunk+ unThunk,+ evaluateIifes ) where import Data.Generics@@ -55,6 +56,13 @@ where convert :: JS -> JS convert (JSBlock [JSReturn (JSApp (JSFunction Nothing [] (JSBlock body)) [])]) = JSBlock body+ convert js = js++evaluateIifes :: JS -> JS+evaluateIifes = everywhere (mkT convert)+ where+ convert :: JS -> JS+ convert (JSApp (JSFunction Nothing [] (JSBlock [JSReturn ret])) []) = ret convert js = js inlineVariables :: JS -> JS
src/Language/PureScript/Optimizer/Unused.hs view
@@ -14,7 +14,8 @@ ----------------------------------------------------------------------------- module Language.PureScript.Optimizer.Unused (- removeUnusedVariables+ removeUnusedVariables,+ removeCodeAfterReturnStatements ) where import Data.Generics@@ -29,3 +30,12 @@ go [] = [] go (JSVariableIntroduction var _ : sts) | not (isUsed var sts) = go sts go (s:sts) = s : go sts++removeCodeAfterReturnStatements :: JS -> JS+removeCodeAfterReturnStatements = everywhere (mkT $ removeFromBlock go)+ where+ go :: [JS] -> [JS]+ go jss | not (any isJSReturn jss) = jss+ | otherwise = let (body, ret : _) = span (not . isJSReturn) jss in body ++ [ret]+ isJSReturn (JSReturn _) = True+ isJSReturn _ = False
src/Language/PureScript/Parser/Declarations.hs view
@@ -44,7 +44,7 @@ sourcePos :: P.Parsec s u SourcePos sourcePos = toSourcePos <$> P.getPosition where- toSourcePos p = SourcePos (P.sourceLine p) (P.sourceColumn p)+ toSourcePos p = SourcePos (P.sourceName p) (P.sourceLine p) (P.sourceColumn p) parseDataDeclaration :: P.Parsec String ParseState Declaration parseDataDeclaration = do
src/Language/PureScript/Sugar.hs view
@@ -18,6 +18,7 @@ import Control.Monad import Language.PureScript.Declarations+import Language.PureScript.Errors import Language.PureScript.Sugar.Operators as S import Language.PureScript.Sugar.DoNotation as S@@ -46,7 +47,7 @@ -- -- * Qualify any unqualified names and types ---desugar :: [Module] -> Either String [Module]+desugar :: [Module] -> Either ErrorStack [Module] desugar = removeSignedLiterals >>> desugarDo >=> desugarCasesModule
src/Language/PureScript/Sugar/BindingGroups.hs view
@@ -33,11 +33,12 @@ import Language.PureScript.Names import Language.PureScript.Types import Language.PureScript.Environment+import Language.PureScript.Errors -- | -- Replace all sets of mutually-recursive declarations in a module with binding groups ---createBindingGroupsModule :: [Module] -> Either String [Module]+createBindingGroupsModule :: [Module] -> Either ErrorStack [Module] createBindingGroupsModule = mapM $ \(Module name ds exps) -> Module name <$> createBindingGroups name ds <*> pure exps -- |@@ -49,7 +50,7 @@ -- | -- Replace all sets of mutually-recursive declarations with binding groups ---createBindingGroups :: ModuleName -> [Declaration] -> Either String [Declaration]+createBindingGroups :: ModuleName -> [Declaration] -> Either ErrorStack [Declaration] createBindingGroups moduleName ds = do values <- mapM (createBindingGroupsForValue moduleName) $ filter isValueDecl ds let dataDecls = filter isDataDecl ds@@ -68,7 +69,7 @@ filter isExternDecl ds ++ bindingGroupDecls -createBindingGroupsForValue :: ModuleName -> Declaration -> Either String Declaration+createBindingGroupsForValue :: ModuleName -> Declaration -> Either ErrorStack Declaration createBindingGroupsForValue moduleName = everywhereM' (mkM go) where go (Let ds val) = Let <$> createBindingGroups moduleName ds <*> pure val@@ -124,13 +125,13 @@ toBindingGroup (CyclicSCC [d]) = d toBindingGroup (CyclicSCC ds') = BindingGroupDeclaration $ map fromValueDecl ds' -toDataBindingGroup :: SCC Declaration -> Either String Declaration+toDataBindingGroup :: SCC Declaration -> Either ErrorStack Declaration toDataBindingGroup (AcyclicSCC d) = return d toDataBindingGroup (CyclicSCC [d]) = case isTypeSynonym d of- Just pn -> Left $ "Cycle in type synonym " ++ show pn+ Just pn -> Left $ mkErrorStack ("Cycle in type synonym " ++ show pn) Nothing _ -> return d toDataBindingGroup (CyclicSCC ds')- | all (isJust . isTypeSynonym) ds' = Left "Cycle in type synonyms"+ | all (isJust . isTypeSynonym) ds' = Left $ mkErrorStack "Cycle in type synonyms" Nothing | otherwise = return $ DataBindingGroupDeclaration ds' isTypeSynonym :: Declaration -> Maybe ProperName
src/Language/PureScript/Sugar/CaseDeclarations.hs view
@@ -19,6 +19,7 @@ desugarCasesModule ) where +import Data.Monoid ((<>)) import Data.List (groupBy) import Data.Generics (mkM, mkT, everywhere) import Data.Generics.Extras@@ -31,12 +32,15 @@ import Language.PureScript.Declarations import Language.PureScript.Scope import Language.PureScript.Environment+import Language.PureScript.Errors -- | -- Replace all top-level binders in a module with case expressions. ---desugarCasesModule :: [Module] -> Either String [Module]-desugarCasesModule ms = forM ms $ \(Module name ds exps) -> Module name <$> (desugarCases . desugarAbs $ ds) <*> pure exps+desugarCasesModule :: [Module] -> Either ErrorStack [Module]+desugarCasesModule ms = forM ms $ \(Module name ds exps) ->+ rethrow (strMsg ("Error in module " ++ show name) <>) $+ Module name <$> (desugarCases . desugarAbs $ ds) <*> pure exps desugarAbs :: [Declaration] -> [Declaration] desugarAbs = everywhere (mkT replace)@@ -51,10 +55,10 @@ -- | -- Replace all top-level binders with case expressions. ---desugarCases :: [Declaration] -> Either String [Declaration]+desugarCases :: [Declaration] -> Either ErrorStack [Declaration] desugarCases = desugarRest <=< fmap join . mapM toDecls . groupBy inSameGroup where- desugarRest :: [Declaration] -> Either String [Declaration]+ desugarRest :: [Declaration] -> Either ErrorStack [Declaration] desugarRest (TypeInstanceDeclaration name constraints className tys ds : rest) = (:) <$> (TypeInstanceDeclaration name constraints className tys <$> desugarCases ds) <*> desugarRest rest desugarRest (ValueDeclaration name nameKind bs g val : rest) = do@@ -74,7 +78,7 @@ inSameGroup d1 (PositionedDeclaration _ d2) = inSameGroup d1 d2 inSameGroup _ _ = False -toDecls :: [Declaration] -> Either String [Declaration]+toDecls :: [Declaration] -> Either ErrorStack [Declaration] toDecls [ValueDeclaration ident nameKind bs Nothing val] | all isVarBinder bs = do let args = map (\(VarBinder arg) -> arg) bs body = foldr (Abs . Left) val args@@ -82,10 +86,10 @@ toDecls ds@(ValueDeclaration ident _ bs _ _ : _) = do let tuples = map toTuple ds unless (all ((== length bs) . length . fst) tuples) $- throwError $ "Argument list lengths differ in declaration " ++ show ident+ throwError $ mkErrorStack ("Argument list lengths differ in declaration " ++ show ident) Nothing return [makeCaseDeclaration ident tuples] toDecls (PositionedDeclaration pos d : ds) = do- (d' : ds') <- toDecls (d : ds)+ (d' : ds') <- rethrowWithPosition pos $ toDecls (d : ds) return (PositionedDeclaration pos d' : ds') toDecls ds = return ds
src/Language/PureScript/Sugar/DoNotation.hs view
@@ -24,6 +24,7 @@ import Language.PureScript.Names import Language.PureScript.Scope import Language.PureScript.Declarations+import Language.PureScript.Errors import qualified Language.PureScript.Constants as C @@ -33,23 +34,23 @@ -- Replace all @DoNotationBind@ and @DoNotationValue@ constructors with applications of the Prelude.(>>=) function, -- and all @DoNotationLet@ constructors with let expressions. ---desugarDo :: (Data d) => d -> Either String d+desugarDo :: (Data d) => d -> Either ErrorStack d desugarDo = everywhereM (mkM replace) where prelude :: ModuleName prelude = ModuleName [ProperName C.prelude] bind :: Value bind = Var (Qualified (Just prelude) (Op (C.>>=)))- replace :: Value -> Either String Value+ replace :: Value -> Either ErrorStack Value replace (Do els) = go els replace other = return other- go :: [DoNotationElement] -> Either String Value+ go :: [DoNotationElement] -> Either ErrorStack Value go [] = error "The impossible happened in desugarDo" go [DoNotationValue val] = return val go (DoNotationValue val : rest) = do rest' <- go rest return $ App (App bind val) (Abs (Left (Ident "_")) rest')- go [DoNotationBind _ _] = Left "Bind statement cannot be the last statement in a do block"+ go [DoNotationBind _ _] = Left $ mkErrorStack "Bind statement cannot be the last statement in a do block" Nothing go (DoNotationBind NullBinder val : rest) = go (DoNotationValue val : rest) go (DoNotationBind (VarBinder ident) val : rest) = do rest' <- go rest@@ -58,7 +59,7 @@ rest' <- go rest let ident = head $ unusedNames rest' return $ App (App bind val) (Abs (Left ident) (Case [Var (Qualified Nothing ident)] [CaseAlternative [binder] Nothing rest']))- go [DoNotationLet _ _] = Left "Let statement cannot be the last statement in a do block"+ go [DoNotationLet _ _] = Left $ mkErrorStack "Let statement cannot be the last statement in a do block" Nothing go (DoNotationLet binder val : rest) = do rest' <- go rest return $ Case [val] [CaseAlternative [binder] Nothing rest']
src/Language/PureScript/Sugar/Names.hs view
@@ -18,6 +18,7 @@ import Data.Data import Data.Maybe (fromMaybe, isJust, mapMaybe)+import Data.Monoid ((<>)) import Data.Generics (extM, mkM, everywhereM) import Data.Generics.Extras (mkS, extS, everywhereWithContextM') @@ -30,6 +31,7 @@ import Language.PureScript.Names import Language.PureScript.Types import Language.PureScript.Environment+import Language.PureScript.Errors -- | -- The global export environment - every declaration exported from every module.@@ -80,7 +82,7 @@ -- Updates the exports for a module from the global environment. If the module was not previously -- present in the global environment, it is created. ---updateExportedModule :: ExportEnvironment -> ModuleName -> (Exports -> Either String Exports) -> Either String ExportEnvironment+updateExportedModule :: ExportEnvironment -> ModuleName -> (Exports -> Either ErrorStack Exports) -> Either ErrorStack ExportEnvironment updateExportedModule env mn update = do let exports = fromMaybe (error "Module was undefined in updateExportedModule") $ mn `M.lookup` env exports' <- update exports@@ -89,16 +91,16 @@ -- | -- Adds an empty module to an ExportEnvironment. ---addEmptyModule :: ExportEnvironment -> ModuleName -> Either String ExportEnvironment+addEmptyModule :: ExportEnvironment -> ModuleName -> Either ErrorStack ExportEnvironment addEmptyModule env name = if name `M.member` env- then throwError $ "Module '" ++ show name ++ "' has been defined more than once"+ then throwError $ mkErrorStack ("Module '" ++ show name ++ "' has been defined more than once") Nothing else return $ M.insert name (Exports [] [] []) env -- | -- Adds a type belonging to a module to the export environment. ---addType :: ExportEnvironment -> ModuleName -> ProperName -> [ProperName] -> Either String ExportEnvironment+addType :: ExportEnvironment -> ModuleName -> ProperName -> [ProperName] -> Either ErrorStack ExportEnvironment addType env mn name dctors = updateExportedModule env mn $ \m -> do types' <- addExport (exportedTypes m) (name, dctors) return $ m { exportedTypes = types' }@@ -106,7 +108,7 @@ -- | -- Adds a class to the export environment. ---addTypeClass :: ExportEnvironment -> ModuleName -> ProperName -> Either String ExportEnvironment+addTypeClass :: ExportEnvironment -> ModuleName -> ProperName -> Either ErrorStack ExportEnvironment addTypeClass env mn name = updateExportedModule env mn $ \m -> do classes <- addExport (exportedTypeClasses m) name return $ m { exportedTypeClasses = classes }@@ -114,7 +116,7 @@ -- | -- Adds a class to the export environment. ---addValue :: ExportEnvironment -> ModuleName -> Ident -> Either String ExportEnvironment+addValue :: ExportEnvironment -> ModuleName -> Ident -> Either ErrorStack ExportEnvironment addValue env mn name = updateExportedModule env mn $ \m -> do values <- addExport (exportedValues m) name return $ m { exportedValues = values }@@ -123,16 +125,16 @@ -- Adds an entry to a list of exports unless it is already present, in which case an error is -- returned. ---addExport :: (Eq a, Show a) => [a] -> a -> Either String [a]+addExport :: (Eq a, Show a) => [a] -> a -> Either ErrorStack [a] addExport exports name = if name `elem` exports- then throwError $ "Multiple definitions for '" ++ show name ++ "'"+ then throwError $ mkErrorStack ("Multiple definitions for '" ++ show name ++ "'") Nothing else return $ name : exports -- | -- Replaces all local names with qualified names within a set of modules. ---desugarImports :: [Module] -> Either String [Module]+desugarImports :: [Module] -> Either ErrorStack [Module] desugarImports modules = do unfilteredExports <- findExports modules exports <- foldM filterModuleExports unfilteredExports modules@@ -142,30 +144,19 @@ -- Filters the exports for a module in the global exports environment so that only explicitly -- exported members remain. If the module does not explicitly export anything, everything is -- exported.- filterModuleExports :: ExportEnvironment -> Module -> Either String ExportEnvironment+ filterModuleExports :: ExportEnvironment -> Module -> Either ErrorStack ExportEnvironment filterModuleExports env (Module mn _ (Just exps)) = filterExports mn exps env filterModuleExports env _ = return env -- Rename and check all the names within a module. We tweak the global exports environment so -- the module has access to an unfiltered list of its own members.- renameInModule' :: ExportEnvironment -> ExportEnvironment -> Module -> Either String Module- renameInModule' unfilteredExports exports m@(Module mn _ _) = rethrowForModule m $ do- let env = M.update (\_ -> M.lookup mn unfilteredExports) mn exports- let exps = fromMaybe (error "Module is missing in renameInModule'") $ M.lookup mn exports- imports <- resolveImports env m- renameInModule imports env (elaborateExports exps m)---- |--- Rethrow an error with an extra message line prepended----rethrow :: String -> Either String a -> Either String a-rethrow msg = flip catchError $ \e -> throwError (msg ++ ":\n" ++ e)---- |--- Rethrow an error with details of the current module prepended to the message----rethrowForModule :: Module -> Either String a -> Either String a-rethrowForModule (Module mn _ _) = rethrow $ "Error in module '" ++ show mn ++ "'"+ renameInModule' :: ExportEnvironment -> ExportEnvironment -> Module -> Either ErrorStack Module+ renameInModule' unfilteredExports exports m@(Module mn _ _) =+ rethrow (strMsg ("Error in module " ++ show mn) <>) $ do+ let env = M.update (\_ -> M.lookup mn unfilteredExports) mn exports+ let exps = fromMaybe (error "Module is missing in renameInModule'") $ M.lookup mn exports+ imports <- resolveImports env m+ renameInModule imports env (elaborateExports exps m) -- | -- Make all exports for a module explicit. This may still effect modules that have an exports list,@@ -181,23 +172,27 @@ -- Replaces all local names with qualified names within a module and checks that all existing -- qualified names are valid. ---renameInModule :: ImportEnvironment -> ExportEnvironment -> Module -> Either String Module+renameInModule :: ImportEnvironment -> ExportEnvironment -> Module -> Either ErrorStack Module renameInModule imports exports (Module mn decls exps) = Module mn <$> mapM go decls <*> pure exps where+ go :: Declaration -> Either ErrorStack Declaration go (DataDeclaration name args dctors) =- rethrowFor "data declaration" name $ DataDeclaration <$> pure name <*> pure args <*> updateAll dctors+ rethrow (strMsg ("Error in data declaration " ++ show name) <>) $+ DataDeclaration <$> pure name <*> pure args <*> updateAll dctors go (DataBindingGroupDeclaration decls') = DataBindingGroupDeclaration <$> mapM go decls' go (TypeSynonymDeclaration name ps ty) =- rethrowFor "type synonym" name $ TypeSynonymDeclaration <$> pure name <*> pure ps <*> updateType' ty+ rethrow (strMsg ("Error in type synonym " ++ show name) <>) $+ TypeSynonymDeclaration <$> pure name <*> pure ps <*> updateType' ty go (TypeInstanceDeclaration name cs cn ts ds) = TypeInstanceDeclaration name <$> updateConstraints cs <*> updateClassName cn <*> updateType' ts <*> mapM go ds go (ExternInstanceDeclaration name cs cn ts) = ExternInstanceDeclaration name <$> updateConstraints cs <*> updateClassName cn <*> updateType' ts go (ValueDeclaration name nameKind [] Nothing val) = do val' <- everywhereWithContextM' [] (mkS bindFunctionArgs `extS` bindBinders) val- rethrowFor "declaration" name $ ValueDeclaration name nameKind [] Nothing <$> updateAll val'+ rethrow (strMsg ("Error in declaration " ++ show name) <>) $+ ValueDeclaration name nameKind [] Nothing <$> updateAll val' where bindFunctionArgs bound (Abs (Left arg) val') = return (arg : bound, Abs (Left arg) val') bindFunctionArgs bound (Let ds val') = let args = mapMaybe letBoundVariable ds in@@ -211,7 +206,7 @@ bindFunctionArgs bound (BinaryNoParens name'@(Qualified (Just _) _) v1 v2) = (,) bound <$> (BinaryNoParens <$> updateValueName name' <*> pure v1 <*> pure v2) bindFunctionArgs bound other = return (bound, other)- bindBinders :: [Ident] -> CaseAlternative -> Either String ([Ident], CaseAlternative)+ bindBinders :: [Ident] -> CaseAlternative -> Either ErrorStack ([Ident], CaseAlternative) bindBinders bound c@(CaseAlternative bs _ _) = return (binderNames bs ++ bound, c) letBoundVariable :: Declaration -> Maybe Ident@@ -220,17 +215,18 @@ letBoundVariable _ = Nothing go (ValueDeclaration name _ _ _ _) = error $ "Binders should have been desugared in " ++ show name go (ExternDeclaration fit name js ty) =- rethrowFor "declaration" name $ ExternDeclaration <$> pure fit <*> pure name <*> pure js <*> updateType' ty+ rethrow (strMsg ("Error in declaration " ++ show name) <>) $+ ExternDeclaration <$> pure fit <*> pure name <*> pure js <*> updateType' ty go (BindingGroupDeclaration decls') = do BindingGroupDeclaration <$> mapM go' decls'- where go' = \(name, nk, value) -> rethrowFor "declaration" name $ (,,) <$> pure name <*> pure nk <*> updateAll value+ where+ go' = \(name, nk, value) ->+ rethrow (strMsg ("Error in declaration " ++ show name) <>) $+ (,,) <$> pure name <*> pure nk <*> updateAll value go (PositionedDeclaration pos d) = PositionedDeclaration pos <$> go d go d = updateAll d - rethrowFor :: (Show a) => String -> a -> Either String b -> Either String b- rethrowFor what name = rethrow $ "Error in " ++ what ++ " '" ++ show name ++ "'"-- updateAll :: Data d => d -> Either String d+ updateAll :: Data d => d -> Either ErrorStack d updateAll = everywhereM (mkM updateType `extM` updateValue `extM` updateBinder) updateValue (Constructor name) = Constructor <$> updateDataConstructorName name@@ -243,7 +239,7 @@ updateType (SaturatedTypeSynonym name tys) = SaturatedTypeSynonym <$> updateTypeName name <*> mapM updateType tys updateType (ConstrainedType cs t) = ConstrainedType <$> updateConstraints cs <*> pure t updateType t = return t- updateType' :: Data d => d -> Either String d+ updateType' :: Data d => d -> Either ErrorStack d updateType' = everywhereM (mkM updateType) updateConstraints = mapM (\(name, ts) -> (,) <$> updateClassName name <*> pure ts)@@ -259,24 +255,24 @@ -> (ImportEnvironment -> M.Map (Qualified a) (Qualified a)) -> (Exports -> a -> Bool) -> (Qualified a)- -> Either String (Qualified a)+ -> Either ErrorStack (Qualified a) update t getI checkE qname@(Qualified mn' name) = case (M.lookup qname (getI imports), mn') of (Just qname', _) -> return qname' (Nothing, Just mn'') -> do modExports <- getExports mn'' if checkE modExports name then return qname- else throwError $ "Unknown " ++ t ++ " '" ++ show (qname) ++ "'"- _ -> throwError $ "Unknown " ++ t ++ " '" ++ show name ++ "'"+ else throwError $ mkErrorStack ("Unknown " ++ t ++ " '" ++ show (qname) ++ "'") Nothing+ _ -> throwError $ mkErrorStack ("Unknown " ++ t ++ " '" ++ show name ++ "'") Nothing -- Gets the exports for a module, or an error message if the module doesn't exist- getExports :: ModuleName -> Either String Exports- getExports mn' = maybe (throwError $ "Unknown module '" ++ show mn' ++ "'") return $ M.lookup mn' exports+ getExports :: ModuleName -> Either ErrorStack Exports+ getExports mn' = maybe (throwError $ mkErrorStack ("Unknown module '" ++ show mn' ++ "'") Nothing) return $ M.lookup mn' exports -- | -- Finds all exported declarations in a set of modules. ---findExports :: [Module] -> Either String ExportEnvironment+findExports :: [Module] -> Either ErrorStack ExportEnvironment findExports = foldM addModule $ M.singleton (ModuleName [ProperName "Prim"]) primExports where @@ -286,13 +282,13 @@ mkTypeEntry (Qualified _ name) = (name, []) -- Add all of the exported declarations from a module to the global export environment- addModule :: ExportEnvironment -> Module -> Either String ExportEnvironment+ addModule :: ExportEnvironment -> Module -> Either ErrorStack ExportEnvironment addModule env m@(Module mn ds _) = do env' <- addEmptyModule env mn- rethrowForModule m $ foldM (addDecl mn) env' ds+ rethrow (strMsg ("Error in module " ++ show mn) <>) $ foldM (addDecl mn) env' ds -- Add a declaration from a module to the global export environment- addDecl :: ModuleName -> ExportEnvironment -> Declaration -> Either String ExportEnvironment+ addDecl :: ModuleName -> ExportEnvironment -> Declaration -> Either ErrorStack ExportEnvironment addDecl mn env (TypeClassDeclaration tcn _ ds) = do env' <- addTypeClass env mn tcn foldM (\env'' (TypeDeclaration name _) -> addValue env'' mn name) env' ds@@ -308,7 +304,7 @@ -- Filters the exports for a module to ensure only explicit exports are kept in the global exports -- environment. ---filterExports :: ModuleName -> [DeclarationRef] -> ExportEnvironment -> Either String ExportEnvironment+filterExports :: ModuleName -> [DeclarationRef] -> ExportEnvironment -> Either ErrorStack ExportEnvironment filterExports mn exps env = do let moduleExports = fromMaybe (error "Module is missing") (mn `M.lookup` env) moduleExports' <- filterModule moduleExports@@ -316,7 +312,7 @@ where -- Filter the exports for the specific module- filterModule :: Exports -> Either String Exports+ filterModule :: Exports -> Either ErrorStack Exports filterModule exported = do types' <- foldM (filterTypes $ exportedTypes exported) [] exps values <- foldM (filterValues $ exportedValues exported) [] exps@@ -325,34 +321,34 @@ -- Ensure the exported types and data constructors exist in the module and add them to the set of -- exports- filterTypes :: [(ProperName, [ProperName])] -> [(ProperName, [ProperName])] -> DeclarationRef -> Either String [(ProperName, [ProperName])]+ filterTypes :: [(ProperName, [ProperName])] -> [(ProperName, [ProperName])] -> DeclarationRef -> Either ErrorStack [(ProperName, [ProperName])] filterTypes expTys result (TypeRef name expDcons) = do- dcons <- maybe (throwError $ "Cannot export undefined type '" ++ show name ++ "'") return $ name `lookup` expTys+ dcons <- maybe (throwError $ mkErrorStack ("Cannot export undefined type '" ++ show name ++ "'") Nothing) return $ name `lookup` expTys dcons' <- maybe (return dcons) (foldM (filterDcons name dcons) []) expDcons return $ (name, dcons') : result filterTypes _ result _ = return result -- Ensure the exported data constructors exists for a type and add them to the list of exports- filterDcons :: ProperName -> [ProperName] -> [ProperName] -> ProperName -> Either String [ProperName]+ filterDcons :: ProperName -> [ProperName] -> [ProperName] -> ProperName -> Either ErrorStack [ProperName] filterDcons tcon exps' result name = if name `elem` exps' then return $ name : result- else throwError $ "Cannot export undefined data constructor '" ++ show name ++ "' for type '" ++ show tcon ++ "'"+ else throwError $ mkErrorStack ("Cannot export undefined data constructor '" ++ show name ++ "' for type '" ++ show tcon ++ "'") Nothing -- Ensure the exported classes exist in the module and add them to the set of exports- filterClasses :: [ProperName] -> [ProperName] -> DeclarationRef -> Either String [ProperName]+ filterClasses :: [ProperName] -> [ProperName] -> DeclarationRef -> Either ErrorStack [ProperName] filterClasses exps' result (TypeClassRef name) = if name `elem` exps' then return $ name : result- else throwError $ "Cannot export undefined type class '" ++ show name ++ "'"+ else throwError $ mkErrorStack ("Cannot export undefined type class '" ++ show name ++ "'") Nothing filterClasses _ result _ = return result -- Ensure the exported values exist in the module and add them to the set of exports- filterValues :: [Ident] -> [Ident] -> DeclarationRef -> Either String [Ident]+ filterValues :: [Ident] -> [Ident] -> DeclarationRef -> Either ErrorStack [Ident] filterValues exps' result (ValueRef name) = if name `elem` exps' then return $ name : result- else throwError $ "Cannot export undefined value '" ++ show name ++ "'"+ else throwError $ mkErrorStack ("Cannot export undefined value '" ++ show name ++ "'") Nothing filterValues _ result _ = return result -- |@@ -374,7 +370,7 @@ -- | -- Constructs a local environment for a module. ---resolveImports :: ExportEnvironment -> Module -> Either String ImportEnvironment+resolveImports :: ExportEnvironment -> Module -> Either ErrorStack ImportEnvironment resolveImports env (Module currentModule decls _) = foldM resolveImport' (ImportEnvironment M.empty M.empty M.empty M.empty) (M.toList scope) where@@ -382,25 +378,25 @@ scope :: M.Map ModuleName (Maybe ExplicitImports, Maybe ModuleName) scope = M.insert currentModule (Nothing, Nothing) (findImports decls) resolveImport' imp (mn, (explImports, impQual)) = do- modExports <- maybe (throwError $ "Cannot import unknown module '" ++ show mn ++ "'") return $ mn `M.lookup` env+ modExports <- maybe (throwError $ mkErrorStack ("Cannot import unknown module '" ++ show mn ++ "'") Nothing) return $ mn `M.lookup` env resolveImport currentModule mn modExports imp impQual explImports -- | -- Extends the local environment for a module by resolving an import of another module. ---resolveImport :: ModuleName -> ModuleName -> Exports -> ImportEnvironment -> Maybe ModuleName -> Maybe ExplicitImports-> Either String ImportEnvironment+resolveImport :: ModuleName -> ModuleName -> Exports -> ImportEnvironment -> Maybe ModuleName -> Maybe ExplicitImports-> Either ErrorStack ImportEnvironment resolveImport currentModule importModule exps imps impQual = maybe importAll (foldM importExplicit imps) where -- Import everything from a module- importAll :: Either String ImportEnvironment+ importAll :: Either ErrorStack ImportEnvironment importAll = do imp' <- foldM (\m (name, dctors) -> importExplicit m (TypeRef name (Just dctors))) imps (exportedTypes exps) imp'' <- foldM (\m name -> importExplicit m (ValueRef name)) imp' (exportedValues exps) foldM (\m name -> importExplicit m (TypeClassRef name)) imp'' (exportedTypeClasses exps) -- Import something explicitly- importExplicit :: ImportEnvironment -> DeclarationRef -> Either String ImportEnvironment+ importExplicit :: ImportEnvironment -> DeclarationRef -> Either ErrorStack ImportEnvironment importExplicit imp (ValueRef name) = do _ <- checkImportExists "value" values name values' <- updateImports (importedValues imp) name@@ -423,14 +419,15 @@ allExportedDataConstructors name = fromMaybe [] $ name `lookup` exportedTypes exps -- Add something to the ImportEnvironment if it does not already exist there- updateImports :: (Ord a, Show a) => M.Map (Qualified a) (Qualified a) -> a -> Either String (M.Map (Qualified a) (Qualified a))+ updateImports :: (Ord a, Show a) => M.Map (Qualified a) (Qualified a) -> a -> Either ErrorStack (M.Map (Qualified a) (Qualified a)) updateImports m name = case M.lookup (Qualified impQual name) m of Nothing -> return $ M.insert (Qualified impQual name) (Qualified (Just importModule) name) m Just (Qualified Nothing _) -> error "Invalid state in updateImports"- Just x@(Qualified (Just mn) _) -> throwError $- if mn == currentModule || importModule == currentModule- then "Definition '" ++ show name ++ "' conflicts with import '" ++ show (Qualified (Just importModule) name) ++ "'"- else "Conflicting imports for '" ++ show name ++ "': '" ++ show x ++ "', '" ++ show (Qualified (Just importModule) name) ++ "'"+ Just x@(Qualified (Just mn) _) -> throwError $ mkErrorStack err Nothing+ where+ err = if mn == currentModule || importModule == currentModule+ then "Definition '" ++ show name ++ "' conflicts with import '" ++ show (Qualified (Just importModule) name) ++ "'"+ else "Conflicting imports for '" ++ show name ++ "': '" ++ show x ++ "', '" ++ show (Qualified (Just importModule) name) ++ "'" -- The available values, types, and classes in the module being imported values = exportedValues exps@@ -439,14 +436,14 @@ -- Ensure that an explicitly imported data constructor exists for the type it is being imported -- from- checkDctorExists :: [ProperName] -> ProperName -> Either String ProperName+ checkDctorExists :: [ProperName] -> ProperName -> Either ErrorStack ProperName checkDctorExists = checkImportExists "data constructor" -- Check that an explicitly imported item exists in the module it is being imported from- checkImportExists :: (Eq a, Show a) => String -> [a] -> a -> Either String a+ checkImportExists :: (Eq a, Show a) => String -> [a] -> a -> Either ErrorStack a checkImportExists t exports item = if item `elem` exports then return item- else throwError $ "Unable to find " ++ t ++ " '" ++ show (Qualified (Just importModule) item) ++ "'"+ else throwError $ mkErrorStack ("Unable to find " ++ t ++ " '" ++ show (Qualified (Just importModule) item) ++ "'") Nothing
src/Language/PureScript/Sugar/Operators.hs view
@@ -26,14 +26,16 @@ import Language.PureScript.Names import Language.PureScript.Declarations+import Language.PureScript.Errors import Control.Applicative import Control.Monad.State import Control.Monad.Error.Class +import Data.Monoid ((<>)) import Data.Function (on) import Data.Functor.Identity-import Data.List (sort, groupBy, sortBy)+import Data.List (groupBy, sortBy) import qualified Data.Data as D import qualified Data.Generics as G@@ -48,11 +50,11 @@ -- | -- Remove explicit parentheses and reorder binary operator applications ---rebracket :: [Module] -> Either String [Module]+rebracket :: [Module] -> Either ErrorStack [Module] rebracket ms = do let fixities = concatMap collectFixities ms- ensureNoDuplicates $ map fst fixities- let opTable = customOperatorTable fixities+ ensureNoDuplicates $ map (\(i, pos, _) -> (i, pos)) fixities+ let opTable = customOperatorTable $ map (\(i, _, f) -> (i, f)) fixities mapM (rebracketModule opTable) ms removeSignedLiterals :: (D.Data d) => d -> d@@ -63,7 +65,7 @@ go (UnaryMinus val) = App (Var (Qualified (Just (ModuleName [ProperName C.prelude])) (Ident C.negate))) val go other = other -rebracketModule :: [[(Qualified Ident, Value -> Value -> Value, Associativity)]] -> Module -> Either String Module+rebracketModule :: [[(Qualified Ident, Value -> Value -> Value, Associativity)]] -> Module -> Either ErrorStack Module rebracketModule opTable (Module mn ds exts) = Module mn <$> (removeParens <$> G.everywhereM' (G.mkM (matchOperators opTable)) ds) <*> pure exts removeParens :: (D.Data d) => d -> d@@ -72,20 +74,23 @@ go (Parens val) = val go val = val -collectFixities :: Module -> [(Qualified Ident, Fixity)]+collectFixities :: Module -> [(Qualified Ident, SourcePos, Fixity)] collectFixities (Module moduleName ds _) = concatMap collect ds where- collect :: Declaration -> [(Qualified Ident, Fixity)]- collect (PositionedDeclaration _ d) = collect d- collect (FixityDeclaration fixity name) = [(Qualified (Just moduleName) (Op name), fixity)]+ collect :: Declaration -> [(Qualified Ident, SourcePos, Fixity)]+ collect (PositionedDeclaration pos (FixityDeclaration fixity name)) = [(Qualified (Just moduleName) (Op name), pos, fixity)]+ collect FixityDeclaration{} = error "Fixity without srcpos info" collect _ = [] -ensureNoDuplicates :: [Qualified Ident] -> Either String ()-ensureNoDuplicates m = go $ sort m+ensureNoDuplicates :: [(Qualified Ident, SourcePos)] -> Either ErrorStack ()+ensureNoDuplicates m = go $ sortBy (compare `on` fst) m where go [] = return () go [_] = return ()- go (x : y : _) | x == y = throwError $ "Redefined fixity for " ++ show x+ go ((x@(Qualified (Just mn) name), _) : (y, pos) : _) | x == y =+ rethrow (strMsg ("Error in module " ++ show mn) <>) $+ rethrowWithPosition pos $+ throwError $ mkErrorStack ("Redefined fixity for " ++ show name) Nothing go (_ : rest) = go rest customOperatorTable :: [(Qualified Ident, Fixity)] -> [[(Qualified Ident, Value -> Value -> Value, Associativity)]]@@ -100,17 +105,17 @@ type Chain = [Either Value (Qualified Ident)] -matchOperators :: [[(Qualified Ident, Value -> Value -> Value, Associativity)]] -> Value -> Either String Value+matchOperators :: [[(Qualified Ident, Value -> Value -> Value, Associativity)]] -> Value -> Either ErrorStack Value matchOperators ops = parseChains where- parseChains :: Value -> Either String Value+ parseChains :: Value -> Either ErrorStack Value parseChains b@BinaryNoParens{} = bracketChain (extendChain b) parseChains other = return other extendChain :: Value -> Chain extendChain (BinaryNoParens name l r) = Left l : Right name : extendChain r extendChain other = [Left other]- bracketChain :: Chain -> Either String Value- bracketChain = either (Left . show) Right . P.parse (P.buildExpressionParser opTable parseValue <* P.eof) "operator expression"+ bracketChain :: Chain -> Either ErrorStack Value+ bracketChain = either (Left . (`mkErrorStack` Nothing) . show) Right . P.parse (P.buildExpressionParser opTable parseValue <* P.eof) "operator expression" opTable = [P.Infix (P.try (parseTicks >>= \ident -> return (\t1 t2 -> App (App (Var ident) t1) t2))) P.AssocLeft] : map (map (\(name, f, a) -> P.Infix (P.try (matchOp name) >> return f) (toAssoc a))) ops ++ [[ P.Infix (P.try (parseOp >>= \ident -> return (\t1 t2 -> App (App (Var ident) t1) t2))) P.AssocLeft ]]
src/Language/PureScript/Sugar/TypeClasses.hs view
@@ -25,6 +25,7 @@ import Language.PureScript.CodeGen.JS.AST import Language.PureScript.Sugar.CaseDeclarations import Language.PureScript.Environment+import Language.PureScript.Errors import Language.PureScript.CodeGen.Common (identToJs) import Control.Applicative@@ -36,13 +37,13 @@ type MemberMap = M.Map (ModuleName, ProperName) ([String], [(String, Type)]) -type Desugar = StateT MemberMap (Either String)+type Desugar = StateT MemberMap (Either ErrorStack) -- | -- Add type synonym declarations for type class dictionary types, and value declarations for type class -- instance dictionary expressions. ---desugarTypeClasses :: [Module] -> Either String [Module]+desugarTypeClasses :: [Module] -> Either ErrorStack [Module] desugarTypeClasses = flip evalStateT M.empty . mapM desugarModule desugarModule :: Module -> Desugar Module@@ -125,7 +126,7 @@ typeInstanceDictionaryDeclaration :: Ident -> ModuleName -> [(Qualified ProperName, [Type])] -> Qualified ProperName -> [Type] -> [Declaration] -> Desugar Declaration typeInstanceDictionaryDeclaration name mn deps className tys decls = do m <- get- (args, instanceTys) <- lift $ maybe (Left $ "Type class " ++ show className ++ " is undefined. Type class names must be qualified.") Right+ (args, instanceTys) <- lift $ maybe (Left $ mkErrorStack ("Type class " ++ show className ++ " is undefined") Nothing) Right $ M.lookup (qualify mn className) m let memberTypes = map (second (replaceAllTypeVars (zip args tys))) instanceTys let entryName = Escaped (show name)@@ -144,7 +145,7 @@ memberToNameAndValue :: [(String, Type)] -> Declaration -> Desugar (String, Value) memberToNameAndValue tys' (ValueDeclaration ident _ _ _ _) = do- memberType <- lift . maybe (Left "Type class member type not found") Right $ lookup (identToJs ident) tys'+ memberType <- lift . maybe (Left $ mkErrorStack "Type class member type not found" Nothing) Right $ lookup (identToJs ident) tys' memberName <- mkDictionaryEntryName name ident return (identToJs ident, TypedValue False (foldl App (Var (Qualified Nothing memberName)) (map (\n -> Var (Qualified Nothing (Ident ('_' : show n)))) [1..length deps]))@@ -164,8 +165,8 @@ return $ ValueDeclaration entryName TypeInstanceMember [] Nothing (TypedValue True val (quantify (if null deps then valTy else ConstrainedType deps valTy))) where- lookupTypeClass m = maybe (Left $ "Type class " ++ show className ++ " is undefined. Type class names must be qualified.") Right $ M.lookup (qualify mn className) m- lookupIdent members = maybe (Left $ "Type class " ++ show className ++ " does not have method " ++ show ident) Right $ lookup (identToJs ident) members+ lookupTypeClass m = maybe (Left $ mkErrorStack ("Type class " ++ show className ++ " is undefined") Nothing) Right $ M.lookup (qualify mn className) m+ lookupIdent members = maybe (Left $ mkErrorStack ("Type class " ++ show className ++ " does not have method " ++ show ident) Nothing) Right $ lookup (identToJs ident) members typeInstanceDictionaryEntryDeclaration name mn deps className tys (PositionedDeclaration pos d) = PositionedDeclaration pos <$> typeInstanceDictionaryEntryDeclaration name mn deps className tys d typeInstanceDictionaryEntryDeclaration _ _ _ _ _ _ = error "Invalid declaration in type instance definition"
src/Language/PureScript/Sugar/TypeDeclarations.hs view
@@ -21,6 +21,7 @@ import Data.Generics (mkM) import Data.Generics.Extras+import Data.Monoid ((<>)) import Control.Applicative import Control.Monad.Error.Class@@ -29,30 +30,34 @@ import Language.PureScript.Declarations import Language.PureScript.Names import Language.PureScript.Environment+import Language.PureScript.Errors -- | -- Replace all top level type declarations in a module with type annotations ---desugarTypeDeclarationsModule :: [Module] -> Either String [Module]-desugarTypeDeclarationsModule ms = forM ms $ \(Module name ds exps) -> Module name <$> desugarTypeDeclarations ds <*> pure exps+desugarTypeDeclarationsModule :: [Module] -> Either ErrorStack [Module]+desugarTypeDeclarationsModule ms = forM ms $ \(Module name ds exps) ->+ rethrow (strMsg ("Error in module " ++ show name) <>) $+ Module name <$> desugarTypeDeclarations ds <*> pure exps -- | -- Replace all top level type declarations with type annotations ---desugarTypeDeclarations :: [Declaration] -> Either String [Declaration]+desugarTypeDeclarations :: [Declaration] -> Either ErrorStack [Declaration] desugarTypeDeclarations (PositionedDeclaration pos d : ds) = do- (d' : ds') <- desugarTypeDeclarations (d : ds)+ (d' : ds') <- rethrowWithPosition pos $ desugarTypeDeclarations (d : ds) return (PositionedDeclaration pos d' : ds') desugarTypeDeclarations (TypeDeclaration name ty : d : rest) = do (_, nameKind, val) <- fromValueDeclaration d desugarTypeDeclarations (ValueDeclaration name nameKind [] Nothing (TypedValue True val ty) : rest) where- fromValueDeclaration :: Declaration -> Either String (Ident, NameKind, Value)+ fromValueDeclaration :: Declaration -> Either ErrorStack (Ident, NameKind, Value) fromValueDeclaration (ValueDeclaration name' nameKind [] Nothing val) | name == name' = return (name', nameKind, val) fromValueDeclaration (PositionedDeclaration pos d') = do- (ident, nameKind, val) <- fromValueDeclaration d'+ (ident, nameKind, val) <- rethrowWithPosition pos $ fromValueDeclaration d' return (ident, nameKind, PositionedValue pos val)- fromValueDeclaration _ = throwError $ "Orphan type declaration for " ++ show name+ fromValueDeclaration _ = throwError $ mkErrorStack ("Orphan type declaration for " ++ show name) Nothing+desugarTypeDeclarations (TypeDeclaration name _ : []) = throwError $ mkErrorStack ("Orphan type declaration for " ++ show name) Nothing desugarTypeDeclarations (ValueDeclaration name nameKind bs g val : rest) = do (:) <$> (ValueDeclaration name nameKind bs g <$> everywhereM' (mkM go) val) <*> desugarTypeDeclarations rest where
src/Language/PureScript/TypeChecker.hs view
@@ -37,6 +37,7 @@ import Language.PureScript.Declarations import Language.PureScript.TypeClassDictionaries import Language.PureScript.Environment+import Language.PureScript.Errors addDataType :: ModuleName -> ProperName -> [String] -> [(ProperName, [Type])] -> Kind -> Check () addDataType moduleName name args dctors ctorKind = do@@ -88,7 +89,7 @@ when (ctor `M.member` typeSynonyms env) . throwError . strMsg $ "Type synonym instances are disallowed" return () checkTypeClassInstance m (TypeApp t1 t2) = checkTypeClassInstance m t1 >> checkTypeClassInstance m t2-checkTypeClassInstance _ ty = throwError $ mkUnifyErrorStack "Type class instance head is invalid." (Just (TypeError ty))+checkTypeClassInstance _ ty = throwError $ mkErrorStack "Type class instance head is invalid." (Just (TypeError ty)) -- | -- Type check all declarations in a module
src/Language/PureScript/TypeChecker/Kinds.hs view
@@ -28,6 +28,7 @@ import Language.PureScript.TypeChecker.Monad import Language.PureScript.Pretty import Language.PureScript.Environment+import Language.PureScript.Errors import Control.Monad.State import Control.Monad.Error@@ -60,7 +61,7 @@ -- kindOf :: ModuleName -> Type -> Check Kind kindOf _ ty =- rethrow (mkUnifyErrorStack "Error checking kind" (Just (TypeError ty)) <>) $+ rethrow (mkErrorStack "Error checking kind" (Just (TypeError ty)) <>) $ fmap tidyUp . liftUnify $ starIfUnknown <$> infer ty where tidyUp (k, sub) = sub $? k@@ -129,7 +130,7 @@ -- Infer a kind for a type -- infer :: Type -> UnifyT Kind Check Kind-infer ty = rethrow (mkUnifyErrorStack "Error inferring type of value" (Just (TypeError ty)) <>) $ infer' ty+infer ty = rethrow (mkErrorStack "Error inferring type of value" (Just (TypeError ty)) <>) $ infer' ty infer' :: Type -> UnifyT Kind Check Kind infer' (TypeVar v) = do@@ -138,7 +139,7 @@ infer' c@(TypeConstructor v) = do env <- liftCheck getEnv case M.lookup v (types env) of- Nothing -> UnifyT . lift . throwError $ mkUnifyErrorStack "Unknown type constructor" (Just (TypeError c))+ Nothing -> UnifyT . lift . throwError $ mkErrorStack "Unknown type constructor" (Just (TypeError c)) Just (kind, _) -> return kind infer' (TypeApp t1 t2) = do k0 <- fresh
src/Language/PureScript/TypeChecker/Monad.hs view
@@ -21,14 +21,12 @@ import Language.PureScript.Types import Language.PureScript.Kinds import Language.PureScript.Names-import Language.PureScript.Declarations import Language.PureScript.Environment import Language.PureScript.TypeClassDictionaries-import Language.PureScript.Pretty import Language.PureScript.Options+import Language.PureScript.Errors import Data.Maybe-import Data.Monoid import Control.Applicative import Control.Monad.State@@ -36,80 +34,8 @@ import Control.Monad.Unify import qualified Data.Map as M-import Data.List (intercalate) -- |--- Type for sources of type checking errors----data UnifyErrorSource- -- |- -- An error which originated at a Value- --- = ValueError Value- -- |- -- An error which originated at a Type- --- | TypeError Type deriving (Show)---- |--- Unification errors----data UnifyError = UnifyError {- -- |- -- Error message- --- unifyErrorMessage :: String- -- |- -- The value where the error occurred- --- , unifyErrorValue :: Maybe UnifyErrorSource- -- |- -- Optional source position information- --- , unifyErrorPosition :: Maybe SourcePos- } deriving (Show)---- |--- A stack trace for an error----newtype UnifyErrorStack = UnifyErrorStack { runUnifyErrorStack :: [UnifyError] } deriving (Show, Monoid)--instance Error UnifyErrorStack where- strMsg s = UnifyErrorStack [UnifyError s Nothing Nothing]- noMsg = UnifyErrorStack []--prettyPrintUnifyErrorStack :: Options -> UnifyErrorStack -> String-prettyPrintUnifyErrorStack opts (UnifyErrorStack es) =- case mconcat $ map (Last . unifyErrorPosition) es of- Last (Just sourcePos) -> "Error at " ++ show sourcePos ++ ": \n" ++ prettyPrintUnifyErrorStack'- _ -> prettyPrintUnifyErrorStack'- where- prettyPrintUnifyErrorStack' :: String- prettyPrintUnifyErrorStack'- | optionsVerboseErrors opts =- intercalate "\n" (map showError (filter isErrorNonEmpty es))- | otherwise =- let- es' = filter isErrorNonEmpty es- in case length es' of- 1 -> showError (head es')- _ -> showError (head es') ++ "\n" ++ showError (last es')--isErrorNonEmpty :: UnifyError -> Bool-isErrorNonEmpty = not . null . unifyErrorMessage--showError :: UnifyError -> String-showError (UnifyError msg Nothing _) = msg-showError (UnifyError msg (Just (ValueError val)) _) = "Error in value " ++ prettyPrintValue val ++ "\n" ++ msg-showError (UnifyError msg (Just (TypeError ty)) _) = "Error in type " ++ prettyPrintType ty ++ "\n" ++ msg--mkUnifyErrorStack :: String -> Maybe UnifyErrorSource -> UnifyErrorStack-mkUnifyErrorStack msg t = UnifyErrorStack [UnifyError msg t Nothing]--positionError :: SourcePos -> UnifyErrorStack-positionError pos = UnifyErrorStack [UnifyError "" Nothing (Just pos)]---- | -- Temporarily bind a collection of names to values -- bindNames :: (MonadState CheckState m) => M.Map (ModuleName, Ident) (Type, NameKind) -> m a -> m a@@ -207,8 +133,8 @@ -- | -- The type checking monad, which provides the state of the type checker, and error reporting capabilities ---newtype Check a = Check { unCheck :: StateT CheckState (Either UnifyErrorStack) a }- deriving (Functor, Monad, Applicative, MonadPlus, MonadState CheckState, MonadError UnifyErrorStack)+newtype Check a = Check { unCheck :: StateT CheckState (Either ErrorStack) a }+ deriving (Functor, Monad, Applicative, MonadPlus, MonadState CheckState, MonadError ErrorStack) -- | -- Get the current @Environment@@@ -238,7 +164,7 @@ -- Run a computation in the Check monad, failing with an error, or succeeding with a return value and the final @Environment@. -- runCheck' :: Options -> Environment -> Check a -> Either String (a, Environment)-runCheck' opts env c = either (Left . prettyPrintUnifyErrorStack opts) Right $ do+runCheck' opts env c = stringifyErrorStack (optionsVerboseErrors opts) $ do (a, s) <- flip runStateT (CheckState env 0 0 Nothing) $ unCheck c return (a, checkEnv s) @@ -248,18 +174,6 @@ guardWith :: (MonadError e m) => e -> Bool -> m () guardWith _ True = return () guardWith e False = throwError e---- |--- Rethrow an error with a more detailed error message in the case of failure----rethrow :: (MonadError e m) => (e -> e) -> m a -> m a-rethrow f = flip catchError $ \e -> throwError (f e)---- |--- Rethrow an error with source position information----rethrowWithPosition :: (MonadError UnifyErrorStack m) => SourcePos -> m a -> m a-rethrowWithPosition pos = rethrow (positionError pos <>) -- | -- Generate new type class dictionary name
src/Language/PureScript/TypeChecker/Types.hs view
@@ -59,6 +59,7 @@ import Language.PureScript.TypeChecker.Synonyms import Language.PureScript.Pretty import Language.PureScript.Environment+import Language.PureScript.Errors import qualified Language.PureScript.Constants as C import Control.Monad.State@@ -85,7 +86,7 @@ -- Unify two types, updating the current substitution -- unifyTypes :: Type -> Type -> UnifyT Type Check ()-unifyTypes t1 t2 = rethrow (mkUnifyErrorStack ("Error unifying type " ++ prettyPrintType t1 ++ " with type " ++ prettyPrintType t2) Nothing <>) $+unifyTypes t1 t2 = rethrow (mkErrorStack ("Error unifying type " ++ prettyPrintType t1 ++ " with type " ++ prettyPrintType t2) Nothing <>) $ unifyTypes' t1 t2 where unifyTypes' (TUnknown u1) (TUnknown u2) | u1 == u2 = return ()@@ -364,7 +365,7 @@ -- an escaped skolem variable. case everythingWithContext [] (++) (mkQ ((,) []) go) root of [] -> return ()- ((binding, val) : _) -> throwError $ mkUnifyErrorStack ("Rigid/skolem type variable " ++ maybe "" (("bound by " ++) . prettyPrintValue) binding ++ " has escaped.") (Just (ValueError val))+ ((binding, val) : _) -> throwError $ mkErrorStack ("Rigid/skolem type variable " ++ maybe "" (("bound by " ++) . prettyPrintValue) binding ++ " has escaped.") (Just (ValueError val)) where go :: Value -> [(SkolemScope, Value)] -> ([(Maybe Value, Value)], [(SkolemScope, Value)]) go val@(TypedValue _ _ (ForAll _ _ (Just sco))) scos = ([], (sco, val) : scos)@@ -383,7 +384,7 @@ where go' val@(TypedValue _ _ (ForAll _ _ (Just sco'))) | sco == sco' = Just val go' _ = Nothing-skolemEscapeCheck val = throwError $ mkUnifyErrorStack "Untyped value passed to skolemEscapeCheck" (Just (ValueError val))+skolemEscapeCheck val = throwError $ mkErrorStack "Untyped value passed to skolemEscapeCheck" (Just (ValueError val)) -- | -- Ensure a row contains no duplicate labels@@ -492,7 +493,7 @@ -- Infer a type for a value, rethrowing any error to provide a more useful error message -- infer :: Value -> UnifyT Type Check Value-infer val = rethrow (mkUnifyErrorStack "Error inferring type of value" (Just (ValueError val)) <>) $ infer' val+infer val = rethrow (mkErrorStack "Error inferring type of value" (Just (ValueError val)) <>) $ infer' val -- | -- Infer a type for a value@@ -720,7 +721,7 @@ -- Check the type of a value, rethrowing errors to provide a better error message -- check :: Value -> Type -> UnifyT Type Check Value-check val ty = rethrow (mkUnifyErrorStack errorMessage (Just (ValueError val)) <>) $ check' val ty+check val ty = rethrow (mkErrorStack errorMessage (Just (ValueError val)) <>) $ check' val ty where errorMessage = "Error checking type of term " ++@@ -836,7 +837,7 @@ check val ty' check' (PositionedValue pos val) ty = rethrowWithPosition pos $ check val ty-check' val ty = throwError $ mkUnifyErrorStack ("Value does not have type " ++ prettyPrintType ty) (Just (ValueError val))+check' val ty = throwError $ mkErrorStack ("Value does not have type " ++ prettyPrintType ty) (Just (ValueError val)) containsTypeSynonyms :: Type -> Bool containsTypeSynonyms = everything (||) (mkQ False go) where@@ -855,8 +856,8 @@ return [] go [] [] (Skolem _ _) | lax = return [] go [] ((p, _): _) _ | lax = return []- | otherwise = throwError $ mkUnifyErrorStack ("Object does not have property " ++ p) (Just (ValueError (ObjectLiteral ps)))- go ((p,_):_) [] REmpty = throwError $ mkUnifyErrorStack ("Property " ++ p ++ " is not present in closed object type " ++ prettyPrintRow row) (Just (ValueError (ObjectLiteral ps)))+ | otherwise = throwError $ mkErrorStack ("Object does not have property " ++ p) (Just (ValueError (ObjectLiteral ps)))+ go ((p,_):_) [] REmpty = throwError $ mkErrorStack ("Property " ++ p ++ " is not present in closed object type " ++ prettyPrintRow row) (Just (ValueError (ObjectLiteral ps))) go ((p,v):ps') [] u@(TUnknown _) = do v'@(TypedValue _ _ ty) <- infer v rest <- fresh@@ -875,13 +876,13 @@ v' <- check v ty ps'' <- go ps' (delete (p, ty) ts) r return $ (p, v') : ps''- go _ _ _ = throwError $ mkUnifyErrorStack ("Object does not have type " ++ prettyPrintType (TypeApp tyObject row)) (Just (ValueError (ObjectLiteral ps)))+ go _ _ _ = throwError $ mkErrorStack ("Object does not have type " ++ prettyPrintType (TypeApp tyObject row)) (Just (ValueError (ObjectLiteral ps))) -- | -- Check the type of a function application, rethrowing errors to provide a better error message -- checkFunctionApplication :: Value -> Type -> Value -> Maybe Type -> UnifyT Type Check (Type, Value)-checkFunctionApplication fn fnTy arg ret = rethrow (mkUnifyErrorStack errorMessage (Just (ValueError fn)) <>) $ checkFunctionApplication' fn fnTy arg ret+checkFunctionApplication fn fnTy arg ret = rethrow (mkErrorStack errorMessage (Just (ValueError fn)) <>) $ checkFunctionApplication' fn fnTy arg ret where errorMessage = "Error applying function of type " ++ prettyPrintType fnTy@@ -923,7 +924,7 @@ -- Check whether one type subsumes another, rethrowing errors to provide a better error message -- subsumes :: Maybe Value -> Type -> Type -> UnifyT Type Check (Maybe Value)-subsumes val ty1 ty2 = rethrow (mkUnifyErrorStack errorMessage (ValueError <$> val) <>) $ subsumes' val ty1 ty2+subsumes val ty1 ty2 = rethrow (mkErrorStack errorMessage (ValueError <$> val) <>) $ subsumes' val ty1 ty2 where errorMessage = "Error checking that type " ++ prettyPrintType ty1