purescript 0.4.9 → 0.4.10
raw patch · 29 files changed
+568/−225 lines, 29 files
Files
- docgen/Main.hs +3/−0
- psc-make/Main.hs +5/−1
- psc/Main.hs +5/−1
- psci/Main.hs +1/−1
- purescript.cabal +1/−1
- src/Language/PureScript.hs +8/−6
- src/Language/PureScript/CodeGen/Externs.hs +1/−0
- src/Language/PureScript/CodeGen/JS.hs +3/−0
- src/Language/PureScript/DeadCodeElimination.hs +5/−0
- src/Language/PureScript/Declarations.hs +49/−4
- src/Language/PureScript/ModuleDependencies.hs +1/−0
- src/Language/PureScript/Options.hs +5/−1
- src/Language/PureScript/Parser/Common.hs +3/−8
- src/Language/PureScript/Parser/Declarations.hs +18/−6
- src/Language/PureScript/Pretty/Common.hs +38/−0
- src/Language/PureScript/Pretty/JS.hs +18/−27
- src/Language/PureScript/Pretty/Values.hs +139/−64
- src/Language/PureScript/Sugar.hs +4/−1
- src/Language/PureScript/Sugar/BindingGroups.hs +14/−7
- src/Language/PureScript/Sugar/CaseDeclarations.hs +9/−0
- src/Language/PureScript/Sugar/DoNotation.hs +3/−0
- src/Language/PureScript/Sugar/Names.hs +8/−4
- src/Language/PureScript/Sugar/Operators.hs +13/−1
- src/Language/PureScript/Sugar/TypeClasses.hs +11/−0
- src/Language/PureScript/Sugar/TypeDeclarations.hs +14/−2
- src/Language/PureScript/TypeChecker.hs +20/−14
- src/Language/PureScript/TypeChecker/Kinds.hs +19/−13
- src/Language/PureScript/TypeChecker/Monad.hs +97/−17
- src/Language/PureScript/TypeChecker/Types.hs +53/−46
docgen/Main.hs view
@@ -84,6 +84,7 @@ isExported :: Maybe [P.DeclarationRef] -> P.Declaration -> Bool isExported Nothing _ = True isExported _ (P.TypeInstanceDeclaration _ _ _ _ _) = True+isExported exps (P.PositionedDeclaration _ d) = isExported exps d isExported (Just exps) decl = any (matches decl) exps where matches (P.TypeDeclaration ident _) (P.ValueRef ident') = ident == ident'@@ -130,6 +131,8 @@ [] -> "" cs -> "(" ++ intercalate ", " (map (\(pn, tys') -> show pn ++ " " ++ unwords (map P.prettyPrintTypeAtom tys')) cs) ++ ") => " atIndent n $ "instance " ++ show name ++ " :: " ++ constraintsText ++ show className ++ " " ++ unwords (map P.prettyPrintTypeAtom tys)+renderDeclaration n exps (P.PositionedDeclaration _ d) =+ renderDeclaration n exps d renderDeclaration _ _ _ = return () getName :: P.Declaration -> String
psc-make/Main.hs view
@@ -115,8 +115,12 @@ browserNamespace = value $ opt "PS" $ (optInfo [ "browser-namespace" ]) { optDoc = "Specify the namespace that PureScript modules will be exported to when running in the browser." } +verboseErrors :: Term Bool+verboseErrors = value $ flag $ (optInfo [ "v", "verbose-errors" ])+ { optDoc = "Display verbose error messages" }+ options :: Term P.Options-options = P.Options <$> noPrelude <*> noTco <*> performRuntimeTypeChecks <*> noMagicDo <*> pure Nothing <*> noOpts <*> browserNamespace <*> pure [] <*> pure []+options = P.Options <$> noPrelude <*> noTco <*> performRuntimeTypeChecks <*> noMagicDo <*> pure Nothing <*> noOpts <*> browserNamespace <*> pure [] <*> pure [] <*> verboseErrors inputFilesAndPrelude :: FilePath -> Term [FilePath] inputFilesAndPrelude prelude = combine <$> (not <$> noPrelude) <*> inputFiles
psc/Main.hs view
@@ -122,8 +122,12 @@ codeGenModules = value $ optAll [] $ (optInfo [ "codegen" ]) { optDoc = "A list of modules for which Javascript and externs should be generated. This argument can be used multiple times." } +verboseErrors :: Term Bool+verboseErrors = value $ flag $ (optInfo [ "v", "verbose-errors" ])+ { optDoc = "Display verbose error messages" }+ options :: Term P.Options-options = P.Options <$> noPrelude <*> noTco <*> performRuntimeTypeChecks <*> noMagicDo <*> runMain <*> noOpts <*> browserNamespace <*> dceModules <*> codeGenModules+options = P.Options <$> noPrelude <*> noTco <*> performRuntimeTypeChecks <*> noMagicDo <*> runMain <*> noOpts <*> browserNamespace <*> dceModules <*> codeGenModules <*> verboseErrors stdInOrInputFiles :: FilePath -> Term (Maybe [FilePath]) stdInOrInputFiles prelude = combine <$> useStdIn <*> (not <$> noPrelude) <*> inputFiles
psci/Main.hs view
@@ -194,7 +194,7 @@ -- | Compilation options. -- options :: P.Options-options = P.Options False True False True (Just "Main") True "PS" [] []+options = P.Options False True False True (Just "Main") True "PS" [] [] False -- | -- Makes a volatile module to execute the current expression.
purescript.cabal view
@@ -1,5 +1,5 @@ name: purescript-version: 0.4.9+version: 0.4.10 cabal-version: >=1.8 build-type: Custom license: MIT
src/Language/PureScript.hs view
@@ -71,7 +71,7 @@ compile' env opts ms = do (sorted, _) <- sortModules $ if optionsNoPrelude opts then ms else (map importPrelude ms) desugared <- desugar sorted- (elaborated, env') <- runCheck' env $ forM desugared $ typeCheckModule mainModuleIdent+ (elaborated, env') <- runCheck' opts env $ forM desugared $ typeCheckModule mainModuleIdent regrouped <- createBindingGroupsModule . collapseBindingGroupsModule $ elaborated let entryPoints = moduleNameFromString `map` optionsModules opts let elim = if null entryPoints then regrouped else eliminateDeadCode entryPoints regrouped@@ -100,8 +100,9 @@ checkTypesAreExported (ValueRef name) = do ty <- lookupVariable mn (Qualified (Just mn) name) case find isTconHidden (findTcons ty) of- Just hiddenType -> throwError $ "Error in module '" ++ show mn ++ "':\n\- \Exporting declaration '" ++ show name ++ "' requires type '" ++ show hiddenType ++ "' to be exported as well"+ Just hiddenType -> throwError . strMsg $+ "Error in module '" ++ show mn ++ "':\n\+ \Exporting declaration '" ++ show name ++ "' requires type '" ++ show hiddenType ++ "' to be exported as well" Nothing -> return () checkTypesAreExported _ = return () @@ -118,8 +119,8 @@ where go (TypeRef tyName' _) = tyName' /= tyName go _ = True- + generateMain :: Environment -> Options -> [JS] -> Either String [JS] generateMain env opts js = case moduleNameFromString <$> optionsMain opts of@@ -191,7 +192,7 @@ go :: (Functor m, Monad m, MonadMake m) => Environment -> [(Bool, Module)] -> m () go _ [] = return () go env ((False, m) : ms') = do- (_, env') <- liftError . runCheck' env $ typeCheckModule Nothing m+ (_, env') <- liftError . runCheck' opts env $ typeCheckModule Nothing m go env' ms' go env ((True, m@(Module moduleName' _ exps)) : ms') = do@@ -199,7 +200,7 @@ jsFile = "js" ++ pathSeparator : filePath ++ ".js" externsFile = "externs" ++ pathSeparator : filePath ++ ".externs" - (Module _ elaborated _, env') <- liftError . runCheck' env $ typeCheckModule Nothing m+ (Module _ elaborated _, env') <- liftError . runCheck' opts env $ typeCheckModule Nothing m regrouped <- liftError . createBindingGroups moduleName' . collapseBindingGroups $ elaborated @@ -247,5 +248,6 @@ where prelude = ModuleName [ProperName C.prelude] isPreludeImport (ImportDeclaration (ModuleName [ProperName mn']) _ _) | mn' == C.prelude = True+ isPreludeImport (PositionedDeclaration _ d) = isPreludeImport d isPreludeImport _ = False preludeImport = ImportDeclaration prelude Nothing Nothing
src/Language/PureScript/CodeGen/Externs.hs view
@@ -45,6 +45,7 @@ fixityToPs :: Declaration -> Writer [String] () fixityToPs (FixityDeclaration (Fixity assoc prec) ident) = tell [ unwords [ show assoc, show prec, ident ] ]+ fixityToPs (PositionedDeclaration _ d) = fixityToPs d fixityToPs _ = return () exportToPs :: DeclarationRef -> Writer [String] ()
src/Language/PureScript/CodeGen/JS.hs view
@@ -82,6 +82,7 @@ (JSBlock [JSReturn (go pn (index + 1) tys' (JSVar ("value" ++ show index) : values))]) declToJs opts mp (DataBindingGroupDeclaration ds) e = Just $ concat $ mapMaybe (flip (declToJs opts mp) e) ds declToJs _ _ (ExternDeclaration _ _ (Just js) _) _ = Just [js]+declToJs opts mp (PositionedDeclaration _ d) e = declToJs opts mp d e declToJs _ _ _ _ = Nothing -- |@@ -307,6 +308,8 @@ binderToJs m e varName done (NamedBinder ident binder) = do js <- binderToJs m e varName done binder return (JSVariableIntroduction (identToJs ident) (Just (JSVar varName)) : js)+binderToJs m e varName done (PositionedBinder _ binder) =+ binderToJs m e varName done binder -- | -- Checks whether a data constructor is the only constructor for that type, used to simplify the
src/Language/PureScript/DeadCodeElimination.hs view
@@ -50,11 +50,13 @@ valueExists name (ValueDeclaration name' _ _ _ _) = name == name' valueExists name (ExternDeclaration _ name' _ _) = name == name' valueExists name (BindingGroupDeclaration decls) = any (\(name', _, _) -> name == name') decls+ valueExists name (PositionedDeclaration _ d) = valueExists name d valueExists _ _ = False typeExists :: ProperName -> Declaration -> Bool typeExists name (DataDeclaration name' _ _) = name == name' typeExists name (DataBindingGroupDeclaration decls) = any (typeExists name) decls+ typeExists name (PositionedDeclaration _ d) = typeExists name d typeExists _ _ = False type Key = (ModuleName, Either Ident ProperName)@@ -68,6 +70,7 @@ go (ExternDeclaration _ name _ _) = [((moduleName, Left name), [])] go d@(BindingGroupDeclaration names') = map (\(name, _, _) -> ((moduleName, Left name), dependencies moduleName d)) names' go (DataBindingGroupDeclaration ds') = concatMap go ds'+ go (PositionedDeclaration _ d) = go d go _ = [] dependencies :: (Data d) => ModuleName -> d -> [Key]@@ -94,4 +97,6 @@ in any (\v -> path graph v v') entryPointVertices) ds isUsed moduleName graph vertexFor entryPointVertices (DataBindingGroupDeclaration ds) = any (isUsed moduleName graph vertexFor entryPointVertices) ds+isUsed moduleName graph vertexFor entryPointVertices (PositionedDeclaration _ d) =+ isUsed moduleName graph vertexFor entryPointVertices d isUsed _ _ _ _ _ = True
src/Language/PureScript/Declarations.hs view
@@ -42,6 +42,24 @@ show Infix = "infix" -- |+-- Source position information+--+data SourcePos = SourcePos+ {+ -- |+ -- Line number+ --+ sourcePosLine :: Int+ -- |+ -- Column number+ --+ , sourcePosColumn :: Int+ } deriving (D.Data, D.Typeable)++instance Show SourcePos where+ show sp = "line " ++ show (sourcePosLine sp) ++ ", column " ++ show (sourcePosColumn sp)++-- | -- Fixity data for infix operators -- data Fixity = Fixity Associativity Precedence deriving (Show, D.Data, D.Typeable)@@ -132,6 +150,10 @@ -- declarations) -- | TypeInstanceDeclaration Ident [(Qualified ProperName, [Type])] (Qualified ProperName) [Type] [Declaration]+ -- |+ -- A declaration with source position information+ --+ | PositionedDeclaration SourcePos Declaration deriving (Show, D.Data, D.Typeable) -- |@@ -139,6 +161,7 @@ -- isValueDecl :: Declaration -> Bool isValueDecl ValueDeclaration{} = True+isValueDecl (PositionedDeclaration _ d) = isValueDecl d isValueDecl _ = False -- |@@ -147,6 +170,7 @@ isDataDecl :: Declaration -> Bool isDataDecl DataDeclaration{} = True isDataDecl TypeSynonymDeclaration{} = True+isDataDecl (PositionedDeclaration _ d) = isDataDecl d isDataDecl _ = False -- |@@ -154,6 +178,7 @@ -- isImportDecl :: Declaration -> Bool isImportDecl ImportDeclaration{} = True+isImportDecl (PositionedDeclaration _ d) = isImportDecl d isImportDecl _ = False -- |@@ -161,6 +186,7 @@ -- isExternDataDecl :: Declaration -> Bool isExternDataDecl ExternDataDeclaration{} = True+isExternDataDecl (PositionedDeclaration _ d) = isExternDataDecl d isExternDataDecl _ = False -- |@@ -168,6 +194,7 @@ -- isExternInstanceDecl :: Declaration -> Bool isExternInstanceDecl ExternInstanceDeclaration{} = True+isExternInstanceDecl (PositionedDeclaration _ d) = isExternInstanceDecl d isExternInstanceDecl _ = False -- |@@ -175,6 +202,7 @@ -- isFixityDecl :: Declaration -> Bool isFixityDecl FixityDeclaration{} = True+isFixityDecl (PositionedDeclaration _ d) = isFixityDecl d isFixityDecl _ = False -- |@@ -182,6 +210,7 @@ -- isExternDecl :: Declaration -> Bool isExternDecl ExternDeclaration{} = True+isExternDecl (PositionedDeclaration _ d) = isExternDecl d isExternDecl _ = False -- |@@ -190,6 +219,7 @@ isTypeClassDeclaration :: Declaration -> Bool isTypeClassDeclaration TypeClassDeclaration{} = True isTypeClassDeclaration TypeInstanceDeclaration{} = True+isTypeClassDeclaration (PositionedDeclaration _ d) = isTypeClassDeclaration d isTypeClassDeclaration _ = False -- |@@ -214,6 +244,10 @@ -- | BooleanLiteral Bool -- |+ -- A prefix -, will be desugared+ --+ | UnaryMinus Value+ -- | -- Binary operator application. During the rebracketing phase of desugaring, this data constructor -- will be removed. --@@ -282,7 +316,11 @@ -- can be evaluated at runtime. The constructor arguments represent (in order): the type class name and -- instance type, and the type class dictionaries in scope. --- | TypeClassDictionary (Qualified ProperName, [Type]) [TypeClassDictionaryInScope] deriving (Show, D.Data, D.Typeable)+ | TypeClassDictionary (Qualified ProperName, [Type]) [TypeClassDictionaryInScope]+ -- |+ -- A value with source position information+ --+ | PositionedValue SourcePos Value deriving (Show, D.Data, D.Typeable) -- | -- An alternative in a case statement@@ -324,7 +362,11 @@ -- | -- A let statement, i.e. a pure value with a binder --- | DoNotationLet Binder Value deriving (Show, D.Data, D.Typeable)+ | DoNotationLet Binder Value+ -- |+ -- A do notation element with source position information+ --+ | PositionedDoNotationElement SourcePos DoNotationElement deriving (Show, D.Data, D.Typeable) -- | -- Data type for binders@@ -369,8 +411,11 @@ -- | -- A binder which binds its input to an identifier --- | NamedBinder Ident Binder deriving (Show, D.Data, D.Typeable)-+ | NamedBinder Ident Binder+ -- |+ -- A binder with source position information+ --+ | PositionedBinder SourcePos Binder deriving (Show, D.Data, D.Typeable) -- | -- Collect all names introduced in binders in an expression
src/Language/PureScript/ModuleDependencies.hs view
@@ -56,6 +56,7 @@ qualifiedProperNames _ = [] imports :: Declaration -> [ModuleName] imports (ImportDeclaration mn _ _) = [mn]+ imports (PositionedDeclaration _ d) = imports d imports _ = [] getModuleName :: Module -> ModuleName
src/Language/PureScript/Options.hs view
@@ -57,10 +57,14 @@ -- The modules to code gen -- , optionsCodeGenModules :: [String]+ -- |+ -- Verbose error message+ --+ , optionsVerboseErrors :: Bool } deriving Show -- | -- Default compiler options -- defaultOptions :: Options-defaultOptions = Options False False False False Nothing False "PS" [] []+defaultOptions = Options False False False False Nothing False "PS" [] [] False
src/Language/PureScript/Parser/Common.hs view
@@ -227,14 +227,8 @@ -- Parse an integer or floating point value -- integerOrFloat :: P.Parsec String u (Either Integer Double)-integerOrFloat = (Right <$> P.try (signed PT.float) <|>- Left <$> P.try (signed PT.natural)) P.<?> "number"- where- signed p = do- let sign = (P.char '-' >> return negate) <|> (optional (P.char '+') >> return id)- f <- sign- n <- p tokenParser- return (f n)+integerOrFloat = (Right <$> P.try (PT.float tokenParser) <|>+ Left <$> P.try (PT.natural tokenParser)) P.<?> "number" -- | -- Parse an identifier or parenthesized operator@@ -375,3 +369,4 @@ -- runIndentParser :: FilePath -> P.Parsec String ParseState a -> String -> Either P.ParseError a runIndentParser filePath p = P.runParser p (ParseState 0) filePath+
src/Language/PureScript/Parser/Declarations.hs view
@@ -38,6 +38,14 @@ import qualified Text.Parsec as P import qualified Text.Parsec.Expr as P +-- |+-- Read source position information+--+sourcePos :: P.Parsec s u SourcePos+sourcePos = toSourcePos <$> P.getPosition+ where+ toSourcePos p = SourcePos (P.sourceLine p) (P.sourceColumn p)+ parseDataDeclaration :: P.Parsec String ParseState Declaration parseDataDeclaration = do reserved "data"@@ -162,7 +170,7 @@ -- Parse a single declaration -- parseDeclaration :: P.Parsec String ParseState Declaration-parseDeclaration = P.choice+parseDeclaration = PositionedDeclaration <$> sourcePos <*> P.choice [ parseDataDeclaration , parseTypeDeclaration , parseTypeSynonymDeclaration@@ -175,7 +183,7 @@ ] P.<?> "declaration" parseLocalDeclaration :: P.Parsec String ParseState Declaration-parseLocalDeclaration = P.choice+parseLocalDeclaration = PositionedDeclaration <$> sourcePos <*> P.choice [ parseTypeDeclaration , parseValueDeclaration ] P.<?> "local declaration"@@ -313,7 +321,7 @@ -- Parse a value -- parseValue :: P.Parsec String ParseState Value-parseValue =+parseValue = PositionedValue <$> sourcePos <*> (P.buildExpressionParser operators . C.buildPostfixParser postfixTable2 $ indexersAndAccessors) P.<?> "expression"@@ -324,8 +332,11 @@ postfixTable2 = [ \v -> P.try (flip App <$> (C.indented *> indexersAndAccessors)) <*> pure v , \v -> flip (TypedValue True) <$> (P.try (C.lexeme (C.indented *> P.string "::")) *> parsePolyType) <*> pure v ]- operators = [ [ P.Infix (C.lexeme (P.try (C.indented *> C.parseIdentInfix P.<?> "operator") >>= \ident ->- return (BinaryNoParens ident))) P.AssocRight ]+ operators = [ [ P.Prefix (C.lexeme (P.try (C.indented *> P.char '-') >> return UnaryMinus))+ ]+ , [ P.Infix (C.lexeme (P.try (C.indented *> C.parseIdentInfix P.<?> "operator") >>= \ident ->+ return (BinaryNoParens ident))) P.AssocRight+ ] ] parseStringBinder :: P.Parsec String ParseState Binder@@ -370,7 +381,8 @@ -- Parse a binder -- parseBinder :: P.Parsec String ParseState Binder-parseBinder = P.buildExpressionParser operators parseBinderAtom P.<?> "expression"+parseBinder = PositionedBinder <$> sourcePos <*>+ P.buildExpressionParser operators parseBinderAtom P.<?> "expression" where operators = [ [ P.Infix ( C.lexeme (P.try $ C.indented *> C.reservedOp ":") >> return ConsBinder) P.AssocRight ] ] parseBinderAtom :: P.Parsec String ParseState Binder
src/Language/PureScript/Pretty/Common.hs view
@@ -15,8 +15,46 @@ module Language.PureScript.Pretty.Common where +import Control.Monad.State+import Data.List (intercalate)+ -- | -- Wrap a string in parentheses -- parens :: String -> String parens s = ('(':s) ++ ")"++newtype PrinterState = PrinterState { indent :: Int } deriving (Show, Eq, Ord)++-- |+-- Number of characters per identation level+--+blockIndent :: Int+blockIndent = 4++-- |+-- Pretty print with a new indentation level+--+withIndent :: StateT PrinterState Maybe String -> StateT PrinterState Maybe String+withIndent action = do+ modify $ \st -> st { indent = indent st + blockIndent }+ result <- action+ modify $ \st -> st { indent = indent st - blockIndent }+ return result++-- |+-- Get the current indentation level+--+currentIndent :: StateT PrinterState Maybe String+currentIndent = do+ current <- get+ return $ replicate (indent current) ' '++-- |+-- Print many lines+--+prettyPrintMany :: (a -> StateT PrinterState Maybe String) -> [a] -> StateT PrinterState Maybe String+prettyPrintMany f xs = do+ ss <- mapM f xs+ indentString <- currentIndent+ return $ intercalate "\n" $ map (indentString ++) ss
src/Language/PureScript/Pretty/JS.hs view
@@ -27,39 +27,14 @@ import Control.PatternArrows import Control.Applicative import Control.Monad.State--newtype PrinterState = PrinterState { indent :: Int } deriving (Show, Eq, Ord)---- |--- Number of characters per identation level----blockIndent :: Int-blockIndent = 4---- |--- Pretty print with a new indentation level----withIndent :: StateT PrinterState Maybe String -> StateT PrinterState Maybe String-withIndent action = do- modify $ \st -> st { indent = indent st + blockIndent }- result <- action- modify $ \st -> st { indent = indent st - blockIndent }- return result---- |--- Get the current indentation level----currentIndent :: StateT PrinterState Maybe String-currentIndent = do- current <- get- return $ replicate (indent current) ' '+import Numeric literals :: Pattern PrinterState JS String literals = mkPattern' match where match :: JS -> StateT PrinterState Maybe String match (JSNumericLiteral n) = return $ either show show n- match (JSStringLiteral s) = return $ show s+ match (JSStringLiteral s) = return $ string s match (JSBooleanLiteral True) = return "true" match (JSBooleanLiteral False) = return "false" match (JSArrayLiteral xs) = fmap concat $ sequence@@ -139,6 +114,22 @@ ] match (JSRaw js) = return js match _ = mzero++string :: String -> String+string s = '"' : concatMap encodeChar s ++ "\""+ where+ encodeChar :: Char -> String+ encodeChar '\b' = "\\b"+ encodeChar '\t' = "\\t"+ encodeChar '\n' = "\\n"+ encodeChar '\v' = "\\v"+ encodeChar '\f' = "\\f"+ encodeChar '\r' = "\\r"+ encodeChar '"' = "\\\""+ encodeChar '\\' = "\\\\"+ encodeChar c | fromEnum c > 0xFFF = "\\u" ++ showHex (fromEnum c) ""+ encodeChar c | fromEnum c > 0xFF = "\\u0" ++ showHex (fromEnum c) ""+ encodeChar c = [c] conditional :: Pattern PrinterState JS ((JS, JS), JS) conditional = mkPattern match
src/Language/PureScript/Pretty/Values.hs view
@@ -20,132 +20,207 @@ import Data.Maybe (fromMaybe) import Data.List (intercalate)-import Control.Arrow ((<+>))++import Control.Arrow ((<+>), runKleisli) import Control.PatternArrows+import Control.Monad.State+import Control.Applicative -import Language.PureScript.Types import Language.PureScript.Declarations import Language.PureScript.Pretty.Common-import Language.PureScript.Pretty.Types+import Language.PureScript.Pretty.Types (prettyPrintType) -literals :: Pattern () Value String-literals = mkPattern match+literals :: Pattern PrinterState Value String+literals = mkPattern' match where- match (NumericLiteral n) = Just $ either show show n- match (StringLiteral s) = Just $ show s- match (BooleanLiteral True) = Just "true"- match (BooleanLiteral False) = Just "false"- match (ArrayLiteral xs) = Just $ "[" ++ intercalate ", " (map prettyPrintValue xs) ++ "]"- match (ObjectLiteral ps) = Just $ "{" ++ intercalate ", " (map (uncurry prettyPrintObjectProperty) ps) ++ "}"- match (Constructor name) = Just $ show name- match (Case values binders) = Just $ "case " ++ unwords (map prettyPrintValue values) ++- " of { " ++ intercalate " ; " (map prettyPrintCaseAlternative binders) ++ " }"- match (Let _ val) = Just $ "let ... in " ++ prettyPrintValue val- match (Var ident) = Just $ show ident- match (Do els) = Just $ " do { " ++ intercalate "; " (map prettyPrintDoNotationElement els) ++ " }"+ match :: Value -> StateT PrinterState Maybe String+ match (NumericLiteral n) = return $ either show show n+ match (StringLiteral s) = return $ show s+ match (BooleanLiteral True) = return "true"+ match (BooleanLiteral False) = return "false"+ match (ArrayLiteral xs) = fmap concat $ sequence+ [ return "[ "+ , withIndent $ prettyPrintMany prettyPrintValue' xs+ , return " ]"+ ]+ match (ObjectLiteral []) = return "{}"+ match (ObjectLiteral ps) = fmap concat $ sequence+ [ return "{\n"+ , withIndent $ prettyPrintMany prettyPrintObjectProperty ps+ , currentIndent+ , return "}"+ ]+ match (Constructor name) = return $ show name+ match (Case values binders) = fmap concat $ sequence+ [ return "case "+ , unwords <$> forM values prettyPrintValue'+ , return " of\n"+ , withIndent $ prettyPrintMany prettyPrintCaseAlternative binders+ , currentIndent+ ]+ match (Let ds val) = fmap concat $ sequence+ [ return "let\n"+ , withIndent $ prettyPrintMany prettyPrintDeclaration ds+ , return "\n"+ , currentIndent+ , return "in "+ , prettyPrintValue' val+ ]+ match (Var ident) = return $ show ident+ match (Do els) = fmap concat $ sequence+ [ return "do "+ , withIndent $ prettyPrintMany prettyPrintDoNotationElement els+ , currentIndent+ ] match (TypeClassDictionary _ _) = error "Type class dictionary was not replaced"- match _ = Nothing+ match (TypedValue _ val _) = prettyPrintValue' val+ match (PositionedValue _ val) = prettyPrintValue' val+ match _ = mzero -prettyPrintCaseAlternative :: CaseAlternative -> String+prettyPrintDeclaration :: Declaration -> StateT PrinterState Maybe String+prettyPrintDeclaration (TypeDeclaration ident ty) = return $ show ident ++ " :: " ++ prettyPrintType ty+prettyPrintDeclaration (ValueDeclaration ident _ [] Nothing val) = fmap concat $ sequence+ [ return $ show ident ++ " = "+ , prettyPrintValue' val+ ]+prettyPrintDeclaration (PositionedDeclaration _ d) = prettyPrintDeclaration d+prettyPrintDeclaration _ = error "Invalid argument to prettyPrintDeclaration"++prettyPrintCaseAlternative :: CaseAlternative -> StateT PrinterState Maybe String prettyPrintCaseAlternative (CaseAlternative binders grd val) =- "(" ++ intercalate ", " (map prettyPrintBinder binders) ++ ") " ++- maybe "" (("| " ++) . prettyPrintValue) grd ++ " -> " ++ prettyPrintValue val+ fmap concat $ sequence+ [ intercalate ", " <$> forM binders prettyPrintBinder'+ , maybe (return "") (fmap ("| " ++) . prettyPrintValue') grd+ , return " -> "+ , prettyPrintValue' val+ ] -ifThenElse :: Pattern () Value ((Value, Value), Value)+prettyPrintDoNotationElement :: DoNotationElement -> StateT PrinterState Maybe String+prettyPrintDoNotationElement (DoNotationValue val) =+ prettyPrintValue' val+prettyPrintDoNotationElement (DoNotationBind binder val) =+ fmap concat $ sequence+ [ prettyPrintBinder' binder+ , return " <- "+ , prettyPrintValue' val+ ]+prettyPrintDoNotationElement (DoNotationLet binder val) =+ fmap concat $ sequence+ [ return "let "+ , prettyPrintBinder' binder+ , return " = "+ , prettyPrintValue' val+ ]+prettyPrintDoNotationElement (PositionedDoNotationElement _ el) = prettyPrintDoNotationElement el++ifThenElse :: Pattern PrinterState Value ((Value, Value), Value) ifThenElse = mkPattern match where match (IfThenElse cond th el) = Just ((th, el), cond) match _ = Nothing -accessor :: Pattern () Value (String, Value)+accessor :: Pattern PrinterState Value (String, Value) accessor = mkPattern match where match (Accessor prop val) = Just (prop, val) match _ = Nothing -objectUpdate :: Pattern () Value ([String], Value)+objectUpdate :: Pattern PrinterState Value ([String], Value) objectUpdate = mkPattern match where match (ObjectUpdate o ps) = Just (flip map ps $ \(key, val) -> key ++ " = " ++ prettyPrintValue val, o) match _ = Nothing -app :: Pattern () Value (String, Value)+app :: Pattern PrinterState Value (String, Value) app = mkPattern match where match (App val arg) = Just (prettyPrintValue arg, val) match _ = Nothing -lam :: Pattern () Value (String, Value)+lam :: Pattern PrinterState Value (String, Value) lam = mkPattern match where match (Abs (Left arg) val) = Just (show arg, val) match _ = Nothing -typed :: Pattern () Value (Type, Value)-typed = mkPattern match- where- match (TypedValue _ val ty) = Just (ty, val)- match _ = Nothing--prettyPrintDoNotationElement :: DoNotationElement -> String-prettyPrintDoNotationElement (DoNotationValue val) = prettyPrintValue val-prettyPrintDoNotationElement (DoNotationBind binder val) = prettyPrintBinder binder ++ " <- " ++ prettyPrintValue val-prettyPrintDoNotationElement (DoNotationLet binder val) = "let " ++ prettyPrintBinder binder ++ " = " ++ prettyPrintValue val- -- |--- Generate a pretty-printed string representing a Value+-- Generate a pretty-printed string representing an expression -- prettyPrintValue :: Value -> String-prettyPrintValue = fromMaybe (error "Incomplete pattern") . pattern matchValue ()+prettyPrintValue = fromMaybe (error "Incomplete pattern") . flip evalStateT (PrinterState 0) . prettyPrintValue'++prettyPrintValue' :: Value -> StateT PrinterState Maybe String+prettyPrintValue' = runKleisli $ runPattern matchValue where- matchValue :: Pattern () Value String+ matchValue :: Pattern PrinterState Value String matchValue = buildPrettyPrinter operators (literals <+> fmap parens matchValue)- operators :: OperatorTable () Value String+ operators :: OperatorTable PrinterState Value String operators = OperatorTable [ [ Wrap accessor $ \prop val -> val ++ "." ++ prop ] , [ Wrap objectUpdate $ \ps val -> val ++ "{ " ++ intercalate ", " ps ++ " }" ] , [ Wrap app $ \arg val -> val ++ "(" ++ arg ++ ")" ] , [ Split lam $ \arg val -> "\\" ++ arg ++ " -> " ++ prettyPrintValue val ] , [ Wrap ifThenElse $ \(th, el) cond -> "if " ++ cond ++ " then " ++ prettyPrintValue th ++ " else " ++ prettyPrintValue el ]- , [ Wrap typed $ \ty val -> val ++ " :: " ++ prettyPrintType ty ] ] -prettyPrintBinderAtom :: Pattern () Binder String-prettyPrintBinderAtom = mkPattern match+prettyPrintBinderAtom :: Pattern PrinterState Binder String+prettyPrintBinderAtom = mkPattern' match where- match :: Binder -> Maybe String- match NullBinder = Just "_"- match (StringBinder str) = Just $ show str- match (NumberBinder num) = Just $ either show show num- match (BooleanBinder True) = Just "true"- match (BooleanBinder False) = Just "false"- match (VarBinder ident) = Just $ show ident- match (ConstructorBinder ctor args) = Just $ show ctor ++ " " ++ unwords (map (parens . prettyPrintBinder) args)- match (ObjectBinder bs) = Just $ "{ " ++ intercalate ", " (map (uncurry prettyPrintObjectPropertyBinder) bs) ++ " }"- match (ArrayBinder bs) = Just $ "[ " ++ intercalate ", " (map prettyPrintBinder bs) ++ " ]"- match (NamedBinder ident binder) = Just $ show ident ++ "@" ++ prettyPrintBinder binder- match _ = Nothing+ match :: Binder -> StateT PrinterState Maybe String+ match NullBinder = return "_"+ match (StringBinder str) = return $ show str+ match (NumberBinder num) = return $ either show show num+ match (BooleanBinder True) = return "true"+ match (BooleanBinder False) = return "false"+ match (VarBinder ident) = return $ show ident+ match (ConstructorBinder ctor args) = fmap concat $ sequence+ [ return $ show ctor ++ " "+ , unwords <$> forM args match+ ]+ match (ObjectBinder bs) = fmap concat $ sequence+ [ return "{\n"+ , withIndent $ prettyPrintMany prettyPrintObjectPropertyBinder bs+ , currentIndent+ , return "}"+ ]+ match (ArrayBinder bs) = fmap concat $ sequence+ [ return "["+ , unwords <$> mapM prettyPrintBinder' bs+ , return "]"+ ]+ match (NamedBinder ident binder) = ((show ident ++ "@") ++) <$> prettyPrintBinder' binder+ match (PositionedBinder _ binder) = prettyPrintBinder' binder+ match _ = mzero -- | -- Generate a pretty-printed string representing a Binder -- prettyPrintBinder :: Binder -> String-prettyPrintBinder = fromMaybe (error "Incomplete pattern") . pattern matchBinder ()+prettyPrintBinder = fromMaybe (error "Incomplete pattern") . flip evalStateT (PrinterState 0) . prettyPrintBinder'++prettyPrintBinder' :: Binder -> StateT PrinterState Maybe String+prettyPrintBinder' = runKleisli $ runPattern matchBinder where- matchBinder :: Pattern () Binder String+ matchBinder :: Pattern PrinterState Binder String matchBinder = buildPrettyPrinter operators (prettyPrintBinderAtom <+> fmap parens matchBinder)- operators :: OperatorTable () Binder String+ operators :: OperatorTable PrinterState Binder String operators = OperatorTable [ [ AssocR matchConsBinder (\b1 b2 -> b1 ++ " : " ++ b2) ] ] -matchConsBinder :: Pattern () Binder (Binder, Binder)+matchConsBinder :: Pattern PrinterState Binder (Binder, Binder) matchConsBinder = mkPattern match' where match' (ConsBinder b1 b2) = Just (b1, b2) match' _ = Nothing -prettyPrintObjectPropertyBinder :: String -> Binder -> String-prettyPrintObjectPropertyBinder key binder = key ++ ": " ++ prettyPrintBinder binder+prettyPrintObjectPropertyBinder :: (String, Binder) -> StateT PrinterState Maybe String+prettyPrintObjectPropertyBinder (key, binder) = fmap concat $ sequence+ [ return $ key ++ ": "+ , prettyPrintBinder' binder+ ] -prettyPrintObjectProperty :: String -> Value -> String-prettyPrintObjectProperty key value = key ++ ": " ++ prettyPrintValue value+prettyPrintObjectProperty :: (String, Value) -> StateT PrinterState Maybe String+prettyPrintObjectProperty (key, value) = fmap concat $ sequence+ [ return $ key ++ ": "+ , prettyPrintValue' value+ ]
src/Language/PureScript/Sugar.hs view
@@ -27,6 +27,8 @@ import Language.PureScript.Sugar.TypeClasses as S import Language.PureScript.Sugar.Names as S +import Control.Category ((>>>))+ -- | -- The desugaring pipeline proceeds as follows: --@@ -45,7 +47,8 @@ -- * Qualify any unqualified names and types -- desugar :: [Module] -> Either String [Module]-desugar = desugarDo+desugar = removeSignedLiterals+ >>> desugarDo >=> desugarCasesModule >=> desugarTypeDeclarationsModule >=> desugarImports
src/Language/PureScript/Sugar/BindingGroups.hs view
@@ -26,7 +26,7 @@ import Data.Generics import Data.Generics.Extras import Data.List (nub, intersect)-import Data.Maybe (mapMaybe)+import Data.Maybe (isJust, mapMaybe) import Control.Applicative ((<$>), (<*>), pure) import Language.PureScript.Declarations@@ -82,6 +82,7 @@ where go (DataBindingGroupDeclaration ds) = ds go (BindingGroupDeclaration ds) = map (\(ident, nameKind, val) -> ValueDeclaration ident nameKind [] Nothing val) ds+ go (PositionedDeclaration pos d) = map (PositionedDeclaration pos) $ go d go other = [other] collapseBindingGroupsForValue :: Value -> Value@@ -109,11 +110,13 @@ getIdent :: Declaration -> Ident getIdent (ValueDeclaration ident _ _ _ _) = ident+getIdent (PositionedDeclaration _ d) = getIdent d getIdent _ = error "Expected ValueDeclaration" getProperName :: Declaration -> ProperName getProperName (DataDeclaration pn _ _) = pn getProperName (TypeSynonymDeclaration pn _ _) = pn+getProperName (PositionedDeclaration _ d) = getProperName d getProperName _ = error "Expected DataDeclaration" toBindingGroup :: SCC Declaration -> Declaration@@ -123,16 +126,20 @@ toDataBindingGroup :: SCC Declaration -> Either String Declaration toDataBindingGroup (AcyclicSCC d) = return d-toDataBindingGroup (CyclicSCC [TypeSynonymDeclaration pn _ _]) = Left $ "Cycle in type synonym " ++ show pn-toDataBindingGroup (CyclicSCC [d]) = return d+toDataBindingGroup (CyclicSCC [d]) = case isTypeSynonym d of+ Just pn -> Left $ "Cycle in type synonym " ++ show pn+ _ -> return d toDataBindingGroup (CyclicSCC ds')- | all isTypeSynonym ds' = Left "Cycle in type synonyms"+ | all (isJust . isTypeSynonym) ds' = Left "Cycle in type synonyms" | otherwise = return $ DataBindingGroupDeclaration ds'- where- isTypeSynonym TypeSynonymDeclaration{} = True- isTypeSynonym _ = False +isTypeSynonym :: Declaration -> Maybe ProperName+isTypeSynonym (TypeSynonymDeclaration pn _ _) = Just pn+isTypeSynonym (PositionedDeclaration _ d) = isTypeSynonym d+isTypeSynonym _ = Nothing+ fromValueDecl :: Declaration -> (Ident, NameKind, Value) fromValueDecl (ValueDeclaration ident nameKind [] Nothing val) = (ident, nameKind, val) fromValueDecl ValueDeclaration{} = error "Binders should have been desugared"+fromValueDecl (PositionedDeclaration _ d) = fromValueDecl d fromValueDecl _ = error "Expected ValueDeclaration"
src/Language/PureScript/Sugar/CaseDeclarations.hs view
@@ -62,11 +62,16 @@ where go (Let ds val') = Let <$> desugarCases ds <*> pure val' go other = return other+ desugarRest (PositionedDeclaration pos d : ds) = do+ (d' : ds') <- desugarRest (d : ds)+ return (PositionedDeclaration pos d' : ds') desugarRest (d : ds) = (:) d <$> desugarRest ds desugarRest [] = pure [] inSameGroup :: Declaration -> Declaration -> Bool inSameGroup (ValueDeclaration ident1 _ _ _ _) (ValueDeclaration ident2 _ _ _ _) = ident1 == ident2+inSameGroup (PositionedDeclaration _ d1) d2 = inSameGroup d1 d2+inSameGroup d1 (PositionedDeclaration _ d2) = inSameGroup d1 d2 inSameGroup _ _ = False toDecls :: [Declaration] -> Either String [Declaration]@@ -79,6 +84,9 @@ unless (all ((== length bs) . length . fst) tuples) $ throwError $ "Argument list lengths differ in declaration " ++ show ident return [makeCaseDeclaration ident tuples]+toDecls (PositionedDeclaration pos d : ds) = do+ (d' : ds') <- toDecls (d : ds)+ return (PositionedDeclaration pos d' : ds') toDecls ds = return ds isVarBinder :: Binder -> Bool@@ -87,6 +95,7 @@ toTuple :: Declaration -> ([Binder], (Maybe Guard, Value)) toTuple (ValueDeclaration _ _ bs g val) = (bs, (g, val))+toTuple (PositionedDeclaration _ d) = toTuple d toTuple _ = error "Not a value declaration" makeCaseDeclaration :: Ident -> [([Binder], (Maybe Guard, Value))] -> Declaration
src/Language/PureScript/Sugar/DoNotation.hs view
@@ -27,6 +27,8 @@ import qualified Language.PureScript.Constants as C +import Control.Applicative+ -- | -- Replace all @DoNotationBind@ and @DoNotationValue@ constructors with applications of the Prelude.(>>=) function, -- and all @DoNotationLet@ constructors with let expressions.@@ -60,3 +62,4 @@ go (DoNotationLet binder val : rest) = do rest' <- go rest return $ Case [val] [CaseAlternative [binder] Nothing rest']+ go (PositionedDoNotationElement pos el : rest) = PositionedValue pos <$> go (el : rest)
src/Language/PureScript/Sugar/Names.hs view
@@ -216,6 +216,7 @@ letBoundVariable :: Declaration -> Ident letBoundVariable (ValueDeclaration ident _ _ _ _) = ident+ letBoundVariable (PositionedDeclaration _ d) = letBoundVariable d letBoundVariable _ = error "Invalid argument to letBoundVariable" go (ValueDeclaration name _ _ _ _) = error $ "Binders should have been desugared in " ++ show name go (ExternDeclaration fit name js ty) =@@ -223,6 +224,7 @@ go (BindingGroupDeclaration decls') = do BindingGroupDeclaration <$> mapM go' decls' where go' = \(name, nk, value) -> rethrowFor "declaration" 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@@ -230,20 +232,20 @@ updateAll :: Data d => d -> Either String d updateAll = everywhereM (mkM updateType `extM` updateValue `extM` updateBinder)- + updateValue (Constructor name) = Constructor <$> updateDataConstructorName name updateValue v = return v- + updateBinder (ConstructorBinder name b) = ConstructorBinder <$> updateDataConstructorName name <*> pure b updateBinder v = return v- + updateType (TypeConstructor name) = TypeConstructor <$> updateTypeName name 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' = everywhereM (mkM updateType)- + updateConstraints = mapM (\(name, ts) -> (,) <$> updateClassName name <*> pure ts) updateTypeName = update "type" importedTypes (\mes -> isJust . (`lookup` (exportedTypes mes)))@@ -299,6 +301,7 @@ addDecl mn env (ExternDataDeclaration tn _) = addType env mn tn [] addDecl mn env (ValueDeclaration name _ _ _ _) = addValue env mn name addDecl mn env (ExternDeclaration _ name _ _) = addValue env mn name+ addDecl mn env (PositionedDeclaration _ d) = addDecl mn env d addDecl _ env _ = return env -- |@@ -365,6 +368,7 @@ findImports = foldl findImports' M.empty where findImports' result (ImportDeclaration mn expl qual) = M.insert mn (expl, qual) result+ findImports' result (PositionedDeclaration _ d) = findImports' result d findImports' result _ = result -- |
src/Language/PureScript/Sugar/Operators.hs view
@@ -20,7 +20,8 @@ {-# LANGUAGE Rank2Types, FlexibleContexts #-} module Language.PureScript.Sugar.Operators (- rebracket+ rebracket,+ removeSignedLiterals ) where import Language.PureScript.Names@@ -42,6 +43,8 @@ import qualified Text.Parsec.Pos as P import qualified Text.Parsec.Expr as P +import qualified Language.PureScript.Constants as C+ -- | -- Remove explicit parentheses and reorder binary operator applications --@@ -52,6 +55,14 @@ let opTable = customOperatorTable fixities mapM (rebracketModule opTable) ms +removeSignedLiterals :: (D.Data d) => d -> d+removeSignedLiterals = G.everywhere (G.mkT go)+ where+ go (UnaryMinus (NumericLiteral (Left n))) = NumericLiteral (Left $ negate n)+ go (UnaryMinus (NumericLiteral (Right n))) = NumericLiteral (Right $ negate n)+ 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 opTable (Module mn ds exts) = Module mn <$> (removeParens <$> G.everywhereM' (G.mkM (matchOperators opTable)) ds) <*> pure exts @@ -65,6 +76,7 @@ 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 _ = []
src/Language/PureScript/Sugar/TypeClasses.hs view
@@ -99,10 +99,14 @@ entries <- mapM (typeInstanceDictionaryEntryDeclaration name mn deps className ty) desugared dictDecl <- typeInstanceDictionaryDeclaration name mn deps className ty desugared return $ (Just $ TypeInstanceRef name, d : entries ++ [dictDecl])+desugarDecl mn (PositionedDeclaration pos d) = do+ (dr, ds) <- desugarDecl mn d+ return (dr, map (PositionedDeclaration pos) ds) desugarDecl _ other = return (Nothing, [other]) memberToNameAndType :: Declaration -> (String, Type) memberToNameAndType (TypeDeclaration ident ty) = (identToJs ident, ty)+memberToNameAndType (PositionedDeclaration _ d) = memberToNameAndType d memberToNameAndType _ = error "Invalid declaration in type class definition" typeClassDictionaryDeclaration :: ProperName -> [String] -> [Declaration] -> Declaration@@ -114,6 +118,8 @@ ExternDeclaration TypeClassAccessorImport ident (Just (JSFunction (Just $ identToJs ident) ["dict"] (JSBlock [JSReturn (JSAccessor (identToJs ident) (JSVar "dict"))]))) (quantify (ConstrainedType [(Qualified (Just mn) name, map TypeVar args)] ty))+typeClassMemberToDictionaryAccessor mn name args (PositionedDeclaration pos d) =+ PositionedDeclaration pos $ typeClassMemberToDictionaryAccessor mn name args d typeClassMemberToDictionaryAccessor _ _ _ _ = error "Invalid declaration in type class definition" typeInstanceDictionaryDeclaration :: Ident -> ModuleName -> [(Qualified ProperName, [Type])] -> Qualified ProperName -> [Type] -> [Declaration] -> Desugar Declaration@@ -143,6 +149,9 @@ return (identToJs ident, TypedValue False (foldl App (Var (Qualified Nothing memberName)) (map (\n -> Var (Qualified Nothing (Ident ('_' : show n)))) [1..length deps])) (quantify memberType))+ memberToNameAndValue tys' (PositionedDeclaration pos d) = do+ (ident, val) <- memberToNameAndValue tys' d+ return (ident, PositionedValue pos val) memberToNameAndValue _ _ = error "Invalid declaration in type instance definition" typeInstanceDictionaryEntryDeclaration :: Ident -> ModuleName -> [(Qualified ProperName, [Type])] -> Qualified ProperName -> [Type] -> Declaration -> Desugar Declaration@@ -157,6 +166,8 @@ 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+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
@@ -27,6 +27,8 @@ import Control.Monad (forM) import Language.PureScript.Declarations+import Language.PureScript.Names+import Language.PureScript.Environment -- | -- Replace all top level type declarations in a module with type annotations@@ -38,9 +40,19 @@ -- Replace all top level type declarations with type annotations -- desugarTypeDeclarations :: [Declaration] -> Either String [Declaration]-desugarTypeDeclarations (TypeDeclaration name ty : ValueDeclaration name' nameKind [] Nothing val : rest) | name == name' =+desugarTypeDeclarations (PositionedDeclaration pos d : ds) = do+ (d' : ds') <- 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)-desugarTypeDeclarations (TypeDeclaration name _ : _) = throwError $ "Orphan type declaration for " ++ show name+ where+ fromValueDeclaration :: Declaration -> Either String (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'+ return (ident, nameKind, PositionedValue pos val)+ fromValueDeclaration _ = throwError $ "Orphan type declaration for " ++ show name 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
@@ -26,6 +26,7 @@ import Language.PureScript.TypeChecker.Synonyms as T import Data.Maybe+import Data.Monoid ((<>)) import qualified Data.Map as M import Control.Monad.State import Control.Monad.Error@@ -36,14 +37,13 @@ import Language.PureScript.Declarations import Language.PureScript.TypeClassDictionaries import Language.PureScript.Environment-import Language.PureScript.Pretty.Types addDataType :: ModuleName -> ProperName -> [String] -> [(ProperName, [Type])] -> Kind -> Check () addDataType moduleName name args dctors ctorKind = do env <- getEnv putEnv $ env { types = M.insert (Qualified (Just moduleName) name) (ctorKind, DataType args dctors) (types env) } forM_ dctors $ \(dctor, tys) ->- rethrow (("Error in data constructor " ++ show dctor ++ ":\n") ++) $+ rethrow (strMsg ("Error in data constructor " ++ show dctor) <>) $ addDataConstructor moduleName name args dctor tys addDataConstructor :: ModuleName -> ProperName -> [String] -> ProperName -> [Type] -> Check ()@@ -64,7 +64,7 @@ valueIsNotDefined moduleName name = do env <- getEnv case M.lookup (moduleName, name) (names env) of- Just _ -> throwError $ show name ++ " is already defined"+ Just _ -> throwError . strMsg $ show name ++ " is already defined" Nothing -> return () addValue :: ModuleName -> Ident -> Type -> NameKind -> Check ()@@ -85,10 +85,10 @@ checkTypeClassInstance _ (TypeVar _) = return () checkTypeClassInstance _ (TypeConstructor ctor) = do env <- getEnv- when (ctor `M.member` typeSynonyms env) $ throwError "Type synonym instances are disallowed"+ 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 $ "Type class instance head is invalid: " ++ prettyPrintType ty+checkTypeClassInstance _ ty = throwError $ mkUnifyErrorStack "Type class instance head is invalid." (Just (TypeError ty)) -- | -- Type check all declarations in a module@@ -106,13 +106,13 @@ typeCheckAll :: Maybe ModuleName -> ModuleName -> [Declaration] -> Check [Declaration] typeCheckAll _ _ [] = return [] typeCheckAll mainModuleName moduleName (d@(DataDeclaration name args dctors) : rest) = do- rethrow (("Error in type constructor " ++ show name ++ ":\n") ++) $ do+ rethrow (strMsg ("Error in type constructor " ++ show name) <>) $ do ctorKind <- kindsOf True moduleName name args (concatMap snd dctors) addDataType moduleName name args dctors ctorKind ds <- typeCheckAll mainModuleName moduleName rest return $ d : ds typeCheckAll mainModuleName moduleName (d@(DataBindingGroupDeclaration tys) : rest) = do- rethrow ("Error in data binding group:\n" ++) $ do+ rethrow (strMsg "Error in data binding group" <>) $ do let syns = mapMaybe toTypeSynonym tys let dataDecls = mapMaybe toDataDecl tys (syn_ks, data_ks) <- kindsOfAll moduleName syns (map (\(name, args, dctors) -> (name, args, concatMap snd dctors)) dataDecls)@@ -124,18 +124,20 @@ return $ d : ds where toTypeSynonym (TypeSynonymDeclaration nm args ty) = Just (nm, args, ty)+ toTypeSynonym (PositionedDeclaration _ d') = toTypeSynonym d' toTypeSynonym _ = Nothing toDataDecl (DataDeclaration nm args dctors) = Just (nm, args, dctors)+ toDataDecl (PositionedDeclaration _ d') = toDataDecl d' toDataDecl _ = Nothing typeCheckAll mainModuleName moduleName (d@(TypeSynonymDeclaration name args ty) : rest) = do- rethrow (("Error in type synonym " ++ show name ++ ":\n") ++) $ do+ rethrow (strMsg ("Error in type synonym " ++ show name) <>) $ do kind <- kindsOf False moduleName name args [ty] addTypeSynonym moduleName name args ty kind ds <- typeCheckAll mainModuleName moduleName rest return $ d : ds typeCheckAll _ _ (TypeDeclaration _ _ : _) = error "Type declarations should have been removed" typeCheckAll mainModuleName moduleName (ValueDeclaration name nameKind [] Nothing val : rest) = do- d <- rethrow (("Error in declaration " ++ show name ++ ":\n") ++) $ do+ d <- rethrow (strMsg ("Error in declaration " ++ show name) <>) $ do valueIsNotDefined moduleName name [(_, (val', ty))] <- typesOf mainModuleName moduleName [(name, val)] addValue moduleName name ty nameKind@@ -144,7 +146,7 @@ return $ d : ds typeCheckAll _ _ (ValueDeclaration{} : _) = error "Binders were not desugared" typeCheckAll mainModuleName moduleName (BindingGroupDeclaration vals : rest) = do- d <- rethrow (("Error in binding group " ++ show (map (\(ident, _, _) -> ident) vals) ++ ":\n") ++) $ do+ d <- rethrow (strMsg ("Error in binding group " ++ show (map (\(ident, _, _) -> ident) vals)) <>) $ do forM_ (map (\(ident, _, _) -> ident) vals) $ \name -> valueIsNotDefined moduleName name tys <- typesOf mainModuleName moduleName $ map (\(ident, _, ty) -> (ident, ty)) vals@@ -160,19 +162,19 @@ ds <- typeCheckAll mainModuleName moduleName rest return $ d : ds typeCheckAll mainModuleName moduleName (d@(ExternDeclaration importTy name _ ty) : rest) = do- rethrow (("Error in foreign import declaration " ++ show name ++ ":\n") ++) $ do+ rethrow (strMsg ("Error in foreign import declaration " ++ show name) <>) $ do env <- getEnv kind <- kindOf moduleName ty- guardWith "Expected kind *" $ kind == Star+ guardWith (strMsg "Expected kind *") $ kind == Star case M.lookup (moduleName, name) (names env) of- Just _ -> throwError $ show name ++ " is already defined"+ Just _ -> throwError . strMsg $ show name ++ " is already defined" Nothing -> putEnv (env { names = M.insert (moduleName, name) (ty, Extern importTy) (names env) }) ds <- typeCheckAll mainModuleName moduleName rest return $ d : ds typeCheckAll mainModuleName moduleName (d@(FixityDeclaration _ name) : rest) = do ds <- typeCheckAll mainModuleName moduleName rest env <- getEnv- guardWith ("Fixity declaration with no binding: " ++ name) $ M.member (moduleName, Op name) $ names env+ guardWith (strMsg ("Fixity declaration with no binding: " ++ name)) $ M.member (moduleName, Op name) $ names env return $ d : ds typeCheckAll mainModuleName currentModule (d@(ImportDeclaration moduleName _ _) : rest) = do env <- getEnv@@ -194,3 +196,7 @@ addTypeClassDictionaries [TypeClassDictionaryInScope (Qualified (Just moduleName) dictName) className tys (Just deps) TCDRegular] ds <- typeCheckAll mainModuleName moduleName rest return $ d : ds+typeCheckAll mainModuleName moduleName (PositionedDeclaration pos d : rest) =+ rethrowWithPosition pos $ do+ (d' : rest') <- typeCheckAll mainModuleName moduleName (d : rest)+ return (PositionedDeclaration pos d' : rest')
src/Language/PureScript/TypeChecker/Kinds.hs view
@@ -14,7 +14,7 @@ ----------------------------------------------------------------------------- {-# OPTIONS_GHC -fno-warn-orphans #-}-{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-} module Language.PureScript.TypeChecker.Kinds ( kindOf,@@ -36,6 +36,7 @@ import Control.Applicative import qualified Data.Map as M+import Data.Monoid ((<>)) instance Partial Kind where unknown = KUnknown@@ -52,14 +53,14 @@ FunKind k1 k2 =?= FunKind k3 k4 = do k1 =?= k3 k2 =?= k4- k1 =?= k2 = UnifyT . lift . throwError $ "Cannot unify " ++ prettyPrintKind k1 ++ " with " ++ prettyPrintKind k2 ++ "."+ k1 =?= k2 = UnifyT . lift . throwError . strMsg $ "Cannot unify " ++ prettyPrintKind k1 ++ " with " ++ prettyPrintKind k2 ++ "." -- | -- Infer the kind of a single type -- kindOf :: ModuleName -> Type -> Check Kind kindOf _ ty =- rethrow (("Error checking kind of " ++ prettyPrintType ty ++ ":\n") ++) $+ rethrow (mkUnifyErrorStack "Error checking kind" (Just (TypeError ty)) <>) $ fmap tidyUp . liftUnify $ starIfUnknown <$> infer ty where tidyUp (k, sub) = sub $? k@@ -105,7 +106,7 @@ -- | -- Solve the set of kind constraints associated with the data constructors for a type constructor ---solveTypes :: Bool -> [Type] -> [Kind] -> Kind -> UnifyT Kind Check Kind+solveTypes :: Bool -> [Type] -> [Kind] -> Kind -> UnifyT Kind (Check) Kind solveTypes isData ts kargs tyCon = do ks <- mapM infer ts when isData $ do@@ -128,39 +129,44 @@ -- Infer a kind for a type -- infer :: Type -> UnifyT Kind Check Kind-infer (TypeVar v) = do+infer ty = rethrow (mkUnifyErrorStack "Error inferring type of value" (Just (TypeError ty)) <>) $ infer' ty++infer' :: Type -> UnifyT Kind Check Kind+infer' (TypeVar v) = do Just moduleName <- checkCurrentModule <$> get UnifyT . lift $ lookupTypeVariable moduleName (Qualified Nothing (ProperName v))-infer (TypeConstructor v) = do+infer' c@(TypeConstructor v) = do env <- liftCheck getEnv case M.lookup v (types env) of- Nothing -> UnifyT . lift . throwError $ "Unknown type constructor '" ++ show v ++ "'"+ Nothing -> UnifyT . lift . throwError $ mkUnifyErrorStack "Unknown type constructor" (Just (TypeError c)) Just (kind, _) -> return kind-infer (TypeApp t1 t2) = do+infer' (TypeApp t1 t2) = do k0 <- fresh k1 <- infer t1 k2 <- infer t2 k1 =?= FunKind k2 k0 return k0-infer (ForAll ident ty _) = do+infer' (ForAll ident ty _) = do k1 <- fresh Just moduleName <- checkCurrentModule <$> get k2 <- bindLocalTypeVariables moduleName [(ProperName ident, k1)] $ infer ty k2 =?= Star return Star-infer REmpty = do+infer' REmpty = do k <- fresh return $ Row k-infer (RCons _ ty row) = do+infer' (RCons _ ty row) = do k1 <- infer ty k2 <- infer row k2 =?= Row k1 return $ Row k1-infer (ConstrainedType deps ty) = do+infer' (ConstrainedType deps ty) = do forM_ deps $ \(className, tys) -> do _ <- infer $ foldl TypeApp (TypeConstructor className) tys return () k <- infer ty k =?= Star return Star-infer _ = error "Invalid argument to infer"+infer' _ = error "Invalid argument to infer"++
src/Language/PureScript/TypeChecker/Monad.hs view
@@ -21,10 +21,14 @@ 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 Data.Maybe+import Data.Monoid import Control.Applicative import Control.Monad.State@@ -32,8 +36,80 @@ 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@@ -89,21 +165,21 @@ -- | -- Lookup the type of a value by name in the @Environment@ ---lookupVariable :: (Functor m, MonadState CheckState m, MonadError String m) => ModuleName -> Qualified Ident -> m Type+lookupVariable :: (Error e, Functor m, MonadState CheckState m, MonadError e m) => ModuleName -> Qualified Ident -> m Type lookupVariable currentModule (Qualified moduleName var) = do env <- getEnv case M.lookup (fromMaybe currentModule moduleName, var) (names env) of- Nothing -> throwError $ show var ++ " is undefined"+ Nothing -> throwError . strMsg $ show var ++ " is undefined" Just (ty, _) -> return ty -- | -- Lookup the kind of a type by name in the @Environment@ ---lookupTypeVariable :: (Functor m, MonadState CheckState m, MonadError String m) => ModuleName -> Qualified ProperName -> m Kind+lookupTypeVariable :: (Error e, Functor m, MonadState CheckState m, MonadError e m) => ModuleName -> Qualified ProperName -> m Kind lookupTypeVariable currentModule (Qualified moduleName name) = do env <- getEnv case M.lookup (Qualified (Just $ fromMaybe currentModule moduleName) name) (types env) of- Nothing -> throwError $ "Type variable " ++ show name ++ " is undefined"+ Nothing -> throwError . strMsg $ "Type variable " ++ show name ++ " is undefined" Just (k, _) -> return k -- |@@ -131,8 +207,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 String) a }- deriving (Functor, Monad, Applicative, MonadPlus, MonadState CheckState, MonadError String)+newtype Check a = Check { unCheck :: StateT CheckState (Either UnifyErrorStack) a }+ deriving (Functor, Monad, Applicative, MonadPlus, MonadState CheckState, MonadError UnifyErrorStack) -- | -- Get the current @Environment@@@ -155,14 +231,14 @@ -- | -- Run a computation in the Check monad, starting with an empty @Environment@ ---runCheck :: Check a -> Either String (a, Environment)-runCheck = runCheck' initEnvironment+runCheck :: Options -> Check a -> Either String (a, Environment)+runCheck opts = runCheck' opts initEnvironment -- | -- Run a computation in the Check monad, failing with an error, or succeeding with a return value and the final @Environment@. ---runCheck' :: Environment -> Check a -> Either String (a, Environment)-runCheck' env c = do+runCheck' :: Options -> Environment -> Check a -> Either String (a, Environment)+runCheck' opts env c = either (Left . prettyPrintUnifyErrorStack opts) Right $ do (a, s) <- flip runStateT (CheckState env 0 0 Nothing) $ unCheck c return (a, checkEnv s) @@ -180,6 +256,12 @@ 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 -- freshDictionaryName :: Check Int@@ -192,7 +274,7 @@ -- Lift a computation in the @Check@ monad into the substitution monad. -- liftCheck :: Check a -> UnifyT t Check a-liftCheck = UnifyT . lift . lift+liftCheck = UnifyT . lift -- | -- Run a computation in the substitution monad, generating a return value and the final substitution.@@ -200,9 +282,7 @@ liftUnify :: (Partial t) => UnifyT t Check a -> Check (a, Substitution t) liftUnify unify = do st <- get- e <- runUnify (defaultUnifyState { unifyNextVar = checkNextVar st }) unify- case e of- Left err -> throwError err- Right (a, ust) -> do- modify $ \st' -> st' { checkNextVar = unifyNextVar ust }- return (a, unifyCurrentSubstitution ust)+ (a, ust) <- runUnify (defaultUnifyState { unifyNextVar = checkNextVar st }) unify+ modify $ \st' -> st' { checkNextVar = unifyNextVar ust }+ return (a, unifyCurrentSubstitution ust)+
src/Language/PureScript/TypeChecker/Types.hs view
@@ -14,6 +14,7 @@ ----------------------------------------------------------------------------- {-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} @@ -70,6 +71,7 @@ import qualified Data.Map as M import Data.Function (on) import Data.Ord (comparing)+import Data.Monoid ((<>)) instance Partial Type where unknown = TUnknown@@ -83,7 +85,7 @@ -- Unify two types, updating the current substitution -- unifyTypes :: Type -> Type -> UnifyT Type Check ()-unifyTypes t1 t2 = rethrow (\e -> "Error unifying type " ++ prettyPrintType t1 ++ " with type " ++ prettyPrintType t2 ++ ":\n" ++ e) $+unifyTypes t1 t2 = rethrow (mkUnifyErrorStack ("Error unifying type " ++ prettyPrintType t1 ++ " with type " ++ prettyPrintType t2) Nothing <>) $ unifyTypes' t1 t2 where unifyTypes' (TUnknown u1) (TUnknown u2) | u1 == u2 = return ()@@ -100,16 +102,16 @@ let sk1 = skolemize ident1 sko sc1' ty1 let sk2 = skolemize ident2 sko sc2' ty2 sk1 `unifyTypes` sk2- _ -> throwError (prettyPrintType ty1)+ _ -> error "Skolemized type variable was not given a scope" unifyTypes' (ForAll ident ty1 (Just sc)) ty2 = do sko <- newSkolemConstant let sk = skolemize ident sko sc ty1 sk `unifyTypes` ty2- unifyTypes' ForAll{} _ = throwError "Skolem variable scope is unspecified"+ unifyTypes' ForAll{} _ = throwError . strMsg $ "Skolem variable scope is unspecified" unifyTypes' ty f@ForAll{} = f `unifyTypes` ty unifyTypes' (TypeVar v1) (TypeVar v2) | v1 == v2 = return () unifyTypes' (TypeConstructor c1) (TypeConstructor c2) =- guardWith ("Cannot unify " ++ show c1 ++ " with " ++ show c2 ++ ".") (c1 == c2)+ guardWith (strMsg ("Cannot unify " ++ show c1 ++ " with " ++ show c2 ++ ".")) (c1 == c2) unifyTypes' (TypeApp t3 t4) (TypeApp t5 t6) = do t3 `unifyTypes` t5 t4 `unifyTypes` t6@@ -118,10 +120,9 @@ unifyTypes' r1 r2@RCons{} = unifyRows r1 r2 unifyTypes' r1@REmpty r2 = unifyRows r1 r2 unifyTypes' r1 r2@REmpty = unifyRows r1 r2- unifyTypes' t@(ConstrainedType _ _) _ = throwError $ "Attempted to unify a constrained type " ++ prettyPrintType t ++- " with another type."+ unifyTypes' t@(ConstrainedType _ _) _ = throwError . strMsg $ "Attempted to unify a constrained type " ++ prettyPrintType t ++ " with another type." unifyTypes' t3 t4@(ConstrainedType _ _) = unifyTypes' t4 t3- unifyTypes' t3 t4 = throwError $ "Cannot unify " ++ prettyPrintType t3 ++ " with " ++ prettyPrintType t4 ++ "."+ unifyTypes' t3 t4 = throwError . strMsg $ "Cannot unify " ++ prettyPrintType t3 ++ " with " ++ prettyPrintType t4 ++ "." -- | -- Unify two rows, updating the current substitution@@ -154,7 +155,7 @@ unifyRows' [] REmpty [] REmpty = return () unifyRows' [] (TypeVar v1) [] (TypeVar v2) | v1 == v2 = return () unifyRows' [] (Skolem s1 _) [] (Skolem s2 _) | s1 == s2 = return ()- unifyRows' sd3 r3 sd4 r4 = throwError $ "Cannot unify (" ++ prettyPrintRow (rowFromList (sd3, r3)) ++ ") with (" ++ prettyPrintRow (rowFromList (sd4, r4)) ++ ")."+ unifyRows' sd3 r3 sd4 r4 = throwError . strMsg $ "Cannot unify (" ++ prettyPrintRow (rowFromList (sd3, r3)) ++ ") with (" ++ prettyPrintRow (rowFromList (sd4, r4)) ++ ")" -- | -- Infer the types of multiple mutually-recursive values, and return elaborated values including@@ -217,7 +218,7 @@ (ident, (val', Just (ty, checkType))) -> do -- Kind check kind <- liftCheck $ kindOf moduleName ty- guardWith ("Expected type of kind *, was " ++ prettyPrintKind kind) $ kind == Star+ guardWith (strMsg $ "Expected type of kind *, was " ++ prettyPrintKind kind) $ kind == Star -- Check the type with the new names in scope ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty val'' <- bindNames dict' $ if checkType@@ -237,6 +238,7 @@ isFunction :: Value -> Bool isFunction (Abs _ _) = True isFunction (TypedValue _ val _) = isFunction val+isFunction (PositionedValue _ val) = isFunction val isFunction _ = False -- |@@ -270,7 +272,7 @@ entails :: Environment -> ModuleName -> [TypeClassDictionaryInScope] -> (Qualified ProperName, [Type]) -> Check Value entails env moduleName context goal@(className, tys) = do case go goal of- [] -> throwError $ "No " ++ show className ++ " instance found for " ++ intercalate ", " (map prettyPrintType tys)+ [] -> throwError . strMsg $ "No " ++ show className ++ " instance found for " ++ intercalate ", " (map prettyPrintType tys) (dict : _) -> return dict where go (className', tys') =@@ -362,7 +364,7 @@ -- an escaped skolem variable. case everythingWithContext [] (++) (mkQ ((,) []) go) root of [] -> return ()- ((binding, val) : _) -> throwError $ "Rigid/skolem type variable bound by " ++ maybe "<unknown>" prettyPrintValue binding ++ " has escaped at " ++ prettyPrintValue val+ ((binding, val) : _) -> throwError $ mkUnifyErrorStack ("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)@@ -381,7 +383,7 @@ where go' val@(TypedValue _ _ (ForAll _ _ (Just sco'))) | sco == sco' = Just val go' _ = Nothing-skolemEscapeCheck val = throwError $ "Untyped value passed to skolemEscapeCheck: " ++ prettyPrintValue val+skolemEscapeCheck val = throwError $ mkUnifyErrorStack "Untyped value passed to skolemEscapeCheck" (Just (ValueError val)) -- | -- Ensure a row contains no duplicate labels@@ -444,10 +446,10 @@ in saturateAllTypeSynonyms syns d -replaceAllTypeSynonyms :: (Functor m, Monad m, MonadState CheckState m, MonadError String m) => (D.Data d) => d -> m d+replaceAllTypeSynonyms :: (Error e, Functor m, Monad m, MonadState CheckState m, MonadError e m) => (D.Data d) => d -> m d replaceAllTypeSynonyms d = do env <- getEnv- either throwError return $ replaceAllTypeSynonyms' env d+ either (throwError . strMsg) return $ replaceAllTypeSynonyms' env d -- | -- \"Desaturate\" @SaturatedTypeSynonym@s@@ -469,12 +471,12 @@ replaceAllTypeSynonyms' env repl Nothing -> error "Type synonym was not defined" -expandTypeSynonym :: (Functor m, Monad m, MonadState CheckState m, MonadError String m) => Qualified ProperName -> [Type] -> m Type+expandTypeSynonym :: (Error e, Functor m, Monad m, MonadState CheckState m, MonadError e m) => Qualified ProperName -> [Type] -> m Type expandTypeSynonym name args = do env <- getEnv- either throwError return $ expandTypeSynonym' env name args+ either (throwError . strMsg) return $ expandTypeSynonym' env name args -expandAllTypeSynonyms :: (Functor m, Monad m, MonadState CheckState m, MonadError String m) => Type -> m Type+expandAllTypeSynonyms :: (Error e, Functor m, Monad m, MonadState CheckState m, MonadError e m) => Type -> m Type expandAllTypeSynonyms = everywhereM' (mkM go) where go (SaturatedTypeSynonym name args) = expandTypeSynonym name args@@ -483,14 +485,14 @@ -- | -- Ensure a set of property names and value does not contain duplicate labels ---ensureNoDuplicateProperties :: (MonadError String m) => [(String, Value)] -> m ()-ensureNoDuplicateProperties ps = guardWith "Duplicate property names" $ length (nub . map fst $ ps) == length ps+ensureNoDuplicateProperties :: (Error e, MonadError e m) => [(String, Value)] -> m ()+ensureNoDuplicateProperties ps = guardWith (strMsg "Duplicate property names") $ length (nub . map fst $ ps) == length ps -- | -- 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 (\e -> "Error inferring type of term " ++ prettyPrintValue val ++ ":\n" ++ e) $ infer' val+infer val = rethrow (mkUnifyErrorStack "Error inferring type of value" (Just (ValueError val)) <>) $ infer' val -- | -- Infer a type for a value@@ -551,7 +553,7 @@ infer' v@(Constructor c) = do env <- getEnv case M.lookup c (dataConstructors env) of- Nothing -> throwError $ "Constructor " ++ show c ++ " is undefined"+ Nothing -> throwError . strMsg $ "Constructor " ++ show c ++ " is undefined" Just (_, ty) -> do ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty return $ TypedValue True v ty' infer' (Case vals binders) = do@@ -571,10 +573,11 @@ infer' (TypedValue checkType val ty) = do Just moduleName <- checkCurrentModule <$> get kind <- liftCheck $ kindOf moduleName ty- guardWith ("Expected type of kind *, was " ++ prettyPrintKind kind) $ kind == Star+ guardWith (strMsg $ "Expected type of kind *, was " ++ prettyPrintKind kind) $ kind == Star ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty val' <- if checkType then check val ty' else return val return $ TypedValue True val' ty'+infer' (PositionedValue pos val) = rethrowWithPosition pos $ infer' val infer' _ = error "Invalid argument to infer" inferLetBinding :: [Declaration] -> [Declaration] -> Value -> (Value -> UnifyT Type Check Value) -> UnifyT Type Check ([Declaration], Value)@@ -592,7 +595,10 @@ (ident, (val', _)) <- typeForBindingGroupElement moduleName e dict untypedDict return $ (ident, LocalVariable, val') bindNames dict $ inferLetBinding (seen ++ [BindingGroupDeclaration ds']) rest ret j-inferLetBinding _ _ _ _ = error "Invalid argument to fromValueDeclaration"+inferLetBinding seen (PositionedDeclaration pos d : ds) ret j = do+ ((d' : ds'), val') <- inferLetBinding seen (d : ds) ret j+ return (PositionedDeclaration pos d' : ds', val')+inferLetBinding _ _ _ _ = error "Invalid argument to inferLetBinding" -- | -- Infer the type of a property inside a record with a given type@@ -631,8 +637,8 @@ return M.empty go (binder : binders') (TypeApp (TypeApp t obj) ret) | t == tyFunction = M.union <$> inferBinder obj binder <*> go binders' ret- go _ _ = throwError $ "Wrong number of arguments to constructor " ++ show ctor- _ -> throwError $ "Constructor " ++ show ctor ++ " is not defined"+ go _ _ = throwError . strMsg $ "Wrong number of arguments to constructor " ++ show ctor+ _ -> throwError . strMsg $ "Constructor " ++ show ctor ++ " is not defined" inferBinder val (ObjectBinder props) = do row <- fresh rest <- fresh@@ -661,6 +667,8 @@ inferBinder val (NamedBinder name binder) = do m <- inferBinder val binder return $ M.insert name val m+inferBinder val (PositionedBinder pos binder) =+ rethrowWithPosition pos $ inferBinder val binder -- | -- Check the types of the return values in a set of binders in a case statement@@ -711,15 +719,13 @@ -- 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 errorMessage $ check' val ty+check val ty = rethrow (mkUnifyErrorStack errorMessage (Just (ValueError val)) <>) $ check' val ty where- errorMessage msg =+ errorMessage = "Error checking type of term " ++ prettyPrintValue val ++ " against type " ++- prettyPrintType ty ++- ":\n" ++- msg+ prettyPrintType ty -- | -- Check the type of a value@@ -773,16 +779,16 @@ ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty v' <- subsumes (Just v) repl ty' case v' of- Nothing -> throwError "Unable to check type subsumption"+ Nothing -> throwError . strMsg $ "Unable to check type subsumption" Just v'' -> return $ TypedValue True v'' ty' check' (TypedValue checkType val ty1) ty2 = do Just moduleName <- checkCurrentModule <$> get kind <- liftCheck $ kindOf moduleName ty1- guardWith ("Expected type of kind *, was " ++ prettyPrintKind kind) $ kind == Star+ guardWith (strMsg $ "Expected type of kind *, was " ++ prettyPrintKind kind) $ kind == Star ty1' <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty1 val' <- subsumes (Just val) ty1' ty2 case val' of- Nothing -> throwError "Unable to check type subsumption"+ Nothing -> throwError . strMsg $ "Unable to check type subsumption" Just val'' -> do val''' <- if checkType then check val'' ty1' else return val'' return $ TypedValue checkType (TypedValue True val''' ty1) ty2@@ -816,7 +822,7 @@ check' (Constructor c) ty = do env <- getEnv case M.lookup c (dataConstructors env) of- Nothing -> throwError $ "Constructor " ++ show c ++ " is undefined"+ Nothing -> throwError . strMsg $ "Constructor " ++ show c ++ " is undefined" Just (_, ty1) -> do repl <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty1 _ <- subsumes Nothing repl ty@@ -827,7 +833,9 @@ check' val ty | containsTypeSynonyms ty = do ty' <- introduceSkolemScope <=< expandAllTypeSynonyms $ ty check val ty'-check' val ty = throwError $ prettyPrintValue val ++ " does not have type " ++ prettyPrintType 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)) containsTypeSynonyms :: Type -> Bool containsTypeSynonyms = everything (||) (mkQ False go) where@@ -846,8 +854,8 @@ return [] go [] [] (Skolem _ _) | lax = return [] go [] ((p, _): _) _ | lax = return []- | otherwise = throwError $ prettyPrintValue (ObjectLiteral ps) ++ " does not have property " ++ p- go ((p,_):_) [] REmpty = throwError $ "Property " ++ p ++ " is not present in closed object type " ++ prettyPrintRow row+ | 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))) go ((p,v):ps') [] u@(TUnknown _) = do v'@(TypedValue _ _ ty) <- infer v rest <- fresh@@ -866,18 +874,17 @@ v' <- check v ty ps'' <- go ps' (delete (p, ty) ts) r return $ (p, v') : ps''- go _ _ _ = throwError $ prettyPrintValue (ObjectLiteral ps) ++ " does not have type " ++ prettyPrintType (TypeApp tyObject row)+ go _ _ _ = throwError $ mkUnifyErrorStack ("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 errorMessage $ checkFunctionApplication' fn fnTy arg ret+checkFunctionApplication fn fnTy arg ret = rethrow (mkUnifyErrorStack errorMessage (Just (ValueError fn)) <>) $ checkFunctionApplication' fn fnTy arg ret where- errorMessage msg = "Error applying function of type "+ errorMessage = "Error applying function of type " ++ prettyPrintType fnTy ++ " to argument " ++ prettyPrintValue arg- ++ ":\n" ++ msg -- | -- Check the type of a function application@@ -907,7 +914,7 @@ checkFunctionApplication' fn (ConstrainedType constraints fnTy) arg ret = do dicts <- getTypeClassDictionaries checkFunctionApplication' (foldl App fn (map (flip TypeClassDictionary dicts) constraints)) fnTy arg ret-checkFunctionApplication' _ fnTy arg _ = throwError $ "Cannot apply a function of type "+checkFunctionApplication' _ fnTy arg _ = throwError . strMsg $ "Cannot apply a function of type " ++ prettyPrintType fnTy ++ " to argument " ++ prettyPrintValue arg @@ -915,13 +922,12 @@ -- 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 errorMessage $ subsumes' val ty1 ty2+subsumes val ty1 ty2 = rethrow (mkUnifyErrorStack errorMessage (ValueError <$> val) <>) $ subsumes' val ty1 ty2 where- errorMessage msg = "Error checking that type "+ errorMessage = "Error checking that type " ++ prettyPrintType ty1 ++ " subsumes type " ++ prettyPrintType ty2- ++ ":\n" ++ msg -- | -- Check whether one type subsumes another@@ -936,7 +942,7 @@ sko <- newSkolemConstant let sk = skolemize ident sko sco' ty2 subsumes val ty1 sk- Nothing -> throwError "Skolem variable scope is unspecified"+ Nothing -> throwError . strMsg $ "Skolem variable scope is unspecified" subsumes' val (TypeApp (TypeApp f1 arg1) ret1) (TypeApp (TypeApp f2 arg2) ret2) | f1 == tyFunction && f2 == tyFunction = do _ <- subsumes Nothing arg2 arg1 _ <- subsumes Nothing ret1 ret2@@ -975,4 +981,5 @@ subsumes' val ty1 ty2 = do ty1 =?= ty2 return val+