git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Merge branch 'master' into pure11
commita193b032688618d857e88007c0fca2220adb3e17 authorAndy Arvanitis <andyarvanitis@gmail.com> dateMon 9 Jan 2017, 13:27 (10 years ago) parenta8df71152ee527
59 files changed+929−412
examples/failing/2534.purs+8 examples/failing/BindInDo-2.purs+9 examples/failing/BindInDo.purs+9 examples/failing/DeclConflictDuplicateCtor.purs+5 examples/passing/StringEdgeCases.purs+9 examples/passing/StringEdgeCases/Records.purs+66 examples/passing/StringEdgeCases/Symbols.purs+30 examples/passing/StringEscapes.purs+1−1 psc-ide-client/Main.hs+2 purescript.cabal+5−2 src/Language/PureScript/AST/Declarations.hs+9−6 src/Language/PureScript/AST/Literals.hs+3−3 src/Language/PureScript/CodeGen/JS.hs+20−14 src/Language/PureScript/CodeGen/JS/AST.hs+5−3 src/Language/PureScript/CodeGen/JS/Optimizer/Common.hs+2−1 src/Language/PureScript/CodeGen/JS/Optimizer/Inliner.hs+1−1 src/Language/PureScript/CodeGen/JS/Optimizer/MagicDo.hs+2−1 src/Language/PureScript/CoreFn/Desugar.hs+3−2 src/Language/PureScript/CoreFn/Expr.hs+3−3 src/Language/PureScript/CoreFn/ToJSON.hs+13−2 src/Language/PureScript/Docs/Convert/ReExports.hs+2−5 src/Language/PureScript/Docs/Convert/Single.hs+4−10 src/Language/PureScript/Docs/ParseAndBookmark.hs+3−7 src/Language/PureScript/Docs/RenderedCode/Render.hs+7−5 src/Language/PureScript/Docs/Types.hs+44−5 src/Language/PureScript/Errors.hs+15−10 src/Language/PureScript/Ide/Conversions.hs−29 src/Language/PureScript/Ide/Util.hs+18−3 src/Language/PureScript/Label.hs+16 src/Language/PureScript/PSString.hs+187 src/Language/PureScript/Parser/Common.hs+7 src/Language/PureScript/Parser/Declarations.hs+9−8 src/Language/PureScript/Parser/Lexer.hs+8−18 src/Language/PureScript/Parser/Types.hs+3−3 src/Language/PureScript/Pretty.hs+1 src/Language/PureScript/Pretty/Common.hs+4−8 src/Language/PureScript/Pretty/JS.hs+10−30 src/Language/PureScript/Pretty/Kinds.hs+14−11 src/Language/PureScript/Pretty/Types.hs+79−33 src/Language/PureScript/Pretty/Values.hs+8−7 src/Language/PureScript/Publish.hs+13−2 src/Language/PureScript/Publish/ErrorsWarnings.hs+4 src/Language/PureScript/Sugar/DoNotation.hs+8−1 src/Language/PureScript/Sugar/Names/Env.hs+6−1 src/Language/PureScript/Sugar/ObjectWildcards.hs+4−4 src/Language/PureScript/Sugar/TypeClasses.hs+4−2 src/Language/PureScript/Sugar/TypeClasses/Deriving.hs+39−24 src/Language/PureScript/TypeChecker/Entailment.hs+6−4 src/Language/PureScript/TypeChecker/Kinds.hs+1 src/Language/PureScript/TypeChecker/Types.hs+146−124 src/Language/PureScript/TypeChecker/Unify.hs+2−1 src/Language/PureScript/Types.hs+6−4 tests/Language/PureScript/Ide/Integration.hs+14−7 tests/Language/PureScript/Ide/MatcherSpec.hs+1−1 tests/TestDocs.hs+7−4 tests/TestPscPublish.hs+3 tests/TestPsci.hs+1−1 tests/TestUtils.hs+19−1 tests/support/bower.json+1
examples/failing/2534.pursnew file+8
@@ -0,0 +1,8 @@
1+-- @shouldFailWith InfiniteType
2+module Main where
3+
4+foo :: Array Int -> Int
5+foo xs = go xs where
6+ go :: Array _ -> Int
7+ go [] = 0
8+ go xs = go [xs]
examples/failing/BindInDo-2.pursnew file+9
@@ -0,0 +1,9 @@
1+-- @shouldFailWith CannotUseBindWithDo
2+module Main where
3+
4+import Prelude
5+
6+foo = do
7+ let bind = 42
8+ x <- [4, 5, 6]
9+ pure x
examples/failing/BindInDo.pursnew file+9
@@ -0,0 +1,9 @@
1+-- @shouldFailWith CannotUseBindWithDo
2+module Main where
3+
4+import Prelude
5+
6+foo = do
7+ bind <- [1,2,3]
8+ x <- [4, 5, 6]
9+ pure x
examples/failing/DeclConflictDuplicateCtor.pursnew file+5
@@ -0,0 +1,5 @@
1+-- @shouldFailWith DeclConflict
2+module Main where
3+
4+data T = Fail | Fail
5+
examples/passing/StringEdgeCases.pursnew file+9
@@ -0,0 +1,9 @@
1+module Main where
2+
3+import Prelude
4+import Records as Records
5+import Symbols as Symbols
6+
7+main = do
8+ Records.main
9+ Symbols.main
examples/passing/StringEdgeCases/Records.pursnew file+66
@@ -0,0 +1,66 @@
1+module Records where
2+
3+import Prelude
4+import Data.Generic (class Generic, toSpine, GenericSpine(..))
5+import Control.Monad.Eff.Console (log)
6+import Test.Assert (assert')
7+
8+newtype AstralKeys = AstralKeys { "💡" :: Int, "💢" :: Int }
9+newtype LoneSurrogateKeys = LoneSurrogateKeys { "\xdf06" :: Int, "\xd834" :: Int }
10+
11+derive instance genericAstralKeys :: Generic AstralKeys
12+derive instance genericLoneSurrogateKeys :: Generic LoneSurrogateKeys
13+
14+spineOf :: forall a. Generic a => a -> Unit -> GenericSpine
15+spineOf x _ = toSpine x
16+
17+testLoneSurrogateKeys =
18+ let
19+ expected = 5
20+ actual = (_."\xd801" <<< helper) { "\xd800": 5 }
21+ in
22+ assert' ("lone surrogate keys: " <> show actual) (expected == actual)
23+
24+ where
25+ helper :: { "\xd800" :: Int } -> { "\xd801" :: Int }
26+ helper o =
27+ case o."\xd800" of
28+ x -> { "\xd801": x }
29+
30+testAstralKeys =
31+ let
32+ expected = 5
33+ actual = (_."💢" <<< helper) { "💡": 5 }
34+ in
35+ assert' ("astral keys: " <> show actual) (expected == actual)
36+
37+ where
38+ helper :: { "💡" :: Int } -> { "💢" :: Int }
39+ helper o =
40+ case o."💡" of
41+ x -> { "💢": x }
42+
43+testGenericLoneSurrogateKeys = do
44+ let expected = SProd "Records.LoneSurrogateKeys"
45+ [ \_ -> SRecord [ {recLabel: "\xd834", recValue: spineOf 1}
46+ , {recLabel: "\xdf06", recValue: spineOf 0}
47+ ]
48+ ]
49+ actual = toSpine (LoneSurrogateKeys { "\xdf06": 0, "\xd834": 1 })
50+ assert' ("generic lone surrogate keys: " <> show actual) (expected == actual)
51+
52+testGenericAstralKeys = do
53+ let expected = SProd "Records.AstralKeys"
54+ [ \_ -> SRecord [ {recLabel: "💡", recValue: spineOf 0}
55+ , {recLabel: "💢", recValue: spineOf 1}
56+ ]
57+ ]
58+ actual = toSpine (AstralKeys { "💡": 0, "💢": 1 })
59+ assert' ("generic astral keys: " <> show actual) (expected == actual)
60+
61+main = do
62+ testLoneSurrogateKeys
63+ testAstralKeys
64+ testGenericLoneSurrogateKeys
65+ testGenericAstralKeys
66+ log "Done"
examples/passing/StringEdgeCases/Symbols.pursnew file+30
@@ -0,0 +1,30 @@
1+-- This is similar to StringEscapes except we are performing the same tests
2+-- with Symbols (at the type level).
3+
4+module Symbols where
5+
6+import Prelude
7+import Control.Monad.Eff.Console (log)
8+import Type.Data.Symbol (SProxy(..), class AppendSymbol, appendSymbol, reflectSymbol)
9+import Test.Assert (assert')
10+
11+highS :: SProxy "\xd834"
12+highS = SProxy
13+
14+lowS :: SProxy "\xdf06"
15+lowS = SProxy
16+
17+loneSurrogates :: Boolean
18+loneSurrogates = reflectSymbol (appendSymbol highS lowS) == "\x1d306"
19+
20+outOfOrderSurrogates :: Boolean
21+outOfOrderSurrogates = reflectSymbol (appendSymbol lowS highS) == "\xdf06\xd834"
22+
23+notReplacing :: Boolean
24+notReplacing = reflectSymbol lowS /= "\xfffd"
25+
26+main = do
27+ assert' "lone surrogates may be combined into a surrogate pair" loneSurrogates
28+ assert' "lone surrogates may be combined out of order to remain lone surrogates" outOfOrderSurrogates
29+ assert' "lone surrogates are not replaced with the Unicode replacement character U+FFFD" notReplacing
30+ log "Done"
examples/passing/StringEscapes.purs+1−1
@@ -22,5 +22,5 @@ main = do
2222 assert' "astral code points are represented as a UTF-16 surrogate pair" surrogatePair
2323 assert' "lone surrogates may be combined into a surrogate pair" loneSurrogates
2424 assert' "lone surrogates may be combined out of order to remain lone surrogates" outOfOrderSurrogates
25− -- assert' "lone surrogates are not replaced with the Unicode replacement character U+FFFD" notReplacing
25+ assert' "lone surrogates are not replaced with the Unicode replacement character U+FFFD" notReplacing
2626 log "Done"
psc-ide-client/Main.hs+2
@@ -35,6 +35,8 @@ main = do
3535
3636client :: PortID -> IO ()
3737client port = do
38+ hSetEncoding stdin utf8
39+ hSetEncoding stdout utf8
3840 h <-
3941 connectTo "127.0.0.1" port `catch`
4042 (\(SomeException e) ->
purescript.cabal+5−2
@@ -1,5 +1,5 @@
11name: purescript
2−version: 0.10.4
2+version: 0.10.5
33cabal-version: >=1.8
44build-type: Simple
55license: BSD3
@@ -54,6 +54,7 @@ extra-source-files: examples/passing/*.purs
5454 , examples/passing/ResolvableScopeConflict3/*.purs
5555 , examples/passing/ShadowedModuleName/*.purs
5656 , examples/passing/SolvingIsSymbol/*.purs
57+ , examples/passing/StringEdgeCases/*.purs
5758 , examples/passing/TransitiveImport/*.purs
5859 , examples/passing/TypeOperators/*.purs
5960 , examples/passing/TypeWithoutParens/*.purs
@@ -151,6 +152,7 @@ library
151152 protolude >= 0.1.6,
152153 regex-tdfa -any,
153154 safe >= 0.3.9 && < 0.4,
155+ scientific >= 0.3.4.9 && < 0.4,
154156 semigroups >= 0.16.2 && < 0.19,
155157 sourcemap >= 0.1.6,
156158 spdx == 0.2.*,
@@ -221,6 +223,7 @@ library
221223 Language.PureScript.Errors
222224 Language.PureScript.Errors.JSON
223225 Language.PureScript.Kinds
226+ Language.PureScript.Label
224227 Language.PureScript.Linter
225228 Language.PureScript.Linter.Exhaustive
226229 Language.PureScript.Linter.Imports
@@ -241,6 +244,7 @@ library
241244 Language.PureScript.Pretty.Kinds
242245 Language.PureScript.Pretty.Types
243246 Language.PureScript.Pretty.Values
247+ Language.PureScript.PSString
244248 Language.PureScript.Renamer
245249 Language.PureScript.Sugar
246250 Language.PureScript.Sugar.BindingGroups
@@ -298,7 +302,6 @@ library
298302 Language.PureScript.Ide.CaseSplit
299303 Language.PureScript.Ide.Command
300304 Language.PureScript.Ide.Completion
301− Language.PureScript.Ide.Conversions
302305 Language.PureScript.Ide.Externs
303306 Language.PureScript.Ide.Error
304307 Language.PureScript.Ide.Filter
src/Language/PureScript/AST/Declarations.hs+9−6
@@ -18,6 +18,8 @@ import Language.PureScript.AST.Literals
1818import Language.PureScript.AST.Operators
1919import Language.PureScript.AST.SourcePos
2020import Language.PureScript.Types
21+import Language.PureScript.PSString (PSString)
22+import Language.PureScript.Label (Label)
2123import Language.PureScript.Names
2224import Language.PureScript.Kinds
2325import Language.PureScript.TypeClassDictionaries
@@ -90,7 +92,7 @@ data SimpleErrorMessage
9092 | CannotDerive (Qualified (ProperName 'ClassName)) [Type]
9193 | InvalidNewtypeInstance (Qualified (ProperName 'ClassName)) [Type]
9294 | CannotFindDerivingType (ProperName 'TypeName)
93− | DuplicateLabel Text (Maybe Expr)
95+ | DuplicateLabel Label (Maybe Expr)
9496 | DuplicateValueDeclaration Ident
9597 | ArgListLengthsDiffer Ident
9698 | OverlappingArgNames (Maybe Ident)
@@ -99,8 +101,8 @@ data SimpleErrorMessage
99101 | ExpectedType Type Kind
100102 | IncorrectConstructorArity (Qualified (ProperName 'ConstructorName))
101103 | ExprDoesNotHaveType Expr Type
102− | PropertyIsMissing Text
103− | AdditionalProperty Text
104+ | PropertyIsMissing Label
105+ | AdditionalProperty Label
104106 | TypeSynonymInstance
105107 | OrphanInstance Ident (Qualified (ProperName 'ClassName)) [Type]
106108 | InvalidNewtype (ProperName 'TypeName)
@@ -136,6 +138,7 @@ data SimpleErrorMessage
136138 | CannotGeneralizeRecursiveFunction Ident Type
137139 | CannotDeriveNewtypeForData (ProperName 'TypeName)
138140 | ExpectedWildcard (ProperName 'TypeName)
141+ | CannotUseBindWithDo
139142 deriving (Show)
140143
141144-- | Error message hints, providing more detailed information about failure.
@@ -145,7 +148,7 @@ data ErrorMessageHint
145148 | ErrorInModule ModuleName
146149 | ErrorInInstance (Qualified (ProperName 'ClassName)) [Type]
147150 | ErrorInSubsumption Type Type
148− | ErrorCheckingAccessor Expr Text
151+ | ErrorCheckingAccessor Expr PSString
149152 | ErrorCheckingType Expr Type
150153 | ErrorCheckingKind Type
151154 | ErrorCheckingGuard
@@ -573,11 +576,11 @@ data Expr
573576 -- Anonymous arguments will be removed during desugaring and expanded
574577 -- into a lambda that reads a property from a record.
575578 --
576− | Accessor Text Expr
579+ | Accessor PSString Expr
577580 -- |
578581 -- Partial record update
579582 --
580− | ObjectUpdate Expr [(Text, Expr)]
583+ | ObjectUpdate Expr [(PSString, Expr)]
581584 -- |
582585 -- Function introduction
583586 --
src/Language/PureScript/AST/Literals.hs+3−3
@@ -4,7 +4,7 @@
44module Language.PureScript.AST.Literals where
55
66import Prelude.Compat
7−import Data.Text (Text)
7+import Language.PureScript.PSString (PSString)
88
99-- |
1010-- Data type for literal values. Parameterised so it can be used for Exprs and
@@ -18,7 +18,7 @@ data Literal a
1818 -- |
1919 -- A string literal
2020 --
21− | StringLiteral Text
21+ | StringLiteral PSString
2222 -- |
2323 -- A character literal
2424 --
@@ -34,5 +34,5 @@ data Literal a
3434 -- |
3535 -- An object literal
3636 --
37− | ObjectLiteral [(Text, a)]
37+ | ObjectLiteral [(PSString, a)]
3838 deriving (Eq, Ord, Show, Functor)
src/Language/PureScript/CodeGen/JS.hs+20−14
@@ -20,6 +20,7 @@ import qualified Data.Foldable as F
2020import qualified Data.Map as M
2121import Data.Maybe (fromMaybe, isNothing)
2222import Data.Monoid ((<>))
23+import Data.String (fromString)
2324import Data.Text (Text)
2425import qualified Data.Text as T
2526
@@ -34,6 +35,7 @@ import Language.PureScript.Errors (ErrorMessageHint(..), SimpleErrorMessage(..),
3435 errorMessage, rethrowWithPosition, addHint)
3536import Language.PureScript.Names
3637import Language.PureScript.Options
38+import Language.PureScript.PSString (PSString, mkString, decodeString)
3739import Language.PureScript.Traversals (sndM)
3840import qualified Language.PureScript.Constants as C
3941
@@ -65,8 +67,8 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
6567 let moduleBody = header : foreign' ++ jsImports ++ concat optimized
6668 let foreignExps = exps `intersect` (fst `map` foreigns)
6769 let standardExps = exps \\ foreignExps
68− let exps' = JSObjectLiteral Nothing $ map (runIdent &&& JSVar Nothing . identToJs) standardExps
69− ++ map (runIdent &&& foreignIdent) foreignExps
70+ let exps' = JSObjectLiteral Nothing $ map (mkString . runIdent &&& JSVar Nothing . identToJs) standardExps
71+ ++ map (mkString . runIdent &&& foreignIdent) foreignExps
7072 return $ moduleBody ++ [JSAssignment Nothing (JSAccessor Nothing "exports" (JSVar Nothing "module")) exps']
7173
7274 where
@@ -108,7 +110,7 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
108110 importToJs :: M.Map ModuleName (Ann, ModuleName) -> ModuleName -> m JS
109111 importToJs mnLookup mn' = do
110112 let ((ss, _, _, _), mnSafe) = fromMaybe (internalError "Missing value in mnLookup") $ M.lookup mn' mnLookup
111− let moduleBody = JSApp Nothing (JSVar Nothing "require") [JSStringLiteral Nothing (T.pack (".." </> T.unpack (runModuleName mn')))]
113+ let moduleBody = JSApp Nothing (JSVar Nothing "require") [JSStringLiteral Nothing (fromString (".." </> T.unpack (runModuleName mn')))]
112114 withPos ss $ JSVariableIntroduction Nothing (moduleNameToJs mnSafe) (Just moduleBody)
113115
114116 -- |
@@ -176,12 +178,16 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
176178 -- indexer is returned.
177179 --
178180 accessor :: Ident -> JS -> JS
179− accessor (Ident prop) = accessorString prop
181+ accessor (Ident prop) = accessorString $ mkString prop
180182 accessor (GenIdent _ _) = internalError "GenIdent in accessor"
181183
182− accessorString :: Text -> JS -> JS
183− accessorString prop | identNeedsEscaping prop = JSIndexer Nothing (JSStringLiteral Nothing prop)
184− | otherwise = JSAccessor Nothing prop
184+ accessorString :: PSString -> JS -> JS
185+ accessorString prop =
186+ case decodeString prop of
187+ Just s | not (identNeedsEscaping s) ->
188+ JSAccessor Nothing s
189+ _ ->
190+ JSIndexer Nothing (JSStringLiteral Nothing prop)
185191
186192 -- |
187193 -- Generate code in the simplified Javascript intermediate representation for a value or expression.
@@ -212,7 +218,7 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
212218 unAbs (Abs _ arg val) = arg : unAbs val
213219 unAbs _ = []
214220 assign :: Ident -> JS
215− assign name = JSAssignment Nothing (accessorString (runIdent name) (JSVar Nothing "this"))
221+ assign name = JSAssignment Nothing (accessorString (mkString $ runIdent name) (JSVar Nothing "this"))
216222 (var name)
217223 valueToJs' (Abs _ arg val) = do
218224 ret <- valueToJs val
@@ -272,7 +278,7 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
272278 literalToValueJS (NumericLiteral (Left i)) = return $ JSNumericLiteral Nothing (Left i)
273279 literalToValueJS (NumericLiteral (Right n)) = return $ JSNumericLiteral Nothing (Right n)
274280 literalToValueJS (StringLiteral s) = return $ JSStringLiteral Nothing s
275− literalToValueJS (CharLiteral c) = return $ JSStringLiteral Nothing (T.singleton c)
281+ literalToValueJS (CharLiteral c) = return $ JSStringLiteral Nothing (fromString [c])
276282 literalToValueJS (BooleanLiteral b) = return $ JSBooleanLiteral Nothing b
277283 literalToValueJS (ArrayLiteral xs) = JSArrayLiteral Nothing <$> mapM valueToJs xs
278284 literalToValueJS (ObjectLiteral ps) = JSObjectLiteral Nothing <$> mapM (sndM valueToJs) ps
@@ -280,7 +286,7 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
280286 -- |
281287 -- Shallow copy an object.
282288 --
283− extendObj :: JS -> [(Text, JS)] -> m JS
289+ extendObj :: JS -> [(PSString, JS)] -> m JS
284290 extendObj obj sts = do
285291 newObj <- freshName
286292 key <- freshName
@@ -317,7 +323,7 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
317323 qualifiedToJS f (Qualified _ a) = JSVar Nothing $ identToJs (f a)
318324
319325 foreignIdent :: Ident -> JS
320− foreignIdent ident = accessorString (runIdent ident) (JSVar Nothing "$foreign")
326+ foreignIdent ident = accessorString (mkString $ runIdent ident) (JSVar Nothing "$foreign")
321327
322328 -- |
323329 -- Generate code in the simplified Javascript intermediate representation for pattern match binders
@@ -341,7 +347,7 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
341347 go _ _ _ = internalError "Invalid arguments to bindersToJs"
342348
343349 failedPatternError :: [Text] -> JS
344− failedPatternError names = JSUnary Nothing JSNew $ JSApp Nothing (JSVar Nothing "Error") [JSBinary Nothing Add (JSStringLiteral Nothing failedPatternMessage) (JSArrayLiteral Nothing $ zipWith valueError names vals)]
350+ failedPatternError names = JSUnary Nothing JSNew $ JSApp Nothing (JSVar Nothing "Error") [JSBinary Nothing Add (JSStringLiteral Nothing $ mkString failedPatternMessage) (JSArrayLiteral Nothing $ zipWith valueError names vals)]
345351
346352 failedPatternMessage :: Text
347353 failedPatternMessage = "Failed pattern match" <> maybe "" (((" at " <> runModuleName mn <> " ") <>) . displayStartEndPos) maybeSpan <> ": "
@@ -402,7 +408,7 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
402408 literalToBinderJS varName done (NumericLiteral num) =
403409 return [JSIfElse Nothing (JSBinary Nothing EqualTo (JSVar Nothing varName) (JSNumericLiteral Nothing num)) (JSBlock Nothing done) Nothing]
404410 literalToBinderJS varName done (CharLiteral c) =
405− return [JSIfElse Nothing (JSBinary Nothing EqualTo (JSVar Nothing varName) (JSStringLiteral Nothing (T.singleton c))) (JSBlock Nothing done) Nothing]
411+ return [JSIfElse Nothing (JSBinary Nothing EqualTo (JSVar Nothing varName) (JSStringLiteral Nothing (fromString [c]))) (JSBlock Nothing done) Nothing]
406412 literalToBinderJS varName done (StringLiteral str) =
407413 return [JSIfElse Nothing (JSBinary Nothing EqualTo (JSVar Nothing varName) (JSStringLiteral Nothing str)) (JSBlock Nothing done) Nothing]
408414 literalToBinderJS varName done (BooleanLiteral True) =
@@ -411,7 +417,7 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
411417 return [JSIfElse Nothing (JSUnary Nothing Not (JSVar Nothing varName)) (JSBlock Nothing done) Nothing]
412418 literalToBinderJS varName done (ObjectLiteral bs) = go done bs
413419 where
414− go :: [JS] -> [(Text, Binder Ann)] -> m [JS]
420+ go :: [JS] -> [(PSString, Binder Ann)] -> m [JS]
415421 go done' [] = return done'
416422 go done' ((prop, binder):bs') = do
417423 propVar <- freshName
src/Language/PureScript/CodeGen/JS/AST.hs+5−3
@@ -11,6 +11,7 @@ import Data.Text (Text)
1111
1212import Language.PureScript.AST (SourceSpan(..))
1313import Language.PureScript.Comments
14+import Language.PureScript.PSString (PSString)
1415import Language.PureScript.Traversals
1516
1617-- |
@@ -132,7 +133,7 @@ data JS
132133 -- |
133134 -- A string literal
134135 --
135− | JSStringLiteral (Maybe SourceSpan) Text
136+ | JSStringLiteral (Maybe SourceSpan) PSString
136137 -- |
137138 -- A boolean literal
138139 --
@@ -156,7 +157,7 @@ data JS
156157 -- |
157158 -- An object literal
158159 --
159− | JSObjectLiteral (Maybe SourceSpan) [(Text, JS)]
160+ | JSObjectLiteral (Maybe SourceSpan) [(PSString, JS)]
160161 -- |
161162 -- An object property accessor expression
162163 --
@@ -240,7 +241,8 @@ data JS
240241 -- |
241242 -- Commented Javascript
242243 --
243− | JSComment (Maybe SourceSpan) [Comment] JS deriving (Show, Eq)
244+ | JSComment (Maybe SourceSpan) [Comment] JS
245+ deriving (Show, Eq)
244246
245247withSourceSpan :: SourceSpan -> JS -> JS
246248withSourceSpan withSpan = go
src/Language/PureScript/CodeGen/JS/Optimizer/Common.hs+2−1
@@ -11,6 +11,7 @@ import Data.Maybe (fromMaybe)
1111
1212import Language.PureScript.Crash
1313import Language.PureScript.CodeGen.JS.AST
14+import Language.PureScript.PSString (mkString)
1415
1516applyAll :: [a -> a] -> a -> a
1617applyAll = foldl' (.) id
@@ -73,7 +74,7 @@ isFn :: (Text, Text) -> JS -> Bool
7374isFn (moduleName, fnName) (JSAccessor _ x (JSVar _ y)) =
7475 x == fnName && y == moduleName
7576isFn (moduleName, fnName) (JSIndexer _ (JSStringLiteral _ x) (JSVar _ y)) =
76− x == fnName && y == moduleName
77+ x == mkString fnName && y == moduleName
7778isFn _ _ = False
7879
7980isDict :: (Text, Text) -> JS -> Bool
src/Language/PureScript/CodeGen/JS/Optimizer/Inliner.hs+1−1
@@ -239,7 +239,7 @@ inlineCommonOperators = applyAll $
239239 isModFn _ _ = False
240240
241241 isModFnWithDict :: (Text, Text) -> JS -> Bool
242− isModFnWithDict (m, op) (JSApp _ (JSAccessor _ op' (JSVar _ m')) [(JSVar _ _)]) = m == m' && op == op'
242+ isModFnWithDict (m, op) (JSApp _ (JSAccessor _ op' (JSVar _ m')) [JSVar _ _]) = m == m' && op == op'
243243 isModFnWithDict _ _ = False
244244
245245-- (f <<< g $ x) = f (g x)
src/Language/PureScript/CodeGen/JS/Optimizer/MagicDo.hs+2−1
@@ -12,6 +12,7 @@ import Data.Maybe (fromJust, isJust)
1212import Language.PureScript.CodeGen.JS.AST
1313import Language.PureScript.CodeGen.JS.Optimizer.Common
1414import Language.PureScript.Options
15+import Language.PureScript.PSString (mkString)
1516import qualified Language.PureScript.Constants as C
1617
1718magicDo :: Options -> JS -> JS
@@ -104,7 +105,7 @@ inlineST = everywhereOnJS convertBlock
104105 -- or in a more aggressive way, turning wrappers into local variables depending on the
105106 -- agg(ressive) parameter.
106107 convert agg (JSApp s1 f [arg]) | isSTFunc C.newSTRef f =
107− JSFunction s1 Nothing [] (JSBlock s1 [JSReturn s1 $ if agg then arg else JSObjectLiteral s1 [(C.stRefValue, arg)]])
108+ JSFunction s1 Nothing [] (JSBlock s1 [JSReturn s1 $ if agg then arg else JSObjectLiteral s1 [(mkString C.stRefValue, arg)]])
108109 convert agg (JSApp _ (JSApp s1 f [ref]) []) | isSTFunc C.readSTRef f =
109110 if agg then ref else JSAccessor s1 C.stRefValue ref
110111 convert agg (JSApp _ (JSApp _ (JSApp s1 f [ref]) [arg]) []) | isSTFunc C.writeSTRef f =
src/Language/PureScript/CoreFn/Desugar.hs+3−2
@@ -24,6 +24,7 @@ import Language.PureScript.Environment
2424import Language.PureScript.Names
2525import Language.PureScript.Sugar.TypeClasses (typeClassMemberName, superClassDictionaryNames)
2626import Language.PureScript.Types
27+import Language.PureScript.PSString (mkString)
2728import qualified Language.PureScript.AST as A
2829
2930-- |
@@ -119,7 +120,7 @@ moduleToCoreFn env (A.Module _ coms mn decls (Just exps)) =
119120 in foldl (App (ss, com, Nothing, Nothing)) ctor args
120121 exprToCoreFn ss com ty (A.TypeClassDictionaryAccessor _ ident) =
121122 Abs (ss, com, ty, Nothing) (Ident "dict")
122− (Accessor nullAnn (runIdent ident) (Var nullAnn $ Qualified Nothing (Ident "dict")))
123+ (Accessor nullAnn (mkString $ runIdent ident) (Var nullAnn $ Qualified Nothing (Ident "dict")))
123124 exprToCoreFn _ com ty (A.PositionedValue ss com1 v) =
124125 exprToCoreFn (Just ss) (com ++ com1) ty v
125126 exprToCoreFn _ _ _ e =
@@ -265,7 +266,7 @@ mkTypeClassConstructor :: Maybe SourceSpan -> [Comment] -> [Constraint] -> [A.De
265266mkTypeClassConstructor ss com [] [] = Literal (ss, com, Nothing, Just IsTypeClassConstructor) (ObjectLiteral [])
266267mkTypeClassConstructor ss com supers members =
267268 let args@(a:as) = sort $ map typeClassMemberName members ++ superClassDictionaryNames supers
268− props = [ (arg, Var nullAnn $ Qualified Nothing (Ident arg)) | arg <- args ]
269+ props = [ (mkString arg, Var nullAnn $ Qualified Nothing (Ident arg)) | arg <- args ]
269270 dict = Literal nullAnn (ObjectLiteral props)
270271 in Abs (ss, com, Nothing, Just IsTypeClassConstructor)
271272 (Ident a)
src/Language/PureScript/CoreFn/Expr.hs+3−3
@@ -6,11 +6,11 @@ module Language.PureScript.CoreFn.Expr where
66import Prelude.Compat
77
88import Control.Arrow ((***))
9−import Data.Text (Text)
109
1110import Language.PureScript.AST.Literals
1211import Language.PureScript.CoreFn.Binders
1312import Language.PureScript.Names
13+import Language.PureScript.PSString (PSString)
1414
1515-- |
1616-- Data type for expressions and terms
@@ -27,11 +27,11 @@ data Expr a
2727 -- |
2828 -- A record property accessor
2929 --
30− | Accessor a Text (Expr a)
30+ | Accessor a PSString (Expr a)
3131 -- |
3232 -- Partial record update
3333 --
34− | ObjectUpdate a (Expr a) [(Text, Expr a)]
34+ | ObjectUpdate a (Expr a) [(PSString, Expr a)]
3535 -- |
3636 -- Function introduction
3737 --
src/Language/PureScript/CoreFn/ToJSON.hs+13−2
@@ -9,6 +9,7 @@ module Language.PureScript.CoreFn.ToJSON
99
1010import Prelude.Compat
1111
12+import Data.Maybe (fromMaybe)
1213import Data.Aeson
1314import Data.Version (Version, showVersion)
1415import Data.Text (Text)
@@ -17,6 +18,7 @@ import qualified Data.Text as T
1718import Language.PureScript.AST.Literals
1819import Language.PureScript.CoreFn
1920import Language.PureScript.Names
21+import Language.PureScript.PSString (PSString, decodeString)
2022
2123literalToJSON :: (a -> Value) -> Literal a -> Value
2224literalToJSON _ (NumericLiteral (Left n)) = toJSON ("IntLiteral", n)
@@ -51,8 +53,17 @@ bindToJSON :: Bind a -> Value
5153bindToJSON (NonRec _ n e) = object [ runIdent n .= exprToJSON e ]
5254bindToJSON (Rec bs) = object $ map (\((_, n), e) -> runIdent n .= exprToJSON e) bs
5355
54−recordToJSON :: (a -> Value) -> [(Text, a)] -> Value
55−recordToJSON f = object . map (\(label, a) -> label .= f a)
56+-- If all of the labels in the record can safely be converted to JSON strings,
57+-- we generate a JSON object. Otherwise the labels must be represented as
58+-- arrays of integers in the JSON, and in this case we generate the record as
59+-- an array of pairs.
60+recordToJSON :: (a -> Value) -> [(PSString, a)] -> Value
61+recordToJSON f rec = fromMaybe (asArrayOfPairs rec) (asObject rec)
62+ where
63+ asObject = fmap object . traverse (uncurry maybePair)
64+ maybePair label a = fmap (\l -> l .= f a) (decodeString label)
65+
66+ asArrayOfPairs = toJSON . map (\(label, a) -> (toJSON label, f a))
5667
5768exprToJSON :: Expr a -> Value
5869exprToJSON (Var _ i) = toJSON ( "Var"
src/Language/PureScript/Docs/Convert/ReExports.hs+2−5
@@ -457,11 +457,8 @@ handleEnv TypeClassEnv{..} =
457457 addConstraint constraint =
458458 P.quantify . P.moveQuantifiersToFront . P.ConstrainedType [constraint]
459459
460−splitMap :: (Ord k) => Map k (v1, v2) -> (Map k v1, Map k v2)
461−splitMap = foldl go (Map.empty, Map.empty) . Map.toList
462− where
463− go (m1, m2) (k, (v1, v2)) =
464− (Map.insert k v1 m1, Map.insert k v2 m2)
460+splitMap :: Map k (v1, v2) -> (Map k v1, Map k v2)
461+splitMap = fmap fst &&& fmap snd
465462
466463-- |
467464-- Given a list of exported constructor names, remove any data constructor
src/Language/PureScript/Docs/Convert/Single.hs+4−10
@@ -3,16 +3,10 @@ module Language.PureScript.Docs.Convert.Single
33 , collectBookmarks
44 ) where
55
6−import Prelude.Compat
6+import Protolude
77
88import Control.Category ((>>>))
9−import Control.Monad
109
11−import Data.Either
12−import Data.List (nub)
13−import Data.Maybe (mapMaybe, fromMaybe)
14−import Data.Monoid ((<>))
15−import Data.Text (Text)
1610import qualified Data.Text as T
1711
1812import Language.PureScript.Docs.Types
@@ -67,7 +61,7 @@ data DeclarationAugment
6761-- the type synonym IntermediateDeclaration for more information.
6862augmentDeclarations :: [IntermediateDeclaration] -> [Declaration]
6963augmentDeclarations (partitionEithers -> (augments, toplevels)) =
70− foldl go toplevels augments
64+ foldl' go toplevels augments
7165 where
7266 go ds (parentTitles, a) =
7367 map (\d ->
@@ -142,14 +136,14 @@ convertDeclaration (P.TypeInstanceDeclaration _ constraints className tys _) tit
142136 Just (Left (classNameString : typeNameStrings, AugmentChild childDecl))
143137 where
144138 classNameString = unQual className
145− typeNameStrings = nub (concatMap (P.everythingOnTypes (++) extractProperNames) tys)
139+ typeNameStrings = ordNub (concatMap (P.everythingOnTypes (++) extractProperNames) tys)
146140 unQual x = let (P.Qualified _ y) = x in P.runProperName y
147141
148142 extractProperNames (P.TypeConstructor n) = [unQual n]
149143 extractProperNames _ = []
150144
151145 childDecl = ChildDeclaration title Nothing Nothing (ChildInstance constraints classApp)
152− classApp = foldl P.TypeApp (P.TypeConstructor (fmap P.coerceProperName className)) tys
146+ classApp = foldl' P.TypeApp (P.TypeConstructor (fmap P.coerceProperName className)) tys
153147convertDeclaration (P.ValueFixityDeclaration fixity (P.Qualified mn alias) _) title =
154148 Just $ Right $ mkDeclaration title (AliasDeclaration fixity (P.Qualified mn (Right alias)))
155149convertDeclaration (P.TypeFixityDeclaration fixity (P.Qualified mn alias) _) title =
src/Language/PureScript/Docs/ParseAndBookmark.hs+3−7
@@ -2,14 +2,10 @@ module Language.PureScript.Docs.ParseAndBookmark
22 ( parseAndBookmark
33 ) where
44
5−import Prelude.Compat
6−
7−import Control.Arrow (first)
8−import Control.Monad.Error.Class (MonadError(..))
9−import Control.Monad.IO.Class (MonadIO(..))
5+import Protolude
6+import Prelude (id)
107
118import qualified Data.Map as M
12−import Data.Text (Text)
139
1410import Language.PureScript.Docs.Convert (collectBookmarks)
1511import Language.PureScript.Docs.Types
@@ -83,7 +79,7 @@ parseAs :: (MonadIO m) => (FilePath -> a) -> FilePath -> m (a, Text)
8379parseAs g = fmap (first g) . liftIO . parseFile
8480
8581getDepsModuleNames :: [InPackage (FilePath, P.Module)] -> M.Map P.ModuleName PackageName
86−getDepsModuleNames = foldl go M.empty
82+getDepsModuleNames = foldl' go M.empty
8783 where
8884 go deps p = deps # case p of
8985 Local _ -> id
src/Language/PureScript/Docs/RenderedCode/Render.hs+7−5
@@ -26,7 +26,9 @@ import Language.PureScript.Environment
2626import Language.PureScript.Kinds
2727import Language.PureScript.Names
2828import Language.PureScript.Pretty.Kinds
29+import Language.PureScript.Pretty.Types
2930import Language.PureScript.Types
31+import Language.PureScript.Label (Label)
3032
3133typeLiterals :: Pattern () Type RenderedCode
3234typeLiterals = mkPattern match
@@ -79,13 +81,13 @@ renderRow = uncurry renderRow' . rowToList
7981 where
8082 renderRow' h t = renderHead h <> renderTail t
8183
82−renderHead :: [(Text, Type)] -> RenderedCode
84+renderHead :: [(Label, Type)] -> RenderedCode
8385renderHead = mintersperse (syntax "," <> sp) . map renderLabel
8486
85−renderLabel :: (Text, Type) -> RenderedCode
87+renderLabel :: (Label, Type) -> RenderedCode
8688renderLabel (label, ty) =
8789 mintersperse sp
88− [ ident label
90+ [ syntax $ prettyPrintLabel label
8991 , syntax "::"
9092 , renderType ty
9193 ]
@@ -125,9 +127,9 @@ explicitParens = mkPattern match
125127 match _ = Nothing
126128
127129matchTypeAtom :: Pattern () Type RenderedCode
128−matchTypeAtom = typeLiterals <+> fmap parens matchType
130+matchTypeAtom = typeLiterals <+> fmap parens_ matchType
129131 where
130− parens x = syntax "(" <> x <> syntax ")"
132+ parens_ x = syntax "(" <> x <> syntax ")"
131133
132134matchType :: Pattern () Type RenderedCode
133135matchType = buildPrettyPrinter operators matchTypeAtom
src/Language/PureScript/Docs/Types.hs+44−5
@@ -10,17 +10,19 @@ import Control.Arrow (first, (***))
1010import Control.Monad (when)
1111import Control.Monad.Error.Class (catchError)
1212
13−import Data.Monoid ((<>))
1413import Data.Aeson ((.=))
1514import Data.Aeson.BetterErrors
1615import Data.ByteString.Lazy (ByteString)
1716import Data.Either (isLeft, isRight)
18−import Data.Maybe (mapMaybe, fromMaybe)
17+import Data.Maybe (mapMaybe, fromMaybe, maybeToList)
18+import Data.Monoid ((<>))
1919import Data.Text (Text)
20+import Data.Time.Clock (UTCTime)
21+import qualified Data.Time.Format as TimeFormat
2022import Data.Version
21−import qualified Data.Vector as V
2223import qualified Data.Aeson as A
2324import qualified Data.Text as T
25+import qualified Data.Vector as V
2426
2527import qualified Language.PureScript as P
2628
@@ -40,6 +42,10 @@ data Package a = Package
4042 { pkgMeta :: PackageMeta
4143 , pkgVersion :: Version
4244 , pkgVersionTag :: Text
45+ -- TODO: When this field was introduced, it was given the Maybe type for the
46+ -- sake of backwards compatibility, as older JSON blobs will not include the
47+ -- field. It should eventually be changed to just UTCTime.
48+ , pkgTagTime :: Maybe UTCTime
4349 , pkgModules :: [Module]
4450 , pkgBookmarks :: [Bookmark]
4551 , pkgResolvedDependencies :: [(PackageName, Version)]
@@ -62,6 +68,7 @@ verifyPackage verifiedUser Package{..} =
6268 Package pkgMeta
6369 pkgVersion
6470 pkgVersionTag
71+ pkgTagTime
6572 pkgModules
6673 pkgBookmarks
6774 pkgResolvedDependencies
@@ -72,6 +79,29 @@ verifyPackage verifiedUser Package{..} =
7279packageName :: Package a -> PackageName
7380packageName = bowerName . pkgMeta
7481
82+-- |
83+-- The time format used for serializing package tag times in the JSON format.
84+-- This is the ISO 8601 date format which includes a time and a timezone.
85+--
86+jsonTimeFormat :: String
87+jsonTimeFormat = "%Y-%m-%dT%H:%M:%S%z"
88+
89+-- |
90+-- Convenience function for formatting a time in the format expected by this
91+-- module.
92+--
93+formatTime :: UTCTime -> String
94+formatTime =
95+ TimeFormat.formatTime TimeFormat.defaultTimeLocale jsonTimeFormat
96+
97+-- |
98+-- Convenience function for parsing a time in the format expected by this
99+-- module.
100+--
101+parseTime :: String -> Maybe UTCTime
102+parseTime =
103+ TimeFormat.parseTimeM False TimeFormat.defaultTimeLocale jsonTimeFormat
104+
75105data Module = Module
76106 { modName :: P.ModuleName
77107 , modComments :: Maybe Text
@@ -275,6 +305,7 @@ data PackageError
275305 | InvalidFixity
276306 | InvalidKind Text
277307 | InvalidDataDeclType Text
308+ | InvalidTime
278309 deriving (Show, Eq, Ord)
279310
280311type Bookmark = InPackage (P.ModuleName, Text)
@@ -320,6 +351,7 @@ asPackage minimumVersion uploader = do
320351 Package <$> key "packageMeta" asPackageMeta .! ErrorInPackageMeta
321352 <*> key "version" asVersion
322353 <*> key "versionTag" asText
354+ <*> keyMay "tagTime" (withString parseTimeEither)
323355 <*> key "modules" (eachInArray asModule)
324356 <*> key "bookmarks" asBookmarks .! ErrorInPackageMeta
325357 <*> key "resolvedDependencies" asResolvedDependencies
@@ -327,6 +359,10 @@ asPackage minimumVersion uploader = do
327359 <*> key "uploader" uploader
328360 <*> pure compilerVersion
329361
362+parseTimeEither :: String -> Either PackageError UTCTime
363+parseTimeEither =
364+ maybe (Left InvalidTime) Right . parseTime
365+
330366asUploadedPackage :: Version -> Parse PackageError UploadedPackage
331367asUploadedPackage minVersion = asPackage minVersion asNotYetKnown
332368
@@ -359,6 +395,8 @@ displayPackageError e = case e of
359395 "Invalid kind: \"" <> str <> "\""
360396 InvalidDataDeclType str ->
361397 "Invalid data declaration type: \"" <> str <> "\""
398+ InvalidTime ->
399+ "Invalid time"
362400
363401instance A.FromJSON a => A.FromJSON (Package a) where
364402 parseJSON = toAesonParser displayPackageError
@@ -550,7 +588,7 @@ asSourceSpan = P.SourceSpan <$> key "name" asString
550588
551589instance A.ToJSON a => A.ToJSON (Package a) where
552590 toJSON Package{..} =
553− A.object
591+ A.object $
554592 [ "packageMeta" .= pkgMeta
555593 , "version" .= showVersion pkgVersion
556594 , "versionTag" .= pkgVersionTag
@@ -562,7 +600,8 @@ instance A.ToJSON a => A.ToJSON (Package a) where
562600 , "github" .= pkgGithub
563601 , "uploader" .= pkgUploader
564602 , "compilerVersion" .= showVersion P.version
565− ]
603+ ] ++
604+ fmap (\t -> "tagTime" .= formatTime t) (maybeToList pkgTagTime)
566605
567606instance A.ToJSON NotYetKnown where
568607 toJSON _ = A.Null
src/Language/PureScript/Errors.hs+15−10
@@ -32,10 +32,10 @@ import Language.PureScript.Names
3232import Language.PureScript.Pretty
3333import Language.PureScript.Traversals
3434import Language.PureScript.Types
35−import Language.PureScript.Pretty.Common (endWith)
35+import Language.PureScript.Label (Label(..))
36+import Language.PureScript.Pretty.Common (before, endWith)
3637import qualified Language.PureScript.Bundle as Bundle
3738import qualified Language.PureScript.Constants as C
38−import Language.PureScript.Pretty.Common (before)
3939
4040import qualified System.Console.ANSI as ANSI
4141
@@ -172,6 +172,7 @@ errorCode em = case unwrapErrorMessage em of
172172 CannotGeneralizeRecursiveFunction{} -> "CannotGeneralizeRecursiveFunction"
173173 CannotDeriveNewtypeForData{} -> "CannotDeriveNewtypeForData"
174174 ExpectedWildcard{} -> "ExpectedWildcard"
175+ CannotUseBindWithDo{} -> "CannotUseBindWithDo"
175176
176177-- |
177178-- A stack trace for an error
@@ -264,7 +265,7 @@ onTypesInErrorMessageM f (ErrorMessage hints simple) = ErrorMessage <$> traverse
264265 gSimple (ExprDoesNotHaveType e t) = ExprDoesNotHaveType e <$> f t
265266 gSimple (InvalidInstanceHead t) = InvalidInstanceHead <$> f t
266267 gSimple (NoInstanceFound con) = NoInstanceFound <$> overConstraintArgs (traverse f) con
267− gSimple (AmbiguousTypeVariables t con) = AmbiguousTypeVariables <$> (f t) <*> pure con
268+ gSimple (AmbiguousTypeVariables t con) = AmbiguousTypeVariables <$> f t <*> pure con
268269 gSimple (OverlappingInstances cl ts insts) = OverlappingInstances cl <$> traverse f ts <*> pure insts
269270 gSimple (PossiblyInfiniteInstance cl ts) = PossiblyInfiniteInstance cl <$> traverse f ts
270271 gSimple (CannotDerive cl ts) = CannotDerive cl <$> traverse f ts
@@ -565,12 +566,12 @@ prettyPrintSingleError (PPEOptions codeColor full level showDocs) e = flip evalS
565566 sortRows t1 t2 = (t1, t2)
566567
567568 -- Put the common labels last
568− sortRows' :: ([(Text, Type)], Type) -> ([(Text, Type)], Type) -> (Type, Type)
569+ sortRows' :: ([(Label, Type)], Type) -> ([(Label, Type)], Type) -> (Type, Type)
569570 sortRows' (s1, r1) (s2, r2) =
570− let common :: [(Text, (Type, Type))]
571+ let common :: [(Label, (Type, Type))]
571572 common = sortBy (comparing fst) [ (name, (t1, t2)) | (name, t1) <- s1, (name', t2) <- s2, name == name' ]
572573
573− sd1, sd2 :: [(Text, Type)]
574+ sd1, sd2 :: [(Label, Type)]
574575 sd1 = [ (name, t1) | (name, t1) <- s1, name `notElem` map fst s2 ]
575576 sd2 = [ (name, t2) | (name, t2) <- s2, name `notElem` map fst s1 ]
576577 in ( rowFromList (sortBy (comparing fst) sd1 ++ map (fst &&& fst . snd) common, r1)
@@ -673,7 +674,7 @@ prettyPrintSingleError (PPEOptions codeColor full level showDocs) e = flip evalS
673674 renderSimpleErrorMessage (CannotFindDerivingType nm) =
674675 line $ "Cannot derive a type class instance, because the type declaration for " <> markCode (runProperName nm) <> " could not be found."
675676 renderSimpleErrorMessage (DuplicateLabel l expr) =
676− paras $ [ line $ "Label " <> markCode l <> " appears more than once in a row type." ]
677+ paras $ [ line $ "Label " <> markCode (prettyPrintLabel l) <> " appears more than once in a row type." ]
677678 <> foldMap (\expr' -> [ line "Relevant expression: "
678679 , markCodeBox $ indent $ prettyPrintValue valueDepth expr'
679680 ]) expr
@@ -706,9 +707,9 @@ prettyPrintSingleError (PPEOptions codeColor full level showDocs) e = flip evalS
706707 , markCodeBox $ indent $ typeAsBox ty
707708 ]
708709 renderSimpleErrorMessage (PropertyIsMissing prop) =
709− line $ "Type of expression lacks required label " <> markCode prop <> "."
710+ line $ "Type of expression lacks required label " <> markCode (prettyPrintLabel prop) <> "."
710711 renderSimpleErrorMessage (AdditionalProperty prop) =
711− line $ "Type of expression contains additional label " <> markCode prop <> "."
712+ line $ "Type of expression contains additional label " <> markCode (prettyPrintLabel prop) <> "."
712713 renderSimpleErrorMessage TypeSynonymInstance =
713714 line "Type class instances for type synonyms are disallowed."
714715 renderSimpleErrorMessage (OrphanInstance nm cnm ts) =
@@ -880,6 +881,10 @@ prettyPrintSingleError (PPEOptions codeColor full level showDocs) e = flip evalS
880881 paras [ line $ "Expected a type wildcard (_) when deriving an instance for " <> markCode (runProperName tyName) <> "."
881882 ]
882883
884+ renderSimpleErrorMessage CannotUseBindWithDo =
885+ paras [ line $ "The name " <> markCode "bind" <> " cannot be brought into scope in a do notation block, since do notation uses the same name."
886+ ]
887+
883888 renderHint :: ErrorMessageHint -> Box.Box -> Box.Box
884889 renderHint (ErrorUnifyingTypes t1 t2) detail =
885890 paras [ detail
@@ -1265,7 +1270,7 @@ renderBox = unlines
12651270 whiteSpace = all isSpace
12661271
12671272toTypelevelString :: Type -> Maybe Box.Box
1268−toTypelevelString (TypeLevelString s) = Just $ Box.text (T.unpack s)
1273+toTypelevelString (TypeLevelString s) = Just $ Box.text $ T.unpack $ prettyPrintString s
12691274toTypelevelString (TypeApp (TypeConstructor f) x)
12701275 | f == primName "TypeString" = Just $ typeAsBox x
12711276toTypelevelString (TypeApp (TypeApp (TypeConstructor f) x) ret)
src/Language/PureScript/Ide/Conversions.hsdeleted−29
@@ -1,29 +0,0 @@
1−-----------------------------------------------------------------------------
2−--
3−-- Module : Language.PureScript.Ide.Conversions
4−-- Description : Conversions to Text for PureScript types
5−-- Copyright : Christoph Hegemann 2016
6−-- License : MIT (http://opensource.org/licenses/MIT)
7−--
8−-- Maintainer : Christoph Hegemann <christoph.hegemann1337@gmail.com>
9−-- Stability : experimental
10−--
11−-- |
12−-- Conversions to Text for PureScript types
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.Ide.Conversions where
16−
17−import Control.Lens.Iso
18−import Data.Text (lines, strip, unwords, pack)
19−import qualified Language.PureScript as P
20−import Protolude
21−
22−properNameT :: Iso' (P.ProperName a) Text
23−properNameT = iso P.runProperName P.ProperName
24−
25−identT :: Iso' P.Ident Text
26−identT = iso P.runIdent P.Ident
27−
28−prettyTypeT :: P.Type -> Text
29−prettyTypeT = unwords . map strip . lines . pack . P.prettyPrintType
src/Language/PureScript/Ide/Util.hs+18−3
@@ -24,19 +24,20 @@ module Language.PureScript.Ide.Util
2424 , withEmptyAnn
2525 , valueOperatorAliasT
2626 , typeOperatorAliasT
27− , module Language.PureScript.Ide.Conversions
27+ , prettyTypeT
28+ , properNameT
29+ , identT
2830 , module Language.PureScript.Ide.Logging
2931 ) where
3032
3133import Protolude hiding (decodeUtf8,
3234 encodeUtf8)
3335
34−import Control.Lens ((^.))
36+import Control.Lens ((^.), Iso', iso)
3537import Data.Aeson
3638import qualified Data.Text as T
3739import Data.Text.Lazy.Encoding (decodeUtf8, encodeUtf8)
3840import qualified Language.PureScript as P
39−import Language.PureScript.Ide.Conversions
4041import Language.PureScript.Ide.Logging
4142import Language.PureScript.Ide.Types
4243
@@ -114,3 +115,17 @@ unwrapPositioned x = x
114115unwrapPositionedRef :: P.DeclarationRef -> P.DeclarationRef
115116unwrapPositionedRef (P.PositionedDeclarationRef _ _ x) = unwrapPositionedRef x
116117unwrapPositionedRef x = x
118+
119+properNameT :: Iso' (P.ProperName a) Text
120+properNameT = iso P.runProperName P.ProperName
121+
122+identT :: Iso' P.Ident Text
123+identT = iso P.runIdent P.Ident
124+
125+prettyTypeT :: P.Type -> Text
126+prettyTypeT =
127+ T.unwords
128+ . map T.strip
129+ . T.lines
130+ . T.pack
131+ . P.prettyPrintTypeWithUnicode
src/Language/PureScript/Label.hsnew file+16
@@ -0,0 +1,16 @@
1+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2+module Language.PureScript.Label (Label(..)) where
3+
4+import Prelude.Compat hiding (lex)
5+import Data.Monoid ()
6+import Data.String (IsString(..))
7+import qualified Data.Aeson as A
8+
9+import Language.PureScript.PSString (PSString)
10+
11+-- |
12+-- Labels are used as record keys and row entry names. Labels newtype PSString
13+-- because records are indexable by PureScript strings at runtime.
14+--
15+newtype Label = Label { runLabel :: PSString }
16+ deriving (Show, Eq, Ord, IsString, Monoid, A.ToJSON, A.FromJSON)
src/Language/PureScript/PSString.hsnew file+187
@@ -0,0 +1,187 @@
1+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+module Language.PureScript.PSString
4+ ( PSString
5+ , toUTF16CodeUnits
6+ , decodeString
7+ , decodeStringEither
8+ , prettyPrintString
9+ , prettyPrintStringJS
10+ , mkString
11+ ) where
12+
13+import Prelude.Compat
14+import Control.Exception (try, evaluate)
15+import Control.Applicative ((<|>))
16+import Data.Char (chr)
17+import Data.Bits (shiftR)
18+import Data.List (unfoldr)
19+import Data.Monoid ((<>))
20+import Data.Scientific (toBoundedInteger)
21+import Data.String (IsString(..))
22+import Data.ByteString (ByteString)
23+import qualified Data.ByteString as BS
24+import Data.Text (Text)
25+import qualified Data.Text as T
26+import Data.Text.Encoding (decodeUtf16BE)
27+import Data.Text.Encoding.Error (UnicodeException)
28+import qualified Data.Vector as V
29+import Data.Word (Word16, Word8)
30+import Numeric (showHex)
31+import System.IO.Unsafe (unsafePerformIO)
32+import qualified Data.Aeson as A
33+import qualified Data.Aeson.Types as A
34+
35+-- |
36+-- Strings in PureScript are sequences of UTF-16 code units, which do not
37+-- necessarily represent UTF-16 encoded text. For example, it is permissible
38+-- for a string to contain *lone surrogates,* i.e. characters in the range
39+-- U+D800 to U+DFFF which do not appear as a part of a surrogate pair.
40+--
41+-- The Show instance for PSString produces a string literal which would
42+-- represent the same data were it inserted into a PureScript source file.
43+--
44+-- Because JSON parsers vary wildly in terms of how they deal with lone
45+-- surrogates in JSON strings, the ToJSON instance for PSString produces JSON
46+-- strings where that would be safe (i.e. when there are no lone surrogates),
47+-- and arrays of UTF-16 code units (integers) otherwise.
48+--
49+newtype PSString = PSString { toUTF16CodeUnits :: [Word16] }
50+ deriving (Eq, Ord, Monoid)
51+
52+instance Show PSString where
53+ show = show . codePoints
54+
55+-- Decode a PSString to a String, representing any lone surrogates as the
56+-- reserved code point with that index. Warning: if there are any lone
57+-- surrogates, converting the result to Text via Data.Text.pack will result in
58+-- loss of information as those lone surrogates will be replaced with U+FFFD
59+-- REPLACEMENT CHARACTER. Because this function requires care to use correctly,
60+-- we do not export it.
61+codePoints :: PSString -> String
62+codePoints = map (either (chr . fromIntegral) id) . decodeStringEither
63+
64+-- |
65+-- Decode a PSString as UTF-16. Lone surrogates in the input are represented in
66+-- the output with the Left constructor; characters which were successfully
67+-- decoded are represented with the Right constructor.
68+--
69+decodeStringEither :: PSString -> [Either Word16 Char]
70+decodeStringEither = unfoldr decode . toUTF16CodeUnits
71+ where
72+ decode :: [Word16] -> Maybe (Either Word16 Char, [Word16])
73+ decode (h:l:rest) | isLead h && isTrail l = Just (Right (unsurrogate h l), rest)
74+ decode (c:rest) | isSurrogate c = Just (Left c, rest)
75+ decode (c:rest) = Just (Right (toChar c), rest)
76+ decode [] = Nothing
77+
78+ unsurrogate :: Word16 -> Word16 -> Char
79+ unsurrogate h l = toEnum ((toInt h - 0xD800) * 0x400 + (toInt l - 0xDC00) + 0x10000)
80+
81+-- |
82+-- Pretty print a PSString, using Haskell/PureScript escape sequences.
83+-- This is identical to the Show instance except that we get a Text out instead
84+-- of a String.
85+--
86+prettyPrintString :: PSString -> Text
87+prettyPrintString = T.pack . show
88+
89+-- |
90+-- Attempt to decode a PSString as UTF-16 text. This will fail (returning
91+-- Nothing) if the argument contains lone surrogates.
92+--
93+decodeString :: PSString -> Maybe Text
94+decodeString = hush . decodeEither . BS.pack . concatMap unpair . toUTF16CodeUnits
95+ where
96+ unpair w = [highByte w, lowByte w]
97+
98+ lowByte :: Word16 -> Word8
99+ lowByte = fromIntegral
100+
101+ highByte :: Word16 -> Word8
102+ highByte = fromIntegral . (`shiftR` 8)
103+
104+ -- Based on a similar function from Data.Text.Encoding for utf8. This is a
105+ -- safe usage of unsafePerformIO because there are no side effects after
106+ -- handling any thrown UnicodeExceptions.
107+ decodeEither :: ByteString -> Either UnicodeException Text
108+ decodeEither = unsafePerformIO . try . evaluate . decodeUtf16BE
109+
110+ hush = either (const Nothing) Just
111+
112+instance IsString PSString where
113+ fromString a = PSString $ concatMap encodeUTF16 a
114+ where
115+ surrogates :: Char -> (Word16, Word16)
116+ surrogates c = (toWord (h + 0xD800), toWord (l + 0xDC00))
117+ where (h, l) = divMod (fromEnum c - 0x10000) 0x400
118+
119+ encodeUTF16 :: Char -> [Word16]
120+ encodeUTF16 c | fromEnum c > 0xFFFF = [high, low]
121+ where (high, low) = surrogates c
122+ encodeUTF16 c = [toWord $ fromEnum c]
123+
124+instance A.ToJSON PSString where
125+ toJSON str =
126+ case decodeString str of
127+ Just t -> A.toJSON t
128+ Nothing -> A.toJSON (toUTF16CodeUnits str)
129+
130+instance A.FromJSON PSString where
131+ parseJSON a = jsonString <|> arrayOfCodeUnits
132+ where
133+ jsonString = fromString <$> A.parseJSON a
134+
135+ arrayOfCodeUnits = PSString <$> parseArrayOfCodeUnits a
136+
137+ parseArrayOfCodeUnits :: A.Value -> A.Parser [Word16]
138+ parseArrayOfCodeUnits = A.withArray "array of UTF-16 code units" (traverse parseCodeUnit . V.toList)
139+
140+ parseCodeUnit :: A.Value -> A.Parser Word16
141+ parseCodeUnit b = A.withScientific "two-byte non-negative integer" (maybe (A.typeMismatch "" b) return . toBoundedInteger) b
142+
143+-- |
144+-- Pretty print a PSString, using JavaScript escape sequences. Intended for
145+-- use in compiled JS output.
146+--
147+prettyPrintStringJS :: PSString -> Text
148+prettyPrintStringJS s = "\"" <> foldMap encodeChar (toUTF16CodeUnits s) <> "\""
149+ where
150+ encodeChar :: Word16 -> Text
151+ encodeChar c | c > 0xFF = "\\u" <> hex 4 c
152+ encodeChar c | c > 0x7E || c < 0x20 = "\\x" <> hex 2 c
153+ encodeChar c | toChar c == '\b' = "\\b"
154+ encodeChar c | toChar c == '\t' = "\\t"
155+ encodeChar c | toChar c == '\n' = "\\n"
156+ encodeChar c | toChar c == '\v' = "\\v"
157+ encodeChar c | toChar c == '\f' = "\\f"
158+ encodeChar c | toChar c == '\r' = "\\r"
159+ encodeChar c | toChar c == '"' = "\\\""
160+ encodeChar c | toChar c == '\\' = "\\\\"
161+ encodeChar c = T.singleton $ toChar c
162+
163+ hex :: (Enum a) => Int -> a -> Text
164+ hex width c =
165+ let hs = showHex (fromEnum c) "" in
166+ T.pack (replicate (width - length hs) '0' <> hs)
167+
168+isLead :: Word16 -> Bool
169+isLead h = h >= 0xD800 && h <= 0xDBFF
170+
171+isTrail :: Word16 -> Bool
172+isTrail l = l >= 0xDC00 && l <= 0xDFFF
173+
174+isSurrogate :: Word16 -> Bool
175+isSurrogate c = isLead c || isTrail c
176+
177+toChar :: Word16 -> Char
178+toChar = toEnum . fromIntegral
179+
180+toWord :: Int -> Word16
181+toWord = fromIntegral
182+
183+toInt :: Word16 -> Int
184+toInt = fromIntegral
185+
186+mkString :: Text -> PSString
187+mkString = fromString . T.unpack
src/Language/PureScript/Parser/Common.hs+7
@@ -16,6 +16,7 @@ import Language.PureScript.Comments
1616import Language.PureScript.Names
1717import Language.PureScript.Parser.Lexer
1818import Language.PureScript.Parser.State
19+import Language.PureScript.PSString (PSString, mkString)
1920
2021import qualified Text.Parsec as P
2122
@@ -72,6 +73,12 @@ parseQualified parser = part []
7273parseIdent :: TokenParser Ident
7374parseIdent = Ident <$> identifier
7475
76+-- |
77+-- Parse a label, which may look like an identifier or a string
78+--
79+parseLabel :: TokenParser PSString
80+parseLabel = (mkString <$> lname) <|> stringLiteral
81+
7582-- |
7683-- Parse an operator.
7784--
src/Language/PureScript/Parser/Declarations.hs+9−8
@@ -33,6 +33,7 @@ import Language.PureScript.Errors
3333import Language.PureScript.Kinds
3434import Language.PureScript.Names
3535import Language.PureScript.Types
36+import Language.PureScript.PSString (PSString, mkString)
3637import Language.PureScript.Parser.Common
3738import Language.PureScript.Parser.Kinds
3839import Language.PureScript.Parser.Lexer
@@ -338,15 +339,15 @@ parseBooleanLiteral = BooleanLiteral <$> booleanLiteral
338339parseArrayLiteral :: TokenParser a -> TokenParser (Literal a)
339340parseArrayLiteral p = ArrayLiteral <$> squares (commaSep p)
340341
341−parseObjectLiteral :: TokenParser (Text, a) -> TokenParser (Literal a)
342+parseObjectLiteral :: TokenParser (PSString, a) -> TokenParser (Literal a)
342343parseObjectLiteral p = ObjectLiteral <$> braces (commaSep p)
343344
344−parseIdentifierAndValue :: TokenParser (Text, Expr)
345+parseIdentifierAndValue :: TokenParser (PSString, Expr)
345346parseIdentifierAndValue =
346347 do
347348 name <- C.indented *> lname
348349 b <- P.option (Var $ Qualified Nothing (Ident name)) rest
349− return (name, b)
350+ return (mkString name, b)
350351 <|> (,) <$> (C.indented *> stringLiteral) <*> rest
351352 where
352353 rest = C.indented *> colon *> C.indented *> parseValue
@@ -428,16 +429,16 @@ parseInfixExpr
428429parseHole :: TokenParser Expr
429430parseHole = Hole <$> holeLit
430431
431−parsePropertyUpdate :: TokenParser (Text, Expr)
432+parsePropertyUpdate :: TokenParser (PSString, Expr)
432433parsePropertyUpdate = do
433− name <- lname <|> stringLiteral
434+ name <- parseLabel
434435 _ <- C.indented *> equals
435436 value <- C.indented *> parseValue
436437 return (name, value)
437438
438439parseAccessor :: Expr -> TokenParser Expr
439440parseAccessor (Constructor _) = P.unexpected "constructor"
440−parseAccessor obj = P.try $ Accessor <$> (C.indented *> dot *> C.indented *> (lname <|> stringLiteral)) <*> pure obj
441+parseAccessor obj = P.try $ Accessor <$> (C.indented *> dot *> C.indented *> parseLabel) <*> pure obj
441442
442443parseDo :: TokenParser Expr
443444parseDo = do
@@ -520,11 +521,11 @@ parseVarOrNamedBinder = do
520521parseNullBinder :: TokenParser Binder
521522parseNullBinder = underscore *> return NullBinder
522523
523−parseIdentifierAndBinder :: TokenParser (Text, Binder)
524+parseIdentifierAndBinder :: TokenParser (PSString, Binder)
524525parseIdentifierAndBinder =
525526 do name <- lname
526527 b <- P.option (VarBinder (Ident name)) rest
527− return (name, b)
528+ return (mkString name, b)
528529 <|> (,) <$> stringLiteral <*> rest
529530 where
530531 rest = C.indented *> colon *> C.indented *> parseBinder
src/Language/PureScript/Parser/Lexer.hs+8−18
@@ -70,11 +70,13 @@ import Control.Monad (void, guard)
7070import Control.Monad.Identity (Identity)
7171import Data.Char (isSpace, isAscii, isSymbol, isAlphaNum)
7272import Data.Monoid ((<>))
73+import Data.String (fromString)
7374import Data.Text (Text)
7475import qualified Data.Text as T
7576
7677import Language.PureScript.Comments
7778import Language.PureScript.Parser.State
79+import Language.PureScript.PSString (PSString)
7880
7981import qualified Text.Parsec as P
8082import qualified Text.Parsec.Token as PT
@@ -106,7 +108,7 @@ data Token
106108 | Qualifier Text
107109 | Symbol Text
108110 | CharLiteral Char
109− | StringLiteral Text
111+ | StringLiteral PSString
110112 | Number (Either Integer Double)
111113 | HoleLit Text
112114 deriving (Show, Eq, Ord)
@@ -248,19 +250,7 @@ parseToken = P.choice
248250
249251 symbolChar :: Lexer u Char
250252 symbolChar = P.satisfy isSymbolChar
251−{-
252− surrogates :: Char -> (Char, Char)
253− surrogates c = (high, low)
254− where
255− (h, l) = divMod (fromEnum c - 0x10000) 0x400
256− high = toEnum (h + 0xD800)
257− low = toEnum (l + 0xDC00)
258−
259− expandAstralCodePointToUTF16Surrogates :: Char -> [Char]
260− expandAstralCodePointToUTF16Surrogates c | fromEnum c > 0xFFFF = [high, low]
261− where (high, low) = surrogates c
262− expandAstralCodePointToUTF16Surrogates c = [c]
263−-}
253+
264254 parseCharLiteral :: Lexer u Char
265255 parseCharLiteral = P.try $ do {
266256 c <- PT.charLiteral tokenParser;
@@ -269,11 +259,11 @@ parseToken = P.choice
269259 else return c
270260 }
271261
272− parseStringLiteral :: Lexer u Text
273− parseStringLiteral = blockString <|> T.pack <$> {- concatMap expandAstralCodePointToUTF16Surrogates <$> -} PT.stringLiteral tokenParser
262+ parseStringLiteral :: Lexer u PSString
263+ parseStringLiteral = fromString <$> (blockString <|> PT.stringLiteral tokenParser)
274264 where
275265 delimiter = P.try (P.string "\"\"\"")
276− blockString = delimiter *> (T.pack <$> P.manyTill P.anyChar delimiter)
266+ blockString = delimiter *> P.manyTill P.anyChar delimiter
277267
278268 parseNumber :: Lexer u (Either Integer Double)
279269 parseNumber = (consumeLeadingZero *> P.parserZero) <|>
@@ -516,7 +506,7 @@ charLiteral = token go P.<?> "char literal"
516506 go (CharLiteral c) = Just c
517507 go _ = Nothing
518508
519−stringLiteral :: TokenParser Text
509+stringLiteral :: TokenParser PSString
520510stringLiteral = token go P.<?> "string literal"
521511 where
522512 go (StringLiteral s) = Just s
src/Language/PureScript/Parser/Types.hs+3−3
@@ -9,7 +9,6 @@ import Prelude.Compat
99
1010import Control.Monad (when, unless)
1111import Control.Applicative ((<|>))
12−import Data.Text (Text)
1312import qualified Data.Text as T
1413
1514import Language.PureScript.AST.SourcePos
@@ -18,6 +17,7 @@ import Language.PureScript.Parser.Common
1817import Language.PureScript.Parser.Kinds
1918import Language.PureScript.Parser.Lexer
2019import Language.PureScript.Types
20+import Language.PureScript.Label (Label(..))
2121
2222import qualified Text.Parsec as P
2323import qualified Text.Parsec.Expr as P
@@ -118,8 +118,8 @@ noWildcards p = do
118118 when (containsWildcards ty) $ P.unexpected "type wildcard"
119119 return ty
120120
121−parseNameAndType :: TokenParser t -> TokenParser (Text, t)
122−parseNameAndType p = (,) <$> (indented *> (lname <|> stringLiteral) <* indented <* doubleColon) <*> p
121+parseNameAndType :: TokenParser t -> TokenParser (Label, t)
122+parseNameAndType p = (,) <$> (indented *> (Label <$> parseLabel) <* indented <* doubleColon) <*> p
123123
124124parseRowEnding :: TokenParser Type
125125parseRowEnding = P.option REmpty $ indented *> pipe *> indented *> parseType
src/Language/PureScript/Pretty.hs+1
@@ -15,3 +15,4 @@ import Language.PureScript.Pretty.JS as P
1515import Language.PureScript.Pretty.Kinds as P
1616import Language.PureScript.Pretty.Types as P
1717import Language.PureScript.Pretty.Values as P
18+import Language.PureScript.PSString as P (prettyPrintString)
src/Language/PureScript/Pretty/Common.hs+4−8
@@ -15,7 +15,7 @@ import Data.Text (Text)
1515import qualified Data.Text as T
1616
1717import Language.PureScript.AST (SourcePos(..), SourceSpan(..))
18−import Language.PureScript.Parser.Lexer (reservedPsNames, isUnquotedKey)
18+import Language.PureScript.Parser.Lexer (isUnquotedKey, reservedPsNames)
1919
2020import Text.PrettyPrint.Boxes hiding ((<>))
2121import qualified Text.PrettyPrint.Boxes as Box
@@ -146,13 +146,9 @@ prettyPrintMany f xs = do
146146 indentString <- currentIndent
147147 return $ intercalate (emit "\n") $ map (mappend indentString) ss
148148
149−-- |
150−-- Prints an object key, escaping reserved names.
151−--
152−prettyPrintObjectKey :: Text -> Text
153−prettyPrintObjectKey s | s `elem` reservedPsNames = T.pack (show s)
154− | isUnquotedKey s = s
155− | otherwise = T.pack (show s)
149+objectKeyRequiresQuoting :: Text -> Bool
150+objectKeyRequiresQuoting s =
151+ s `elem` reservedPsNames || not (isUnquotedKey s)
156152
157153-- | Place a box before another, vertically when the first box takes up multiple lines.
158154before :: Box -> Box -> Box
src/Language/PureScript/Pretty/JS.hs+10−30
@@ -25,8 +25,7 @@ import Language.PureScript.CodeGen.JS.Common
2525import Language.PureScript.Comments
2626import Language.PureScript.Crash
2727import Language.PureScript.Pretty.Common
28−
29−import Numeric
28+import Language.PureScript.PSString (PSString, decodeString, prettyPrintStringJS)
3029
3130-- TODO (Christoph): Get rid of T.unpack / pack
3231
@@ -38,7 +37,7 @@ literals = mkPattern' match'
3837
3938 match :: (Emit gen) => JS -> StateT PrinterState Maybe gen
4039 match (JSNumericLiteral _ n) = return $ emit $ T.pack $ either show show n
41− match (JSStringLiteral _ s) = return $ string s
40+ match (JSStringLiteral _ s) = return $ emit $ prettyPrintStringJS s
4241 match (JSBooleanLiteral _ True) = return $ emit "true"
4342 match (JSBooleanLiteral _ False) = return $ emit "false"
4443 match (JSArrayLiteral _ xs) = mconcat <$> sequence
@@ -58,9 +57,13 @@ literals = mkPattern' match'
5857 , return $ emit "}"
5958 ]
6059 where
61− objectPropertyToString :: (Emit gen) => Text -> gen
62− objectPropertyToString s | identNeedsEscaping s = string s
63− | otherwise = emit s
60+ objectPropertyToString :: (Emit gen) => PSString -> gen
61+ objectPropertyToString s =
62+ emit $ case decodeString s of
63+ Just s' | not (identNeedsEscaping s') ->
64+ s'
65+ _ ->
66+ prettyPrintStringJS s
6467 match (JSBlock _ sts) = mconcat <$> sequence
6568 [ return $ emit "{\n"
6669 , withIndent $ prettyStatements sts
@@ -150,29 +153,6 @@ literals = mkPattern' match'
150153 match (JSRaw _ js) = return $ emit js
151154 match _ = mzero
152155
153−string :: (Emit gen) => Text -> gen
154−string s = emit $ "\"" <> T.concatMap encodeChar s <> "\""
155− where
156− encodeChar :: Char -> Text
157− encodeChar '\b' = "\\b"
158− encodeChar '\t' = "\\t"
159− encodeChar '\n' = "\\n"
160− encodeChar '\v' = "\\v"
161− encodeChar '\f' = "\\f"
162− encodeChar '\r' = "\\r"
163− encodeChar '"' = "\\\""
164− encodeChar '\\' = "\\\\"
165− -- PureScript strings are sequences of UTF-16 code units, so this case should never be hit.
166− -- If it is somehow hit, though, output the designated Unicode replacement character U+FFFD.
167− encodeChar c | fromEnum c > 0xFFFF = "\\uFFFD"
168− encodeChar c | fromEnum c > 0xFFF = "\\u" <> showHex' (fromEnum c) ""
169− encodeChar c | fromEnum c > 0xFF = "\\u0" <> showHex' (fromEnum c) ""
170− encodeChar c | fromEnum c < 0x10 = "\\x0" <> showHex' (fromEnum c) ""
171− encodeChar c | fromEnum c > 0x7E || fromEnum c < 0x20 = "\\x" <> showHex' (fromEnum c) ""
172− encodeChar c = T.singleton c
173−
174− showHex' a b = T.pack (showHex a b)
175−
176156conditional :: Pattern PrinterState JS ((Maybe SourceSpan, JS, JS), JS)
177157conditional = mkPattern match
178158 where
@@ -182,6 +162,7 @@ conditional = mkPattern match
182162accessor :: (Emit gen) => Pattern PrinterState JS (gen, JS)
183163accessor = mkPattern match
184164 where
165+ -- WARN: if `prop` does not match the `IdentifierName` grammar, this will generate invalid code; see #2513
185166 match (JSAccessor _ prop val) = Just (emit prop, val)
186167 match _ = Nothing
187168
@@ -189,7 +170,6 @@ indexer :: (Emit gen) => Pattern PrinterState JS (gen, JS)
189170indexer = mkPattern' match
190171 where
191172 match (JSIndexer _ index val) = (,) <$> prettyPrintJS' index <*> pure val
192−
193173 match _ = mzero
194174
195175lam :: Pattern PrinterState JS ((Maybe Text, [Text], Maybe SourceSpan), JS)
src/Language/PureScript/Pretty/Kinds.hs+14−11
@@ -10,6 +10,7 @@ import Prelude.Compat
1010import Control.Arrow (ArrowPlus(..))
1111import Control.PatternArrows as PA
1212
13+import Data.Monoid ((<>))
1314import Data.Maybe (fromMaybe)
1415import qualified Data.Text as T
1516import Data.Text (Text)
@@ -19,11 +20,15 @@ import Language.PureScript.Kinds
1920import Language.PureScript.Names
2021import Language.PureScript.Pretty.Common
2122
22−typeLiterals :: Pattern () Kind String
23+typeLiterals :: Pattern () Kind Text
2324typeLiterals = mkPattern match
2425 where
25− match (KUnknown u) = Just $ 'u' : show u
26− match (NamedKind name) = Just $ T.unpack (showQualified runProperName name)
26+ match (KUnknown u) =
27+ Just $ T.cons 'k' (T.pack (show u))
28+ match (NamedKind name) =
29+ Just $ if isQualifiedWith (moduleNameFromString "Prim") name
30+ then runProperName (disqualify name)
31+ else showQualified runProperName name
2732 match _ = Nothing
2833
2934matchRow :: Pattern () Kind ((), Kind)
@@ -41,15 +46,13 @@ funKind = mkPattern match
4146-- | Generate a pretty-printed string representing a Kind
4247prettyPrintKind :: Kind -> Text
4348prettyPrintKind
44− -- TODO(Christoph): get rid of T.pack
45− = T.pack
46− . fromMaybe (internalError "Incomplete pattern")
49+ = fromMaybe (internalError "Incomplete pattern")
4750 . PA.pattern matchKind ()
4851 where
49− matchKind :: Pattern () Kind String
50− matchKind = buildPrettyPrinter operators (typeLiterals <+> fmap parens matchKind)
52+ matchKind :: Pattern () Kind Text
53+ matchKind = buildPrettyPrinter operators (typeLiterals <+> fmap parensT matchKind)
5154
52− operators :: OperatorTable () Kind String
55+ operators :: OperatorTable () Kind Text
5356 operators =
54− OperatorTable [ [ Wrap matchRow $ \_ k -> "# " ++ k]
55− , [ AssocR funKind $ \arg ret -> arg ++ " -> " ++ ret ] ]
57+ OperatorTable [ [ Wrap matchRow $ \_ k -> "# " <> k]
58+ , [ AssocR funKind $ \arg ret -> arg <> " -> " <> ret ] ]
src/Language/PureScript/Pretty/Types.hs+79−33
@@ -5,11 +5,13 @@ module Language.PureScript.Pretty.Types
55 ( typeAsBox
66 , suggestedTypeAsBox
77 , prettyPrintType
8+ , prettyPrintTypeWithUnicode
89 , prettyPrintSuggestedType
910 , typeAtomAsBox
1011 , prettyPrintTypeAtom
11− , prettyPrintRowWith
1212 , prettyPrintRow
13+ , prettyPrintLabel
14+ , prettyPrintObjectKey
1315 ) where
1416
1517import Prelude.Compat
@@ -18,6 +20,7 @@ import Control.Arrow ((<+>))
1820import Control.PatternArrows as PA
1921
2022import Data.Maybe (fromMaybe)
23+import Data.Text (Text)
2124import qualified Data.Text as T
2225
2326import Language.PureScript.Crash
@@ -27,14 +30,19 @@ import Language.PureScript.Names
2730import Language.PureScript.Pretty.Common
2831import Language.PureScript.Pretty.Kinds
2932import Language.PureScript.Types
33+import Language.PureScript.PSString (PSString, prettyPrintString, decodeString)
34+import Language.PureScript.Label (Label(..))
3035
3136import Text.PrettyPrint.Boxes hiding ((<+>))
3237
3338-- TODO(Christoph): get rid of T.unpack s
3439
35−constraintsAsBox :: [Constraint] -> Box -> Box
36−constraintsAsBox [con] ty = text "(" <> constraintAsBox con `before` (text ") => " <> ty)
37−constraintsAsBox xs ty = vcat left (zipWith (\i con -> text (if i == 0 then "( " else ", ") <> constraintAsBox con) [0 :: Int ..] xs) `before` (text ") => " <> ty)
40+constraintsAsBox :: TypeRenderOptions -> [Constraint] -> Box -> Box
41+constraintsAsBox tro constraints ty = case constraints of
42+ [con] -> text "(" <> constraintAsBox con `before` (") " <> text doubleRightArrow <> " " <> ty)
43+ xs -> vcat left (zipWith (\i con -> text (if i == 0 then "( " else ", ") <> constraintAsBox con) [0 :: Int ..] xs) `before` (") " <> text doubleRightArrow <> " " <> ty)
44+ where
45+ doubleRightArrow = if troUnicode tro then "⇒" else "=>"
3846
3947constraintAsBox :: Constraint -> Box
4048constraintAsBox (Constraint pn tys _) = typeAsBox (foldl TypeApp (TypeConstructor (fmap coerceProperName pn)) tys)
@@ -42,29 +50,30 @@ constraintAsBox (Constraint pn tys _) = typeAsBox (foldl TypeApp (TypeConstructo
4250-- |
4351-- Generate a pretty-printed string representing a Row
4452--
45−prettyPrintRowWith :: Char -> Char -> Type -> Box
46−prettyPrintRowWith open close = uncurry listToBox . toList []
53+prettyPrintRowWith :: TypeRenderOptions -> Char -> Char -> Type -> Box
54+prettyPrintRowWith tro open close = uncurry listToBox . toList []
4755 where
48− nameAndTypeToPs :: Char -> String -> Type -> Box
49− nameAndTypeToPs start name ty = text (start : ' ' : T.unpack (prettyPrintObjectKey (T.pack name)) ++ " :: ") <> typeAsBox ty
56+ nameAndTypeToPs :: Char -> Label -> Type -> Box
57+ nameAndTypeToPs start name ty = text (start : ' ' : T.unpack (prettyPrintLabel name) ++ " " ++ doubleColon ++ " ") <> typeAsBox ty
58+
59+ doubleColon = if troUnicode tro then "∷" else "::"
5060
5161 tailToPs :: Type -> Box
5262 tailToPs REmpty = nullBox
5363 tailToPs other = text "| " <> typeAsBox other
5464
55− listToBox :: [(String, Type)] -> Type -> Box
65+ listToBox :: [(Label, Type)] -> Type -> Box
5666 listToBox [] REmpty = text [open, close]
5767 listToBox [] rest = text [ open, ' ' ] <> tailToPs rest <> text [ ' ', close ]
5868 listToBox ts rest = vcat left $
5969 zipWith (\(nm, ty) i -> nameAndTypeToPs (if i == 0 then open else ',') nm ty) ts [0 :: Int ..] ++
6070 [ tailToPs rest, text [close] ]
61−
62− toList :: [(String, Type)] -> Type -> ([(String, Type)], Type)
63− toList tys (RCons name ty row) = toList ((T.unpack name, ty):tys) row
71+ toList :: [(Label, Type)] -> Type -> ([(Label, Type)], Type)
72+ toList tys (RCons name ty row) = toList ((name, ty):tys) row
6473 toList tys r = (reverse tys, r)
6574
6675prettyPrintRow :: Type -> String
67−prettyPrintRow = render . prettyPrintRowWith '(' ')'
76+prettyPrintRow = render . prettyPrintRowWith defaultOptions '(' ')'
6877
6978typeApp :: Pattern () Type (Type, Type)
7079typeApp = mkPattern match
@@ -108,16 +117,16 @@ explicitParens = mkPattern match
108117 match (ParensInType ty) = Just ((), ty)
109118 match _ = Nothing
110119
111−matchTypeAtom :: Bool -> Pattern () Type Box
112−matchTypeAtom suggesting =
113− typeLiterals <+> fmap ((`before` (text ")")) . (text "(" <>)) (matchType suggesting)
120+matchTypeAtom :: TypeRenderOptions -> Pattern () Type Box
121+matchTypeAtom tro@TypeRenderOptions{troSuggesting = suggesting} =
122+ typeLiterals <+> fmap ((`before` (text ")")) . (text "(" <>)) (matchType tro)
114123 where
115124 typeLiterals :: Pattern () Type Box
116125 typeLiterals = mkPattern match where
117126 match TypeWildcard{} = Just $ text "_"
118127 match (TypeVar var) = Just $ text $ T.unpack var
119− match (TypeLevelString s) = Just . text $ show s
120− match (PrettyPrintObject row) = Just $ prettyPrintRowWith '{' '}' row
128+ match (TypeLevelString s) = Just $ text $ T.unpack $ prettyPrintString s
129+ match (PrettyPrintObject row) = Just $ prettyPrintRowWith tro '{' '}' row
121130 match (TypeConstructor ctor) = Just $ text $ T.unpack $ runProperName $ disqualify ctor
122131 match (TUnknown u)
123132 | suggesting = Just $ text "_"
@@ -126,24 +135,28 @@ matchTypeAtom suggesting =
126135 | suggesting = Just $ text $ T.unpack name
127136 | otherwise = Just $ text $ T.unpack name ++ show s
128137 match REmpty = Just $ text "()"
129− match row@RCons{} = Just $ prettyPrintRowWith '(' ')' row
138+ match row@RCons{} = Just $ prettyPrintRowWith tro '(' ')' row
130139 match (BinaryNoParensType op l r) =
131140 Just $ typeAsBox l <> text " " <> typeAsBox op <> text " " <> typeAsBox r
132141 match (TypeOp op) = Just $ text $ T.unpack $ showQualified runOpName op
133142 match _ = Nothing
134143
135−matchType :: Bool -> Pattern () Type Box
136−matchType = buildPrettyPrinter operators . matchTypeAtom where
144+matchType :: TypeRenderOptions -> Pattern () Type Box
145+matchType tro = buildPrettyPrinter operators (matchTypeAtom tro) where
137146 operators :: OperatorTable () Type Box
138147 operators =
139148 OperatorTable [ [ AssocL typeApp $ \f x -> keepSingleLinesOr (moveRight 2) f x ]
140− , [ AssocR appliedFunction $ \arg ret -> keepSingleLinesOr id arg (text "-> " <> ret) ]
141− , [ Wrap constrained $ \deps ty -> constraintsAsBox deps ty ]
142− , [ Wrap forall_ $ \idents ty -> keepSingleLinesOr (moveRight 2) (text ("forall " ++ unwords idents ++ ".")) ty ]
143− , [ Wrap kinded $ \k ty -> keepSingleLinesOr (moveRight 2) ty (text (":: " ++ T.unpack (prettyPrintKind k))) ]
149+ , [ AssocR appliedFunction $ \arg ret -> keepSingleLinesOr id arg (text rightArrow <> " " <> ret) ]
150+ , [ Wrap constrained $ \deps ty -> constraintsAsBox tro deps ty ]
151+ , [ Wrap forall_ $ \idents ty -> keepSingleLinesOr (moveRight 2) (text (forall' ++ " " ++ unwords idents ++ ".")) ty ]
152+ , [ Wrap kinded $ \k ty -> keepSingleLinesOr (moveRight 2) ty (text (doubleColon ++ " " ++ T.unpack (prettyPrintKind k))) ]
144153 , [ Wrap explicitParens $ \_ ty -> ty ]
145154 ]
146155
156+ rightArrow = if troUnicode tro then "→" else "->"
157+ forall' = if troUnicode tro then "∀" else "forall"
158+ doubleColon = if troUnicode tro then "∷" else "::"
159+
147160 -- If both boxes span a single line, keep them on the same line, or else
148161 -- use the specified function to modify the second box, then combine vertically.
149162 keepSingleLinesOr :: (Box -> Box) -> Box -> Box -> Box
@@ -160,7 +173,7 @@ forall_ = mkPattern match
160173typeAtomAsBox :: Type -> Box
161174typeAtomAsBox
162175 = fromMaybe (internalError "Incomplete pattern")
163− . PA.pattern (matchTypeAtom False) ()
176+ . PA.pattern (matchTypeAtom defaultOptions) ()
164177 . insertPlaceholders
165178
166179-- | Generate a pretty-printed string representing a Type, as it should appear inside parentheses
@@ -168,21 +181,54 @@ prettyPrintTypeAtom :: Type -> String
168181prettyPrintTypeAtom = render . typeAtomAsBox
169182
170183typeAsBox :: Type -> Box
171−typeAsBox = typeAsBoxImpl False
184+typeAsBox = typeAsBoxImpl defaultOptions
172185
173186suggestedTypeAsBox :: Type -> Box
174−suggestedTypeAsBox = typeAsBoxImpl True
187+suggestedTypeAsBox = typeAsBoxImpl suggestingOptions
188+
189+data TypeRenderOptions = TypeRenderOptions
190+ { troSuggesting :: Bool
191+ , troUnicode :: Bool
192+ }
193+
194+suggestingOptions :: TypeRenderOptions
195+suggestingOptions = TypeRenderOptions True False
175196
176−typeAsBoxImpl :: Bool -> Type -> Box
177−typeAsBoxImpl suggesting
197+defaultOptions :: TypeRenderOptions
198+defaultOptions = TypeRenderOptions False False
199+
200+unicodeOptions :: TypeRenderOptions
201+unicodeOptions = TypeRenderOptions False True
202+
203+typeAsBoxImpl :: TypeRenderOptions -> Type -> Box
204+typeAsBoxImpl tro
178205 = fromMaybe (internalError "Incomplete pattern")
179− . PA.pattern (matchType suggesting) ()
206+ . PA.pattern (matchType tro) ()
180207 . insertPlaceholders
181208
182209-- | Generate a pretty-printed string representing a 'Type'
183210prettyPrintType :: Type -> String
184−prettyPrintType = render . typeAsBoxImpl False
211+prettyPrintType = prettyPrintType' defaultOptions
212+
213+-- | Generate a pretty-printed string representing a 'Type' using unicode
214+-- symbols where applicable
215+prettyPrintTypeWithUnicode :: Type -> String
216+prettyPrintTypeWithUnicode = prettyPrintType' unicodeOptions
185217
186218-- | Generate a pretty-printed string representing a suggested 'Type'
187219prettyPrintSuggestedType :: Type -> String
188−prettyPrintSuggestedType = render . typeAsBoxImpl True
220+prettyPrintSuggestedType = prettyPrintType' suggestingOptions
221+
222+prettyPrintType' :: TypeRenderOptions -> Type -> String
223+prettyPrintType' tro = render . typeAsBoxImpl tro
224+
225+prettyPrintLabel :: Label -> Text
226+prettyPrintLabel (Label s) =
227+ case decodeString s of
228+ Just s' | not (objectKeyRequiresQuoting s') ->
229+ s'
230+ _ ->
231+ prettyPrintString s
232+
233+prettyPrintObjectKey :: PSString -> Text
234+prettyPrintObjectKey = prettyPrintLabel . Label
src/Language/PureScript/Pretty/Values.hs+8−7
@@ -20,8 +20,9 @@ import Language.PureScript.AST
2020import Language.PureScript.Crash
2121import Language.PureScript.Names
2222import Language.PureScript.Pretty.Common
23−import Language.PureScript.Pretty.Types (typeAsBox, typeAtomAsBox)
23+import Language.PureScript.Pretty.Types (typeAsBox, typeAtomAsBox, prettyPrintObjectKey)
2424import Language.PureScript.Types (Constraint(..))
25+import Language.PureScript.PSString (PSString, prettyPrintString)
2526
2627import Text.PrettyPrint.Boxes
2728
@@ -40,10 +41,10 @@ list open close f xs = vcat left (zipWith toLine [0 :: Int ..] xs ++ [ text [ cl
4041ellipsis :: Box
4142ellipsis = text "..."
4243
43−prettyPrintObject :: Int -> [(Text, Maybe Expr)] -> Box
44+prettyPrintObject :: Int -> [(PSString, Maybe Expr)] -> Box
4445prettyPrintObject d = list '{' '}' prettyPrintObjectProperty
4546 where
46− prettyPrintObjectProperty :: (Text, Maybe Expr) -> Box
47+ prettyPrintObjectProperty :: (PSString, Maybe Expr) -> Box
4748 prettyPrintObjectProperty (key, value) = textT (prettyPrintObjectKey key Monoid.<> ": ") <> maybe (text "_") (prettyPrintValue (d - 1)) value
4849
4950-- | Pretty-print an expression
@@ -55,7 +56,7 @@ prettyPrintValue d (IfThenElse cond th el) =
5556 , text "else " <> prettyPrintValueAtom (d - 1) el
5657 ])
5758prettyPrintValue d (Accessor prop val) = prettyPrintValueAtom (d - 1) val `before` textT ("." Monoid.<> prettyPrintObjectKey prop)
58−prettyPrintValue d (ObjectUpdate o ps) = prettyPrintValueAtom (d - 1) o `beforeWithSpace` list '{' '}' (\(key, val) -> textT (key Monoid.<> " = ") <> prettyPrintValue (d - 1) val) ps
59+prettyPrintValue d (ObjectUpdate o ps) = prettyPrintValueAtom (d - 1) o `beforeWithSpace` list '{' '}' (\(key, val) -> textT (prettyPrintObjectKey key Monoid.<> " = ") <> prettyPrintValue (d - 1) val) ps
5960prettyPrintValue d (App val arg) = prettyPrintValueAtom (d - 1) val `beforeWithSpace` prettyPrintValueAtom (d - 1) arg
6061prettyPrintValue d (Abs (Left arg) val) = text ('\\' : T.unpack (showIdent arg) ++ " -> ") // moveRight 2 (prettyPrintValue (d - 1) val)
6162prettyPrintValue d (Abs (Right arg) val) = text ('\\' : T.unpack (prettyPrintBinder arg) ++ " -> ") // moveRight 2 (prettyPrintValue (d - 1) val)
@@ -105,7 +106,7 @@ prettyPrintValueAtom d expr = (text "(" <> prettyPrintValue d expr) `before` tex
105106
106107prettyPrintLiteralValue :: Int -> Literal Expr -> Box
107108prettyPrintLiteralValue _ (NumericLiteral n) = text $ either show show n
108−prettyPrintLiteralValue _ (StringLiteral s) = text $ show s
109+prettyPrintLiteralValue _ (StringLiteral s) = text $ T.unpack $ prettyPrintString s
109110prettyPrintLiteralValue _ (CharLiteral c) = text $ show c
110111prettyPrintLiteralValue _ (BooleanLiteral True) = text "true"
111112prettyPrintLiteralValue _ (BooleanLiteral False) = text "false"
@@ -169,7 +170,7 @@ prettyPrintBinderAtom (BinaryNoParensBinder op b1 b2) =
169170prettyPrintBinderAtom (ParensInBinder b) = parensT (prettyPrintBinder b)
170171
171172prettyPrintLiteralBinder :: Literal Binder -> Text
172−prettyPrintLiteralBinder (StringLiteral str) = T.pack (show str)
173+prettyPrintLiteralBinder (StringLiteral str) = prettyPrintString str
173174prettyPrintLiteralBinder (CharLiteral c) = T.pack (show c)
174175prettyPrintLiteralBinder (NumericLiteral num) = either (T.pack . show) (T.pack . show) num
175176prettyPrintLiteralBinder (BooleanLiteral True) = "true"
@@ -179,7 +180,7 @@ prettyPrintLiteralBinder (ObjectLiteral bs) =
179180 Monoid.<> T.intercalate ", " (map prettyPrintObjectPropertyBinder bs)
180181 Monoid.<> " }"
181182 where
182− prettyPrintObjectPropertyBinder :: (Text, Binder) -> Text
183+ prettyPrintObjectPropertyBinder :: (PSString, Binder) -> Text
183184 prettyPrintObjectPropertyBinder (key, binder) = prettyPrintObjectKey key Monoid.<> ": " Monoid.<> prettyPrintBinder binder
184185prettyPrintLiteralBinder (ArrayLiteral bs) =
185186 "[ "
src/Language/PureScript/Publish.hs+13−2
@@ -39,12 +39,13 @@ import Data.List (stripPrefix, (\\), nubBy)
3939import Data.List.NonEmpty (NonEmpty(..))
4040import Data.List.Split (splitOn)
4141import Data.Maybe
42−import Data.Version
43−import qualified Data.SPDX as SPDX
4442import Data.Text (Text)
4543import qualified Data.Text as T
4644import qualified Data.Text.Lazy as TL
4745import qualified Data.Text.Lazy.Encoding as TL
46+import Data.Time.Clock (UTCTime)
47+import Data.Version
48+import qualified Data.SPDX as SPDX
4849
4950import Safe (headMay)
5051
@@ -67,6 +68,7 @@ data PublishOptions = PublishOptions
6768 { -- | How to obtain the version tag and version that the data being
6869 -- generated will refer to.
6970 publishGetVersion :: PrepareM (Text, Version)
71+ , publishGetTagTime :: Text -> PrepareM UTCTime
7072 , -- | What to do when the working tree is dirty
7173 publishWorkingTreeDirty :: PrepareM ()
7274 }
@@ -74,6 +76,7 @@ data PublishOptions = PublishOptions
7476defaultPublishOptions :: PublishOptions
7577defaultPublishOptions = PublishOptions
7678 { publishGetVersion = getVersionFromGitTag
79+ , publishGetTagTime = getTagTime
7780 , publishWorkingTreeDirty = userError DirtyWorkingTree
7881 }
7982
@@ -139,6 +142,7 @@ preparePackage' opts = do
139142 checkLicense pkgMeta
140143
141144 (pkgVersionTag, pkgVersion) <- publishGetVersion opts
145+ pkgTagTime <- Just <$> publishGetTagTime opts pkgVersionTag
142146 pkgGithub <- getBowerRepositoryInfo pkgMeta
143147 (pkgBookmarks, pkgModules) <- getModulesAndBookmarks
144148
@@ -200,6 +204,13 @@ getVersionFromGitTag = do
200204 digits <- stripPrefix "v" str
201205 (str,) <$> D.parseVersion' digits
202206
207+-- | Given a git tag, get the time it was created.
208+getTagTime :: Text -> PrepareM UTCTime
209+getTagTime tag = do
210+ out <- readProcess' "git" ["show", T.unpack tag, "--no-patch", "--format=%aI"] ""
211+ let time = headMay (lines out) >>= D.parseTime
212+ maybe (internalError (CouldntParseGitTagDate tag)) pure time
213+
203214getBowerRepositoryInfo :: PackageMeta -> PrepareM (D.GithubUser, D.GithubRepo)
204215getBowerRepositoryInfo = either (userError . BadRepositoryField) return . tryExtract
205216 where
src/Language/PureScript/Publish/ErrorsWarnings.hs+4
@@ -73,6 +73,7 @@ data RepositoryFieldError
7373-- | An error that probably indicates a bug in this module.
7474data InternalError
7575 = JSONError JSONSource (ParseError BowerError)
76+ | CouldntParseGitTagDate Text
7677 deriving (Show)
7778
7879data JSONSource
@@ -289,6 +290,9 @@ displayInternalError e = case e of
289290 [ "Error in JSON " ++ displayJSONSource src ++ ":"
290291 , T.unpack (Bower.displayError r)
291292 ]
293+ CouldntParseGitTagDate tag ->
294+ [ "Unable to parse the date for a git tag: " ++ T.unpack tag
295+ ]
292296
293297displayJSONSource :: JSONSource -> String
294298displayJSONSource s = case s of
src/Language/PureScript/Sugar/DoNotation.hs+8−1
@@ -9,7 +9,6 @@ import Prelude.Compat
99import Control.Monad.Error.Class (MonadError(..))
1010import Control.Monad.Supply.Class
1111
12−
1312import Language.PureScript.AST
1413import Language.PureScript.Crash
1514import Language.PureScript.Errors
@@ -49,6 +48,8 @@ desugarDo d =
4948 return $ App (App bind val) (Abs (Left (Ident C.__unused)) rest')
5049 go [DoNotationBind _ _] = throwError . errorMessage $ InvalidDoBind
5150 go (DoNotationBind NullBinder val : rest) = go (DoNotationValue val : rest)
51+ go (DoNotationBind b _ : _) | Ident C.bind `elem` binderNames b =
52+ throwError . errorMessage $ CannotUseBindWithDo
5253 go (DoNotationBind (VarBinder ident) val : rest) = do
5354 rest' <- go rest
5455 return $ App (App bind val) (Abs (Left ident) rest')
@@ -58,6 +59,12 @@ desugarDo d =
5859 return $ App (App bind val) (Abs (Left ident) (Case [Var (Qualified Nothing ident)] [CaseAlternative [binder] (Right rest')]))
5960 go [DoNotationLet _] = throwError . errorMessage $ InvalidDoLet
6061 go (DoNotationLet ds : rest) = do
62+ let checkBind :: Declaration -> m ()
63+ checkBind (ValueDeclaration (Ident name) _ _ _)
64+ | name == C.bind = throwError . errorMessage $ CannotUseBindWithDo
65+ checkBind (PositionedDeclaration pos _ decl) = rethrowWithPosition pos (checkBind decl)
66+ checkBind _ = pure ()
67+ mapM_ checkBind ds
6168 rest' <- go rest
6269 return $ Let ds rest'
6370 go (PositionedDoNotationElement pos com el : rest) = rethrowWithPosition pos $ PositionedValue pos com <$> go (el : rest)
src/Language/PureScript/Sugar/Names/Env.hs+6−1
@@ -242,7 +242,12 @@ exportType
242242 -> m Exports
243243exportType exportMode exps name dctors mn = do
244244 let exTypes = exportedTypes exps
245− let exClasses = exportedTypeClasses exps
245+ exClasses = exportedTypeClasses exps
246+ dctorNameCounts :: [(ProperName 'ConstructorName, Int)]
247+ dctorNameCounts = M.toList $ M.fromListWith (+) (map (,1) dctors)
248+ forM_ dctorNameCounts $ \(dctorName, count) ->
249+ when (count > 1) $
250+ throwDeclConflict (DctorName dctorName) (DctorName dctorName)
246251 case exportMode of
247252 Internal -> do
248253 when (name `M.member` exTypes) $
src/Language/PureScript/Sugar/ObjectWildcards.hs+4−4
@@ -11,11 +11,11 @@ import Control.Monad.Supply.Class
1111
1212import Data.List (partition)
1313import Data.Maybe (catMaybes)
14−import Data.Text (Text)
1514
1615import Language.PureScript.AST
1716import Language.PureScript.Errors
1817import Language.PureScript.Names
18+import Language.PureScript.PSString (PSString)
1919
2020desugarObjectConstructors
2121 :: forall m
@@ -62,7 +62,7 @@ desugarDecl other = fn other
6262 return $ foldr (Abs . Left) if_ (catMaybes [u', t', f'])
6363 desugarExpr e = return e
6464
65− wrapLambda :: ([(Text, Expr)] -> Expr) -> [(Text, Expr)] -> m Expr
65+ wrapLambda :: ([(PSString, Expr)] -> Expr) -> [(PSString, Expr)] -> m Expr
6666 wrapLambda mkVal ps =
6767 let (args, props) = partition (isAnonymousArgument . snd) ps
6868 in if null args
@@ -75,7 +75,7 @@ desugarDecl other = fn other
7575 stripPositionInfo (PositionedValue _ _ e) = stripPositionInfo e
7676 stripPositionInfo e = e
7777
78− peelAnonAccessorChain :: Expr -> Maybe [Text]
78+ peelAnonAccessorChain :: Expr -> Maybe [PSString]
7979 peelAnonAccessorChain (Accessor p e) = (p :) <$> peelAnonAccessorChain e
8080 peelAnonAccessorChain (PositionedValue _ _ e) = peelAnonAccessorChain e
8181 peelAnonAccessorChain AnonymousArgument = Just []
@@ -86,7 +86,7 @@ desugarDecl other = fn other
8686 isAnonymousArgument (PositionedValue _ _ e) = isAnonymousArgument e
8787 isAnonymousArgument _ = False
8888
89− mkProp :: (Text, Expr) -> m (Maybe Ident, (Text, Expr))
89+ mkProp :: (PSString, Expr) -> m (Maybe Ident, (PSString, Expr))
9090 mkProp (name, e) = do
9191 arg <- freshIfAnon e
9292 return (arg, (name, maybe e argToExpr arg))
src/Language/PureScript/Sugar/TypeClasses.hs+4−2
@@ -19,6 +19,8 @@ import Language.PureScript.Externs
1919import Language.PureScript.Sugar.CaseDeclarations
2020import Control.Monad.Supply.Class
2121import Language.PureScript.Types
22+import Language.PureScript.Label (Label(..))
23+import Language.PureScript.PSString (mkString)
2224
2325import qualified Language.PureScript.Constants as C
2426
@@ -240,7 +242,7 @@ typeClassDictionaryDeclaration name args implies members =
240242 ]
241243 members' = map (first runIdent . memberToNameAndType) members
242244 mtys = members' ++ superclassTypes
243− in TypeSynonymDeclaration (coerceProperName name) args (TypeApp tyRecord $ rowFromList (mtys, REmpty))
245+ in TypeSynonymDeclaration (coerceProperName name) args (TypeApp tyRecord $ rowFromList (map (first (Label . mkString)) mtys, REmpty))
244246
245247typeClassMemberToDictionaryAccessor
246248 :: ModuleName
@@ -297,7 +299,7 @@ typeInstanceDictionaryDeclaration name mn deps className tys decls =
297299 , let tyArgs = map (replaceAllTypeVars (zip (map fst typeClassArguments) tys)) suTyArgs
298300 ]
299301
300− let props = Literal $ ObjectLiteral (members ++ superclasses)
302+ let props = Literal $ ObjectLiteral $ map (first mkString) (members ++ superclasses)
301303 dictTy = foldl TypeApp (TypeConstructor (fmap coerceProperName className)) tys
302304 constrainedTy = quantify (if null deps then dictTy else ConstrainedType deps dictTy)
303305 dict = TypeClassDictionaryConstructorApp className props
src/Language/PureScript/Sugar/TypeClasses/Deriving.hs+39−24
@@ -11,9 +11,11 @@ import Control.Monad.Error.Class (MonadError(..))
1111import Control.Monad.Supply.Class (MonadSupply)
1212import Data.List (foldl', find, sortBy, unzip5)
1313import qualified Data.Map as M
14+import Data.Monoid ((<>))
1415import Data.Maybe (fromMaybe, mapMaybe)
1516import Data.Ord (comparing)
1617import Data.Text (Text)
18+import qualified Data.Text as T
1719import Language.PureScript.AST
1820import qualified Language.PureScript.Constants as C
1921import Language.PureScript.Crash
@@ -22,6 +24,8 @@ import Language.PureScript.Errors
2224import Language.PureScript.Externs
2325import Language.PureScript.Kinds
2426import Language.PureScript.Names
27+import Language.PureScript.Label (Label(..))
28+import Language.PureScript.PSString (mkString, decodeStringEither)
2529import Language.PureScript.Types
2630import Language.PureScript.TypeChecker (checkNewtype)
2731import Language.PureScript.TypeChecker.Synonyms (SynonymMap, replaceAllTypeSynonymsM)
@@ -207,7 +211,7 @@ deriveGeneric mn syns ds tyConNm dargs = do
207211 idents <- replicateM (length tys) freshIdent'
208212 tys' <- mapM (replaceAllTypeSynonymsM syns) tys
209213 let caseResult =
210− App (prodConstructor (Literal . StringLiteral . showQualified runProperName $ Qualified (Just mn) ctorName))
214+ App (prodConstructor (Literal . StringLiteral . mkString . showQualified runProperName $ Qualified (Just mn) ctorName))
211215 . Literal . ArrayLiteral
212216 $ zipWith toSpineFun (map (Var . Qualified Nothing) idents) tys'
213217 return $ CaseAlternative [ConstructorBinder (Qualified (Just mn) ctorName) (map VarBinder idents)] (Right caseResult)
@@ -216,7 +220,7 @@ deriveGeneric mn syns ds tyConNm dargs = do
216220 toSpineFun i r | Just rec <- objectType r =
217221 lamNull . recordConstructor . Literal . ArrayLiteral
218222 . map
219− (\(str,typ) ->
223+ (\((Label str),typ) ->
220224 Literal $ ObjectLiteral
221225 [ ("recLabel", Literal (StringLiteral str))
222226 , ("recValue", toSpineFun (Accessor str i) typ)
@@ -235,7 +239,7 @@ deriveGeneric mn syns ds tyConNm dargs = do
235239 App
236240 (App
237241 (Constructor (Qualified (Just dataGeneric) (ProperName "SigProd")))
238− (Literal (StringLiteral (showQualified runProperName (Qualified (Just mn) name))))
242+ (Literal (StringLiteral $ mkString (showQualified runProperName (Qualified (Just mn) name))))
239243 )
240244 . Literal
241245 . ArrayLiteral
@@ -249,7 +253,7 @@ deriveGeneric mn syns ds tyConNm dargs = do
249253 mkProdClause :: (ProperName 'ConstructorName, [Type]) -> Expr
250254 mkProdClause (ctorName, tys) =
251255 Literal $ ObjectLiteral
252− [ ("sigConstructor", Literal (StringLiteral (showQualified runProperName (Qualified (Just mn) ctorName))))
256+ [ ("sigConstructor", Literal (StringLiteral $ mkString (showQualified runProperName (Qualified (Just mn) ctorName))))
253257 , ("sigValues", Literal . ArrayLiteral . map (mkProductSignature . instantiate) $ tys)
254258 ]
255259
@@ -260,7 +264,7 @@ deriveGeneric mn syns ds tyConNm dargs = do
260264 [ ("recLabel", Literal (StringLiteral str))
261265 , ("recValue", mkProductSignature typ)
262266 ]
263− | (str, typ) <- decomposeRec rec
267+ | ((Label str), typ) <- decomposeRec rec
264268 ]
265269 mkProductSignature typ = lamNull $ App (mkGenVar (Ident C.toSignature))
266270 (TypedValue False (mkGenVar (Ident "anyProxy")) (proxy typ))
@@ -291,7 +295,7 @@ deriveGeneric mn syns ds tyConNm dargs = do
291295 return $
292296 CaseAlternative
293297 [ prodBinder
294− [ LiteralBinder (StringLiteral (showQualified runProperName (Qualified (Just mn) ctorName)))
298+ [ LiteralBinder (StringLiteral $ mkString (showQualified runProperName (Qualified (Just mn) ctorName)))
295299 , LiteralBinder (ArrayLiteral (map VarBinder idents))
296300 ]
297301 ]
@@ -314,16 +318,16 @@ deriveGeneric mn syns ds tyConNm dargs = do
314318 (App e unitVal)
315319 fromSpineFun e _ = App (mkGenVar (Ident C.fromSpine)) (App e unitVal)
316320
317− mkRecCase :: [(Text, Type)] -> CaseAlternative
321+ mkRecCase :: [(Label, Type)] -> CaseAlternative
318322 mkRecCase rs =
319323 CaseAlternative
320− [ recordBinder [ LiteralBinder (ArrayLiteral (map (VarBinder . Ident . fst) rs)) ] ]
324+ [ recordBinder [ LiteralBinder (ArrayLiteral (map (VarBinder . labelToIdent . fst) rs)) ] ]
321325 . Right
322− $ liftApplicative (mkRecFun rs) (map (\(x, y) -> fromSpineFun (Accessor "recValue" (mkVar (Ident x))) y) rs)
326+ $ liftApplicative (mkRecFun rs) (map (\(x, y) -> fromSpineFun (Accessor "recValue" (mkVar $ labelToIdent x)) y) rs)
323327
324− mkRecFun :: [(Text, Type)] -> Expr
325− mkRecFun xs = mkJust $ foldr (lam . Ident . fst) recLiteral xs
326− where recLiteral = Literal . ObjectLiteral $ map (\(s,_) -> (s, mkVar (Ident s))) xs
328+ mkRecFun :: [(Label, Type)] -> Expr
329+ mkRecFun xs = mkJust $ foldr (lam . labelToIdent . fst) recLiteral xs
330+ where recLiteral = Literal . ObjectLiteral $ map (\(l@(Label s), _) -> (s, mkVar $ labelToIdent l)) xs
327331 mkFromSpineFunction (PositionedDeclaration _ _ d) = mkFromSpineFunction d
328332 mkFromSpineFunction _ = internalError "mkFromSpineFunction: expected DataDeclaration"
329333
@@ -405,7 +409,7 @@ deriveGenericRep mn syns ds tyConNm tyConArgs repTy = do
405409 args' <- mapM (replaceAllTypeSynonymsM syns) args
406410 (ctorTy, matchProduct, ctorArgs, matchCtor, mkProduct) <- makeProduct args'
407411 return ( TypeApp (TypeApp (TypeConstructor constructor)
408− (TypeLevelString (runProperName ctorName)))
412+ (TypeLevelString $ mkString (runProperName ctorName)))
409413 ctorTy
410414 , CaseAlternative [ ConstructorBinder constructor [matchProduct] ]
411415 (Right (foldl App (Constructor (Qualified (Just mn) ctorName)) ctorArgs))
@@ -430,19 +434,19 @@ deriveGenericRep mn syns ds tyConNm tyConArgs repTy = do
430434 makeArg :: Type -> m (Type, Binder, Expr, Binder, Expr)
431435 makeArg arg | Just rec <- objectType arg = do
432436 let fields = decomposeRec rec
433− fieldNames <- traverse freshIdent (map fst fields)
437+ fieldNames <- traverse freshIdent (map (runIdent . labelToIdent . fst) fields)
434438 pure ( TypeApp (TypeConstructor record)
435439 (foldr1 (\f -> TypeApp (TypeApp (TypeConstructor productName) f))
436− (map (\(name, ty) ->
440+ (map (\((Label name), ty) ->
437441 TypeApp (TypeApp (TypeConstructor field) (TypeLevelString name)) ty) fields))
438442 , ConstructorBinder record
439443 [ foldr1 (\b1 b2 -> ConstructorBinder productName [b1, b2])
440444 (map (\ident -> ConstructorBinder field [VarBinder ident]) fieldNames)
441445 ]
442446 , Literal . ObjectLiteral $
443− zipWith (\(name, _) ident -> (name, Var (Qualified Nothing ident))) fields fieldNames
447+ zipWith (\((Label name), _) ident -> (name, Var (Qualified Nothing ident))) fields fieldNames
444448 , LiteralBinder . ObjectLiteral $
445− zipWith (\(name, _) ident -> (name, VarBinder ident)) fields fieldNames
449+ zipWith (\((Label name), _) ident -> (name, VarBinder ident)) fields fieldNames
446450 , record' $
447451 foldr1 (\e1 -> App (App (Constructor productName) e1))
448452 (map (field' . Var . Qualified Nothing) fieldNames)
@@ -574,7 +578,7 @@ deriveEq mn syns ds tyConNm = do
574578 toEqTest :: Expr -> Expr -> Type -> Expr
575579 toEqTest l r ty | Just rec <- objectType ty =
576580 conjAll
577− . map (\(str, typ) -> toEqTest (Accessor str l) (Accessor str r) typ)
581+ . map (\((Label str), typ) -> toEqTest (Accessor str l) (Accessor str r) typ)
578582 $ decomposeRec rec
579583 toEqTest l r _ = preludeEq l r
580584
@@ -661,7 +665,7 @@ deriveOrd mn syns ds tyConNm = do
661665 toOrdering :: Expr -> Expr -> Type -> Expr
662666 toOrdering l r ty | Just rec <- objectType ty =
663667 appendAll
664− . map (\(str, typ) -> toOrdering (Accessor str l) (Accessor str r) typ)
668+ . map (\((Label str), typ) -> toOrdering (Accessor str l) (Accessor str r) typ)
665669 $ decomposeRec rec
666670 toOrdering l r _ = ordCompare l r
667671
@@ -733,11 +737,22 @@ mkVarMn mn = Var . Qualified mn
733737mkVar :: Ident -> Expr
734738mkVar = mkVarMn Nothing
735739
740+-- This function may seem a little obtuse, but it's only this way to ensure
741+-- that it is injective. Injectivity is important here; without it, we can end
742+-- up with accidental variable shadowing in the generated code.
743+labelToIdent :: Label -> Ident
744+labelToIdent =
745+ Ident . foldMap (either loneSurrogate char) . decodeStringEither . runLabel
746+ where
747+ char '_' = "__"
748+ char c = T.singleton c
749+ loneSurrogate x = "_" <> T.pack (show x) <> "_"
750+
736751objectType :: Type -> Maybe Type
737752objectType (TypeApp (TypeConstructor (Qualified (Just (ModuleName [ProperName "Prim"])) (ProperName "Record"))) rec) = Just rec
738753objectType _ = Nothing
739754
740−decomposeRec :: Type -> [(Text, Type)]
755+decomposeRec :: Type -> [(Label, Type)]
741756decomposeRec = sortBy (comparing fst) . go
742757 where go (RCons str typ typs) = (str, typ) : decomposeRec typs
743758 go _ = []
@@ -790,17 +805,17 @@ deriveFunctor mn syns ds tyConNm = do
790805 goType recTy | Just row <- objectType recTy =
791806 traverse buildUpdate (decomposeRec row) >>= (traverse buildRecord . justUpdates)
792807 where
793− justUpdates :: [Maybe (Text, Expr)] -> Maybe [(Text, Expr)]
808+ justUpdates :: [Maybe (Label, Expr)] -> Maybe [(Label, Expr)]
794809 justUpdates = foldMap (fmap return)
795810
796− buildUpdate :: (Text, Type) -> m (Maybe (Text, Expr))
811+ buildUpdate :: (Label, Type) -> m (Maybe (Label, Expr))
797812 buildUpdate (lbl, ty) = do upd <- goType ty
798813 return ((lbl,) <$> upd)
799814
800− buildRecord :: [(Text, Expr)] -> m Expr
815+ buildRecord :: [(Label, Expr)] -> m Expr
801816 buildRecord updates = do arg <- freshIdent "o"
802817 let argVar = mkVar arg
803− mkAssignment (l, x) = (l, App x (Accessor l argVar))
818+ mkAssignment ((Label l), x) = (l, App x (Accessor l argVar))
804819 return (lam arg (ObjectUpdate argVar (mkAssignment <$> updates)))
805820
806821 -- under a `* -> *`, just assume functor for now
src/Language/PureScript/TypeChecker/Entailment.hs+6−4
@@ -37,13 +37,15 @@ import Language.PureScript.TypeChecker.Monad
3737import Language.PureScript.TypeChecker.Unify
3838import Language.PureScript.TypeClassDictionaries
3939import Language.PureScript.Types
40+import Language.PureScript.Label (Label(..))
41+import Language.PureScript.PSString (PSString, mkString)
4042import qualified Language.PureScript.Constants as C
4143
4244-- | Describes what sort of dictionary to generate for type class instances
4345data Evidence
4446 = NamedInstance (Qualified Ident)
4547 -- ^ An existing named instance
46− | IsSymbolInstance Text
48+ | IsSymbolInstance PSString
4749 -- ^ Computed instance of the IsSymbol type class for a given Symbol literal
4850 | CompareSymbolInstance
4951 -- ^ Computed instance of CompareSymbol
@@ -319,7 +321,7 @@ entails SolverOptions{..} constraint context hints =
319321 -- Turn a DictionaryValue into a Expr
320322 subclassDictionaryValue :: Expr -> Qualified (ProperName a) -> Integer -> Expr
321323 subclassDictionaryValue dict superclassName index =
322− App (Accessor (C.__superclass_ <> showQualified runProperName superclassName <> "_" <> T.pack (show index))
324+ App (Accessor (mkString (C.__superclass_ <> showQualified runProperName superclassName <> "_" <> T.pack (show index)))
323325 dict)
324326 valUndefined
325327
@@ -387,7 +389,7 @@ matches deps TypeClassDictionaryInScope{..} tys = do
387389 sd1 = [ (name, t1) | (name, t1) <- s1, name `notElem` map fst s2 ]
388390 sd2 = [ (name, t2) | (name, t2) <- s2, name `notElem` map fst s1 ]
389391
390− go :: [(Text, Type)] -> Type -> [(Text, Type)] -> Type -> (Bool, Matching [Type])
392+ go :: [(Label, Type)] -> Type -> [(Label, Type)] -> Type -> (Bool, Matching [Type])
391393 go l (KindedType t1 _) r t2 = go l t1 r t2
392394 go l t1 r (KindedType t2 _) = go l t1 r t2
393395 go [] REmpty [] REmpty = (True, M.empty)
@@ -429,7 +431,7 @@ matches deps TypeClassDictionaryInScope{..} tys = do
429431 sd2 = [ (name, t2) | (name, t2) <- s2, name `notElem` map fst s1 ]
430432 in all (uncurry typesAreEqual) int && go sd1 r1' sd2 r2'
431433 where
432− go :: [(Text, Type)] -> Type -> [(Text, Type)] -> Type -> Bool
434+ go :: [(Label, Type)] -> Type -> [(Label, Type)] -> Type -> Bool
433435 go l (KindedType t1 _) r t2 = go l t1 r t2
434436 go l t1 r (KindedType t2 _) = go l t1 r t2
435437 go [] (TUnknown u1) [] (TUnknown u2) | u1 == u2 = True
src/Language/PureScript/TypeChecker/Kinds.hs+1
@@ -229,6 +229,7 @@ infer' other = (, []) <$> go other
229229 unifyKinds k k'
230230 return k'
231231 go TypeWildcard{} = freshKind
232+ go TUnknown{} = freshKind
232233 go (TypeLevelString _) = return kindSymbol
233234 go (TypeVar v) = do
234235 Just moduleName <- checkCurrentModule <$> get
src/Language/PureScript/TypeChecker/Types.hs+146−124
@@ -34,14 +34,14 @@ import Control.Monad.Supply.Class (MonadSupply)
3434import Control.Monad.Writer.Class (MonadWriter(..))
3535
3636import Data.Bifunctor (bimap)
37−import Data.Either (lefts, rights)
37+import Data.Either (partitionEithers)
3838import Data.Functor (($>))
3939import Data.List (transpose, nub, (\\), partition, delete)
4040import Data.Maybe (fromMaybe)
4141import Data.Monoid ((<>))
4242import qualified Data.Map as M
4343import qualified Data.Set as S
44−import Data.Text (Text)
44+import Data.Traversable (for)
4545
4646import Language.PureScript.AST
4747import Language.PureScript.Crash
@@ -60,7 +60,8 @@ import Language.PureScript.TypeChecker.Synonyms
6060import Language.PureScript.TypeChecker.TypeSearch
6161import Language.PureScript.TypeChecker.Unify
6262import Language.PureScript.Types
63−
63+import Language.PureScript.Label (Label(..))
64+import Language.PureScript.PSString (PSString)
6465
6566data BindingGroupType
6667 = RecursiveBindingGroup
@@ -77,9 +78,9 @@ typesOf
7778 -> m [(Ident, (Expr, Type))]
7879typesOf bindingGroupType moduleName vals = withFreshSubstitution $ do
7980 tys <- capturingSubstitution tidyUp $ do
80− (untyped, typed, dict, untypedDict) <- typeDictionaryForBindingGroup (Just moduleName) vals
81+ SplitBindingGroup untyped typed dict <- typeDictionaryForBindingGroup (Just moduleName) vals
8182 ds1 <- parU typed $ \e -> withoutWarnings $ checkTypedBindingGroupElement moduleName e dict
82− ds2 <- forM untyped $ \e -> withoutWarnings $ typeForBindingGroupElement e dict untypedDict
83+ ds2 <- forM untyped $ \e -> withoutWarnings $ typeForBindingGroupElement e dict
8384 return (map (False, ) ds1 ++ map (True, ) ds2)
8485
8586 inferred <- forM tys $ \(shouldGeneralize, ((ident, (val, ty)), _)) -> do
@@ -165,81 +166,101 @@ typesOf bindingGroupType moduleName vals = withFreshSubstitution $ do
165166 isHoleError (ErrorMessage _ HoleInferredType{}) = True
166167 isHoleError _ = False
167168
168−type TypeData = M.Map (Qualified Ident) (Type, NameKind, NameVisibility)
169−
170−type UntypedData = [(Ident, Type)]
171−
169+-- | A binding group contains multiple value definitions, some of which are typed
170+-- and some which are not.
171+--
172+-- This structure breaks down a binding group into typed and untyped parts.
173+data SplitBindingGroup = SplitBindingGroup
174+ { _splitBindingGroupUntyped :: [(Ident, (Expr, Type))]
175+ -- ^ The untyped expressions
176+ , _splitBindingGroupTyped :: [(Ident, (Expr, Type, Bool))]
177+ -- ^ The typed expressions, along with their type annotations
178+ , _splitBindingGroupNames :: M.Map (Qualified Ident) (Type, NameKind, NameVisibility)
179+ -- ^ A map containing all expressions and their assigned types (which might be
180+ -- fresh unification variables). These will be added to the 'Environment' after
181+ -- the binding group is checked, so the value type of the 'Map' is chosen to be
182+ -- compatible with the type of 'bindNames'.
183+ }
184+
185+-- | This function breaks a binding group down into two sets of declarations:
186+-- those which contain type annotations, and those which don't.
187+-- This function also generates fresh unification variables for the types of
188+-- declarations without type annotations, returned in the 'UntypedData' structure.
172189typeDictionaryForBindingGroup
173− :: (MonadState CheckState m)
190+ :: (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
174191 => Maybe ModuleName
175192 -> [(Ident, Expr)]
176− -> m ([(Ident, Expr)], [(Ident, (Expr, Type, Bool))], TypeData, UntypedData)
193+ -> m SplitBindingGroup
177194typeDictionaryForBindingGroup moduleName vals = do
178− let
179− -- Map each declaration to a name/value pair, with an optional type, if the declaration is typed
180− es = map isTyped vals
181− -- Filter the typed and untyped declarations
182− untyped = lefts es
183− typed = rights es
184− -- Make a map of names to typed declarations
185− typedDict = map (\(ident, (_, ty, _)) -> (ident, ty)) typed
186−
187− -- Create fresh unification variables for the types of untyped declarations
188− untypedNames <- replicateM (length untyped) freshType
189−
190− let
191− -- Make a map of names to the unification variables of untyped declarations
192− untypedDict = zip (map fst untyped) untypedNames
193− -- Create the dictionary of all name/type pairs, which will be added to the environment during type checking
194− dict = M.fromList (map (\(ident, ty) -> (Qualified moduleName ident, (ty, Private, Undefined))) $ typedDict ++ untypedDict)
195− return (untyped, typed, dict, untypedDict)
196−
195+ -- Filter the typed and untyped declarations and make a map of names to typed declarations.
196+ -- Replace type wildcards here so that the resulting dictionary of types contains the
197+ -- fully expanded types.
198+ let (untyped, typed) = partitionEithers (map splitTypeAnnotation vals)
199+ (typedDict, typed') <- fmap unzip . for typed $ \(ident, (expr, ty, checkType)) -> do
200+ ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< replaceTypeWildcards $ ty
201+ return ((ident, ty'), (ident, (expr, ty', checkType)))
202+ -- Create fresh unification variables for the types of untyped declarations
203+ (untypedDict, untyped') <- fmap unzip . for untyped $ \(ident, expr) -> do
204+ ty <- freshType
205+ return ((ident, ty), (ident, (expr, ty)))
206+ -- Create the dictionary of all name/type pairs, which will be added to the
207+ -- environment during type checking
208+ let dict = M.fromList [ (Qualified moduleName ident, (ty, Private, Undefined))
209+ | (ident, ty) <- typedDict <> untypedDict
210+ ]
211+ return (SplitBindingGroup untyped' typed' dict)
212+ where
213+ -- | Check if a value contains a type annotation, and if so, separate it
214+ -- from the value itself.
215+ splitTypeAnnotation :: (Ident, Expr) -> Either (Ident, Expr) (Ident, (Expr, Type, Bool))
216+ splitTypeAnnotation (name, TypedValue checkType value ty) = Right (name, (value, ty, checkType))
217+ splitTypeAnnotation (name, PositionedValue pos c value) =
218+ bimap (second (PositionedValue pos c))
219+ (second (\(e, t, b) -> (PositionedValue pos c e, t, b)))
220+ (splitTypeAnnotation (name, value))
221+ splitTypeAnnotation (name, value) = Left (name, value)
222+
223+-- | Check the type annotation of a typed value in a binding group.
197224checkTypedBindingGroupElement
198225 :: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
199226 => ModuleName
200227 -> (Ident, (Expr, Type, Bool))
201− -> TypeData
228+ -- ^ The identifier we are trying to define, along with the expression and its type annotation
229+ -> M.Map (Qualified Ident) (Type, NameKind, NameVisibility)
230+ -- ^ Names brought into scope in this binding group
202231 -> m (Ident, (Expr, Type))
203−checkTypedBindingGroupElement mn (ident, (val', ty, checkType)) dict = do
204− -- Replace type wildcards
205− ty' <- replaceTypeWildcards ty
232+checkTypedBindingGroupElement mn (ident, (val, ty, checkType)) dict = do
206233 -- Kind check
207234 (kind, args) <- kindOfWithScopedVars ty
208235 checkTypeKind ty kind
209236 -- Check the type with the new names in scope
210− ty'' <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< replaceTypeWildcards $ ty'
211− val'' <- if checkType
212− then withScopedTypeVars mn args $ bindNames dict $ TypedValue True <$> check val' ty'' <*> pure ty''
213− else return (TypedValue False val' ty'')
214− return (ident, (val'', ty''))
237+ val' <- if checkType
238+ then withScopedTypeVars mn args $ bindNames dict $ TypedValue True <$> check val ty <*> pure ty
239+ else return (TypedValue False val ty)
240+ return (ident, (val', ty))
215241
242+-- | Infer a type for a value in a binding group which lacks an annotation.
216243typeForBindingGroupElement
217244 :: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
218− => (Ident, Expr)
219− -> TypeData
220− -> UntypedData
245+ => (Ident, (Expr, Type))
246+ -- ^ The identifier we are trying to define, along with the expression and its assigned type
247+ -- (at this point, this should be a unification variable)
248+ -> M.Map (Qualified Ident) (Type, NameKind, NameVisibility)
249+ -- ^ Names brought into scope in this binding group
221250 -> m (Ident, (Expr, Type))
222−typeForBindingGroupElement (ident, val) dict untypedDict = do
251+typeForBindingGroupElement (ident, (val, ty)) dict = do
223252 -- Infer the type with the new names in scope
224− TypedValue _ val' ty <- bindNames dict $ infer val
225− unifyTypes ty $ fromMaybe (internalError "name not found in dictionary") (lookup ident untypedDict)
226− return (ident, (TypedValue True val' ty, ty))
227−
228−-- | Check if a value contains a type annotation
229−isTyped :: (Ident, Expr) -> Either (Ident, Expr) (Ident, (Expr, Type, Bool))
230−isTyped (name, TypedValue checkType value ty) = Right (name, (value, ty, checkType))
231−isTyped (name, PositionedValue pos c value) =
232− bimap (second (PositionedValue pos c))
233− (second (\(e, t, b) -> (PositionedValue pos c e, t, b)))
234− (isTyped (name, value))
235−isTyped (name, value) = Left (name, value)
253+ TypedValue _ val' ty' <- bindNames dict $ infer val
254+ -- Unify the type with the unification variable we chose for this definition
255+ unifyTypes ty ty'
256+ return (ident, (TypedValue True val' ty', ty'))
236257
237258-- | Check the kind of a type, failing if it is not of kind *.
238−checkTypeKind ::
239− (MonadError MultipleErrors m) =>
240− Type ->
241− Kind ->
242− m ()
259+checkTypeKind
260+ :: MonadError MultipleErrors m
261+ => Type
262+ -> Kind
263+ -> m ()
243264checkTypeKind ty kind = guardWith (errorMessage (ExpectedType ty kind)) $ kind == kindType
244265
245266-- | Remove any ForAlls and ConstrainedType constructors in a type by introducing new unknowns
@@ -247,11 +268,11 @@ checkTypeKind ty kind = guardWith (errorMessage (ExpectedType ty kind)) $ kind =
247268--
248269-- This is necessary during type checking to avoid unifying a polymorphic type with a
249270-- unification variable.
250−instantiatePolyTypeWithUnknowns ::
251− (MonadState CheckState m, MonadError MultipleErrors m) =>
252− Expr ->
253− Type ->
254− m (Expr, Type)
271+instantiatePolyTypeWithUnknowns
272+ :: (MonadState CheckState m, MonadError MultipleErrors m)
273+ => Expr
274+ -> Type
275+ -> m (Expr, Type)
255276instantiatePolyTypeWithUnknowns val (ForAll ident ty _) = do
256277 ty' <- replaceVarWithUnknown ident ty
257278 instantiatePolyTypeWithUnknowns val ty'
@@ -262,17 +283,17 @@ instantiatePolyTypeWithUnknowns val (ConstrainedType constraints ty) = do
262283instantiatePolyTypeWithUnknowns val ty = return (val, ty)
263284
264285-- | Infer a type for a value, rethrowing any error to provide a more useful error message
265−infer ::
266− (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) =>
267− Expr ->
268− m Expr
286+infer
287+ :: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
288+ => Expr
289+ -> m Expr
269290infer val = withErrorMessageHint (ErrorInferringType val) $ infer' val
270291
271292-- | Infer a type for a value
272−infer' ::
273− (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) =>
274− Expr ->
275− m Expr
293+infer'
294+ :: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
295+ => Expr
296+ -> m Expr
276297infer' v@(Literal (NumericLiteral (Left _))) = return $ TypedValue True v tyInt
277298infer' v@(Literal (NumericLiteral (Right _))) = return $ TypedValue True v tyNumber
278299infer' v@(Literal (StringLiteral _)) = return $ TypedValue True v tyString
@@ -289,22 +310,22 @@ infer' (Literal (ArrayLiteral vals)) = do
289310infer' (Literal (ObjectLiteral ps)) = do
290311 ensureNoDuplicateProperties ps
291312 ts <- traverse (infer . snd) ps
292− let fields = zipWith (\name (TypedValue _ _ t) -> (name, t)) (map fst ps) ts
313+ let fields = zipWith (\name (TypedValue _ _ t) -> (Label name, t)) (map fst ps) ts
293314 ty = TypeApp tyRecord $ rowFromList (fields, REmpty)
294315 return $ TypedValue True (Literal (ObjectLiteral (zip (map fst ps) ts))) ty
295316infer' (ObjectUpdate o ps) = do
296317 ensureNoDuplicateProperties ps
297318 row <- freshType
298319 newVals <- zipWith (\(name, _) t -> (name, t)) ps <$> traverse (infer . snd) ps
299− let newTys = map (\(name, TypedValue _ _ ty) -> (name, ty)) newVals
300− oldTys <- zip (map fst ps) <$> replicateM (length ps) freshType
320+ let newTys = map (\(name, TypedValue _ _ ty) -> (Label name, ty)) newVals
321+ oldTys <- zip (map (Label . fst) ps) <$> replicateM (length ps) freshType
301322 let oldTy = TypeApp tyRecord $ rowFromList (oldTys, row)
302323 o' <- TypedValue True <$> check o oldTy <*> pure oldTy
303324 return $ TypedValue True (ObjectUpdate o' newVals) $ TypeApp tyRecord $ rowFromList (newTys, row)
304325infer' (Accessor prop val) = withErrorMessageHint (ErrorCheckingAccessor val prop) $ do
305326 field <- freshType
306327 rest <- freshType
307− typed <- check val (TypeApp tyRecord (RCons prop field rest))
328+ typed <- check val (TypeApp tyRecord (RCons (Label prop) field rest))
308329 return $ TypedValue True (Accessor prop typed) field
309330infer' (Abs (Left arg) ret) = do
310331 ty <- freshType
@@ -369,13 +390,13 @@ infer' (PositionedValue pos c val) = warnAndRethrowWithPositionTC pos $ do
369390 return $ TypedValue t (PositionedValue pos c v) ty
370391infer' v = internalError $ "Invalid argument to infer: " ++ show v
371392
372−inferLetBinding ::
373− (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) =>
374− [Declaration] ->
375− [Declaration] ->
376− Expr ->
377− (Expr -> m Expr) ->
378− m ([Declaration], Expr)
393+inferLetBinding
394+ :: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
395+ => [Declaration]
396+ -> [Declaration]
397+ -> Expr
398+ -> (Expr -> m Expr)
399+ -> m ([Declaration], Expr)
379400inferLetBinding seen [] ret j = (,) seen <$> withBindingGroupVisible (j ret)
380401inferLetBinding seen (ValueDeclaration ident nameKind [] (Right (tv@(TypedValue checkType val ty))) : rest) ret j = do
381402 Just moduleName <- checkCurrentModule <$> get
@@ -393,9 +414,9 @@ inferLetBinding seen (ValueDeclaration ident nameKind [] (Right val) : rest) ret
393414 bindNames (M.singleton (Qualified Nothing ident) (valTy', nameKind, Defined)) $ inferLetBinding (seen ++ [ValueDeclaration ident nameKind [] (Right val')]) rest ret j
394415inferLetBinding seen (BindingGroupDeclaration ds : rest) ret j = do
395416 Just moduleName <- checkCurrentModule <$> get
396− (untyped, typed, dict, untypedDict) <- typeDictionaryForBindingGroup Nothing (map (\(i, _, v) -> (i, v)) ds)
417+ SplitBindingGroup untyped typed dict <- typeDictionaryForBindingGroup Nothing (map (\(i, _, v) -> (i, v)) ds)
397418 ds1' <- parU typed $ \e -> checkTypedBindingGroupElement moduleName e dict
398− ds2' <- forM untyped $ \e -> typeForBindingGroupElement e dict untypedDict
419+ ds2' <- forM untyped $ \e -> typeForBindingGroupElement e dict
399420 let ds' = [(ident, Private, val') | (ident, (val', _)) <- ds1' ++ ds2']
400421 bindNames dict $ do
401422 makeBindingGroupVisible
@@ -406,11 +427,12 @@ inferLetBinding seen (PositionedDeclaration pos com d : ds) ret j = warnAndRethr
406427inferLetBinding _ _ _ _ = internalError "Invalid argument to inferLetBinding"
407428
408429-- | Infer the types of variables brought into scope by a binder
409−inferBinder :: forall m.
410− (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) =>
411− Type ->
412− Binder ->
413− m (M.Map Ident Type)
430+inferBinder
431+ :: forall m
432+ . (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
433+ => Type
434+ -> Binder
435+ -> m (M.Map Ident Type)
414436inferBinder _ NullBinder = return M.empty
415437inferBinder val (LiteralBinder (StringLiteral _)) = unifyTypes val tyString >> return M.empty
416438inferBinder val (LiteralBinder (CharLiteral _)) = unifyTypes val tyChar >> return M.empty
@@ -442,12 +464,12 @@ inferBinder val (LiteralBinder (ObjectLiteral props)) = do
442464 unifyTypes val (TypeApp tyRecord row)
443465 return m1
444466 where
445− inferRowProperties :: Type -> Type -> [(Text, Binder)] -> m (M.Map Ident Type)
467+ inferRowProperties :: Type -> Type -> [(PSString, Binder)] -> m (M.Map Ident Type)
446468 inferRowProperties nrow row [] = unifyTypes nrow row >> return M.empty
447469 inferRowProperties nrow row ((name, binder):binders) = do
448470 propTy <- freshType
449471 m1 <- inferBinder propTy binder
450− m2 <- inferRowProperties nrow (RCons name propTy row) binders
472+ m2 <- inferRowProperties nrow (RCons (Label name) propTy row) binders
451473 return $ m1 `M.union` m2
452474inferBinder val (LiteralBinder (ArrayLiteral binders)) = do
453475 el <- freshType
@@ -485,11 +507,11 @@ binderRequiresMonotype (PositionedBinder _ _ b) = binderRequiresMonotype b
485507binderRequiresMonotype _ = True
486508
487509-- | Instantiate polytypes only when necessitated by a binder.
488−instantiateForBinders ::
489− (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) =>
490− [Expr] ->
491− [CaseAlternative] ->
492− m ([Expr], [Type])
510+instantiateForBinders
511+ :: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
512+ => [Expr]
513+ -> [CaseAlternative]
514+ -> m ([Expr], [Type])
493515instantiateForBinders vals cas = unzip <$> zipWithM (\val inst -> do
494516 TypedValue _ val' ty <- infer val
495517 if inst
@@ -502,12 +524,12 @@ instantiateForBinders vals cas = unzip <$> zipWithM (\val inst -> do
502524-- |
503525-- Check the types of the return values in a set of binders in a case statement
504526--
505−checkBinders ::
506− (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) =>
507− [Type] ->
508− Type ->
509− [CaseAlternative] ->
510− m [CaseAlternative]
527+checkBinders
528+ :: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
529+ => [Type]
530+ -> Type
531+ -> [CaseAlternative]
532+ -> m [CaseAlternative]
511533checkBinders _ _ [] = return []
512534checkBinders nvals ret (CaseAlternative binders result : bs) = do
513535 guardWith (errorMessage $ OverlappingArgNames Nothing) $
@@ -531,11 +553,11 @@ checkBinders nvals ret (CaseAlternative binders result : bs) = do
531553-- |
532554-- Check the type of a value, rethrowing errors to provide a better error message
533555--
534−check ::
535− (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) =>
536− Expr ->
537− Type ->
538− m Expr
556+check
557+ :: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
558+ => Expr
559+ -> Type
560+ -> m Expr
539561check val ty = withErrorMessageHint (ErrorCheckingType val ty) $ check' val ty
540562
541563-- |
@@ -641,14 +663,14 @@ check' e@(ObjectUpdate obj ps) t@(TypeApp o row) | o == tyRecord = do
641663 -- We need to be careful to avoid duplicate labels here.
642664 -- We check _obj_ against the type _t_ with the types in _ps_ replaced with unknowns.
643665 let (propsToCheck, rest) = rowToList row
644− (removedProps, remainingProps) = partition (\(p, _) -> p `elem` map fst ps) propsToCheck
666+ (removedProps, remainingProps) = partition (\(p, _) -> p `elem` map (Label . fst) ps) propsToCheck
645667 us <- zip (map fst removedProps) <$> replicateM (length ps) freshType
646668 obj' <- check obj (TypeApp tyRecord (rowFromList (us ++ remainingProps, rest)))
647669 ps' <- checkProperties e ps row True
648670 return $ TypedValue True (ObjectUpdate obj' ps') t
649671check' (Accessor prop val) ty = withErrorMessageHint (ErrorCheckingAccessor val prop) $ do
650672 rest <- freshType
651− val' <- check val (TypeApp tyRecord (RCons prop ty rest))
673+ val' <- check val (TypeApp tyRecord (RCons (Label prop) ty rest))
652674 return $ TypedValue True (Accessor prop val') ty
653675check' v@(Constructor c) ty = do
654676 env <- getEnv
@@ -678,13 +700,13 @@ check' val ty = do
678700--
679701-- The @lax@ parameter controls whether or not every record member has to be provided. For object updates, this is not the case.
680702--
681−checkProperties ::
682− (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) =>
683− Expr ->
684− [(Text, Expr)] ->
685− Type ->
686− Bool ->
687− m [(Text, Expr)]
703+checkProperties
704+ :: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
705+ => Expr
706+ -> [(PSString, Expr)]
707+ -> Type
708+ -> Bool
709+ -> m [(PSString, Expr)]
688710checkProperties expr ps row lax = let (ts, r') = rowToList row in go ps ts r' where
689711 go [] [] REmpty = return []
690712 go [] [] u@(TUnknown _)
@@ -694,18 +716,18 @@ checkProperties expr ps row lax = let (ts, r') = rowToList row in go ps ts r' wh
694716 go [] [] Skolem{} | lax = return []
695717 go [] ((p, _): _) _ | lax = return []
696718 | otherwise = throwError . errorMessage $ PropertyIsMissing p
697− go ((p,_):_) [] REmpty = throwError . errorMessage $ AdditionalProperty p
719+ go ((p,_):_) [] REmpty = throwError . errorMessage $ AdditionalProperty $ Label p
698720 go ((p,v):ps') ts r =
699− case lookup p ts of
721+ case lookup (Label p) ts of
700722 Nothing -> do
701723 v'@(TypedValue _ _ ty) <- infer v
702724 rest <- freshType
703− unifyTypes r (RCons p ty rest)
725+ unifyTypes r (RCons (Label p) ty rest)
704726 ps'' <- go ps' ts rest
705727 return $ (p, v') : ps''
706728 Just ty -> do
707729 v' <- check v ty
708− ps'' <- go ps' (delete (p, ty) ts) r
730+ ps'' <- go ps' (delete (Label p, ty) ts) r
709731 return $ (p, v') : ps''
710732 go _ _ _ = throwError . errorMessage $ ExprDoesNotHaveType expr (TypeApp tyRecord row)
711733
@@ -771,9 +793,9 @@ checkFunctionApplication' fn u arg = do
771793-- |
772794-- Ensure a set of property names and value does not contain duplicate labels
773795--
774−ensureNoDuplicateProperties :: (MonadError MultipleErrors m) => [(Text, Expr)] -> m ()
796+ensureNoDuplicateProperties :: (MonadError MultipleErrors m) => [(PSString, Expr)] -> m ()
775797ensureNoDuplicateProperties ps =
776798 let ls = map fst ps in
777799 case ls \\ nub ls of
778− l : _ -> throwError . errorMessage $ DuplicateLabel l Nothing
800+ l : _ -> throwError . errorMessage $ DuplicateLabel (Label l) Nothing
779801 _ -> return ()
src/Language/PureScript/TypeChecker/Unify.hs+2−1
@@ -31,6 +31,7 @@ import Language.PureScript.Crash
3131import Language.PureScript.Errors
3232import Language.PureScript.TypeChecker.Monad
3333import Language.PureScript.TypeChecker.Skolems
34+import Language.PureScript.Label (Label(..))
3435import Language.PureScript.Types
3536
3637-- | Generate a fresh type variable
@@ -139,7 +140,7 @@ unifyRows r1 r2 =
139140 forM_ int (uncurry unifyTypes)
140141 unifyRows' sd1 r1' sd2 r2'
141142 where
142− unifyRows' :: [(Text, Type)] -> Type -> [(Text, Type)] -> Type -> m ()
143+ unifyRows' :: [(Label, Type)] -> Type -> [(Label, Type)] -> Type -> m ()
143144 unifyRows' [] (TUnknown u) sd r = solveType u (rowFromList (sd, r))
144145 unifyRows' sd r [] (TUnknown u) = solveType u (rowFromList (sd, r))
145146 unifyRows' sd1 (TUnknown u1) sd2 (TUnknown u2) = do
src/Language/PureScript/Types.hs+6−4
@@ -20,6 +20,8 @@ import qualified Data.Text as T
2020import Language.PureScript.AST.SourcePos
2121import Language.PureScript.Kinds
2222import Language.PureScript.Names
23+import Language.PureScript.Label (Label)
24+import Language.PureScript.PSString (PSString)
2325
2426-- |
2527-- An identifier for the scope of a skolem variable
@@ -36,7 +38,7 @@ data Type
3638 -- | A named type variable
3739 | TypeVar Text
3840 -- | A type-level string
39− | TypeLevelString Text
41+ | TypeLevelString PSString
4042 -- | A type wildcard, as would appear in a partial type synonym
4143 | TypeWildcard SourceSpan
4244 -- | A type constructor
@@ -55,7 +57,7 @@ data Type
5557 -- | An empty row
5658 | REmpty
5759 -- | A non-empty row
58− | RCons Text Type Type
60+ | RCons Label Type Type
5961 -- | A type with a kind annotation
6062 | KindedType Type Kind
6163 -- | A placeholder used in pretty printing
@@ -108,7 +110,7 @@ $(A.deriveJSON A.defaultOptions ''ConstraintData)
108110-- |
109111-- Convert a row to a list of pairs of labels and types
110112--
111−rowToList :: Type -> ([(Text, Type)], Type)
113+rowToList :: Type -> ([(Label, Type)], Type)
112114rowToList (RCons name ty row) = let (tys, rest) = rowToList row
113115 in ((name, ty):tys, rest)
114116rowToList r = ([], r)
@@ -116,7 +118,7 @@ rowToList r = ([], r)
116118-- |
117119-- Convert a list of labels and types to a row
118120--
119−rowFromList :: ([(Text, Type)], Type) -> Type
121+rowFromList :: ([(Label, Type)], Type) -> Type
120122rowFromList ([], r) = r
121123rowFromList ((name, t):ts, r) = RCons name t (rowFromList (ts, r))
122124
tests/Language/PureScript/Ide/Integration.hs+14−7
@@ -50,12 +50,14 @@ import Data.Maybe (fromJust)
5050
5151import Data.Aeson
5252import Data.Aeson.Types
53−import qualified Data.Text as T
53+import qualified Data.Text.Encoding as T
54+import qualified Data.ByteString.Char8 as BS8
55+import qualified Data.ByteString.Lazy.Char8 as BSL8
5456import qualified Data.Vector as V
55−import Language.PureScript.Ide.Util
5657import qualified Language.PureScript as P
5758import System.Directory
5859import System.FilePath
60+import System.IO
5961import System.IO.Error (mkIOError, userErrorType)
6062import System.Process
6163
@@ -124,11 +126,16 @@ fileGlob = "\"src/**/*.purs\""
124126-- Integration Testing API
125127
126128sendCommand :: Value -> IO Text
127−sendCommand v = toS <$> readCreateProcess
128− ((shell "psc-ide-client") { std_out=CreatePipe
129− , std_err=CreatePipe
130− })
131− (T.unpack (encodeT v))
129+sendCommand v = do
130+ (Just hin, Just hout, _, _) <-
131+ createProcess ((proc "psc-ide-client" []) {std_in=CreatePipe, std_out=CreatePipe})
132+
133+ hSetEncoding hin utf8
134+ hSetEncoding hout utf8
135+
136+ BS8.hPutStrLn hin (BSL8.toStrict (encode v))
137+ hFlush hin
138+ T.decodeUtf8 <$> BS8.hGetLine hout
132139
133140quitServer :: IO ()
134141quitServer = do
tests/Language/PureScript/Ide/MatcherSpec.hs+1−1
@@ -46,4 +46,4 @@ spec = do
4646 it "matches on equality" $ do
4747 -- ignore any position information
4848 (m, i, t, _) : _ <- getFlexCompletions "const"
49− (m, i, t) `shouldBe` ("MatcherSpec", "const", "forall a b. a -> b -> a")
49+ (m, i, t) `shouldBe` ("MatcherSpec", "const", "∀ a b. a → b → a")
tests/TestDocs.hs+7−4
@@ -9,14 +9,16 @@ import Prelude ()
99import Prelude.Compat
1010
1111import Control.Arrow (first)
12+import Control.Monad.IO.Class (liftIO)
1213
13−import Data.Version (Version(..))
14−import Data.Monoid
15−import Data.Maybe (fromMaybe)
16−import Data.List ((\\))
1714import Data.Foldable
15+import Data.List ((\\))
16+import Data.Maybe (fromMaybe)
17+import Data.Monoid
1818import Data.Text (Text)
1919import qualified Data.Text as T
20+import Data.Time.Clock (getCurrentTime)
21+import Data.Version (Version(..))
2022import System.Exit
2123
2224import qualified Language.PureScript as P
@@ -32,6 +34,7 @@ import TestUtils
3234publishOpts :: Publish.PublishOptions
3335publishOpts = Publish.defaultPublishOptions
3436 { Publish.publishGetVersion = return testVersion
37+ , Publish.publishGetTagTime = const (liftIO getCurrentTime)
3538 , Publish.publishWorkingTreeDirty = return ()
3639 }
3740 where testVersion = ("v999.0.0", Version [999,0,0] [])
tests/TestPscPublish.hs+3
@@ -4,8 +4,10 @@
44
55module TestPscPublish where
66
7+import Control.Monad.IO.Class (liftIO)
78import System.Exit (exitFailure)
89import Data.ByteString.Lazy (ByteString)
10+import Data.Time.Clock (getCurrentTime)
911import qualified Data.Aeson as A
1012import Data.Version
1113
@@ -38,6 +40,7 @@ roundTrip pkg =
3840testRunOptions :: PublishOptions
3941testRunOptions = defaultPublishOptions
4042 { publishGetVersion = return testVersion
43+ , publishGetTagTime = const (liftIO getCurrentTime)
4144 , publishWorkingTreeDirty = return ()
4245 }
4346 where testVersion = ("v999.0.0", Version [999,0,0] [])
tests/TestPsci.hs+1−1
@@ -120,7 +120,7 @@ getPSCiState :: IO PSCiState
120120getPSCiState = do
121121 cwd <- getCurrentDirectory
122122 let supportDir = cwd </> "tests" </> "support" </> "bower_components"
123− let supportFiles ext = Glob.globDir1 (Glob.compile ("purescript-*/**/*." ++ ext)) supportDir
123+ let supportFiles ext = Glob.globDir1 (Glob.compile ("purescript-*/src/**/*." ++ ext)) supportDir
124124 pursFiles <- supportFiles "purs"
125125
126126 modulesOrFirstError <- loadAllModules pursFiles
tests/TestUtils.hs+19−1
@@ -69,11 +69,15 @@ supportModules =
6969 , "Control.Monad.Eff.Class"
7070 , "Control.Monad.Eff.Console"
7171 , "Control.Monad.Eff.Unsafe"
72+ , "Control.Monad.Rec.Class"
7273 , "Control.Monad.ST"
7374 , "Control.MonadPlus"
7475 , "Control.MonadZero"
7576 , "Control.Plus"
7677 , "Control.Semigroupoid"
78+ , "Data.Array"
79+ , "Data.Array.Partial"
80+ , "Data.Array.ST"
7781 , "Data.Bifoldable"
7882 , "Data.Bifunctor"
7983 , "Data.Bifunctor.Clown"
@@ -86,7 +90,10 @@ supportModules =
8690 , "Data.Boolean"
8791 , "Data.BooleanAlgebra"
8892 , "Data.Bounded"
93+ , "Data.Char"
8994 , "Data.CommutativeRing"
95+ , "Data.Either"
96+ , "Data.Either.Nested"
9097 , "Data.Eq"
9198 , "Data.EuclideanRing"
9299 , "Data.Field"
@@ -95,6 +102,7 @@ supportModules =
95102 , "Data.Function.Uncurried"
96103 , "Data.Functor"
97104 , "Data.Functor.Invariant"
105+ , "Data.Generic"
98106 , "Data.Generic.Rep"
99107 , "Data.Generic.Rep.Eq"
100108 , "Data.Generic.Rep.Monoid"
@@ -102,6 +110,7 @@ supportModules =
102110 , "Data.Generic.Rep.Semigroup"
103111 , "Data.Generic.Rep.Show"
104112 , "Data.HeytingAlgebra"
113+ , "Data.Identity"
105114 , "Data.Maybe"
106115 , "Data.Maybe.First"
107116 , "Data.Maybe.Last"
@@ -115,6 +124,7 @@ supportModules =
115124 , "Data.Monoid.Multiplicative"
116125 , "Data.NaturalTransformation"
117126 , "Data.Newtype"
127+ , "Data.NonEmpty"
118128 , "Data.Ord"
119129 , "Data.Ord.Unsafe"
120130 , "Data.Ordering"
@@ -122,15 +132,23 @@ supportModules =
122132 , "Data.Semigroup"
123133 , "Data.Semiring"
124134 , "Data.Show"
135+ , "Data.String"
136+ , "Data.String.CaseInsensitive"
137+ , "Data.String.Regex"
138+ , "Data.String.Regex.Flags"
139+ , "Data.String.Regex.Unsafe"
140+ , "Data.String.Unsafe"
125141 , "Data.Symbol"
126142 , "Data.Traversable"
143+ , "Data.Tuple"
144+ , "Data.Tuple.Nested"
145+ , "Data.Unfoldable"
127146 , "Data.Unit"
128147 , "Data.Void"
129148 , "Partial"
130149 , "Partial.Unsafe"
131150 , "Prelude"
132151 , "Test.Assert"
133− , "Test.Main"
134152 , "Type.Data.Ordering"
135153 , "Type.Data.Symbol"
136154 , "Type.Equality"
tests/support/bower.json+1
@@ -9,6 +9,7 @@
99 "purescript-st": "2.0.0",
1010 "purescript-partial": "1.1.2",
1111 "purescript-newtype": "1.1.0",
12+ "purescript-generics": "3.3.0",
1213 "purescript-generics-rep": "4.0.0",
1314 "purescript-symbols": "^2.0.0",
1415 "purescript-typelevel-prelude": "https://github.com/purescript/purescript-typelevel-prelude.git#29a7123a0c29c85d4b923fcf4a7df8e45ebf9bac",