on master help sign in
Better model of types in Type.Type

- Get rid of pretty printing for Type.Type - Stop modeling records with overlapping fields in Type.Type - Explicit exports for Type.Environment - Make type Mismatch notes an ADT not a String - Track expected/actual through the unification process Errors still print out weird. Next task is to clean that up! This also appears to resolve issues #1013, #917, #821, #656, and #654. We should do further testing before closing them all though!

commita28acb21900535f3229e7ef924856b70298870c5 authorEvan Czaplicki <info@elm-lang.org> dateSun 18 Oct 2015, 19:22 (11 years ago) parent3821d9a
13 files changed+1409−1312
elm-compiler.cabal−1 src/AST/Type.hs−19 src/Reporting/Error/Type.hs+25−11 src/Type/Constrain/Expression.hs+78−82 src/Type/Constrain/Literal.hs+25−14 src/Type/Constrain/Pattern.hs+11−12 src/Type/Environment.hs+104−93 src/Type/Inference.hs+5−6 src/Type/PrettyPrint.hs−20 src/Type/Solve.hs+152−98 src/Type/State.hs+197−136 src/Type/Type.hs+219−444 src/Type/Unify.hs+593−376
elm-compiler.cabal−1
@@ -119,7 +119,6 @@ Library
119119 Type.Environment,
120120 Type.Fragment,
121121 Type.Inference,
122− Type.PrettyPrint,
123122 Type.Solve,
124123 Type.State,
125124 Type.Type,
src/AST/Type.hs−19
@@ -4,7 +4,6 @@ module AST.Type
44 , Port(..), getPortType
55 , deepDealias, iteratedDealias, dealias
66 , collectLambdas
7− , fieldMap
87 , tuple
98 ) where
109
@@ -65,24 +64,6 @@ getPortType portType =
6564 Signal tipe _ -> tipe
6665
6766
68−fieldMap :: [(String,a)] -> Map.Map String [a]
69−fieldMap fields =
70− let add r (field,tipe) =
71− Map.insertWith (++) field [tipe] r
72− in
73− foldl add Map.empty fields
74−
75−{--
76−recordOf :: [(String, Type var)] -> Type var
77−recordOf fields =
78− Record fields Nothing
79−
80−
81−listOf :: RawType -> RawType
82−listOf tipe =
83− App (Type (Var.Raw "List")) [tipe]
84−--}
85−
8667tuple :: R.Region -> [Raw] -> Raw
8768tuple region types =
8869 let name = Var.Raw ("_Tuple" ++ show (length types))
src/Reporting/Error/Type.hs+25−11
@@ -15,23 +15,31 @@ import qualified Reporting.Report as Report
1515
1616data Error
1717 = Mismatch Mismatch
18− | InfiniteType InfiniteType
1918 | BadMain Type.Canonical
19+ | InfiniteType
20+ { _name :: String
21+ , _overallType :: Type.Canonical
22+ , _infiniteType :: Type.Canonical
23+ }
2024
2125
2226data Mismatch = MismatchInfo
2327 { _hint :: Hint
28+ , _rootType :: Type.Canonical
2429 , _leftType :: Type.Canonical
2530 , _rightType :: Type.Canonical
26− , _note :: Maybe String
31+ , _reason :: Maybe Reason
2732 }
2833
2934
30−data InfiniteType = InfiniteTypeInfo
31− { _name :: String
32− , _var :: Type.Canonical
33− , _type :: Type.Canonical
34− }
35+data Reason
36+ = MessyFields [String] [String]
37+ | ExpectedFields [String]
38+ | ActualFields [String]
39+ | NotRecord
40+ | TooLongComparableTuple Int
41+ | Rigid (Maybe String)
42+ deriving (Show)
3543
3644
3745data Hint
@@ -66,18 +74,21 @@ data Pattern
6674 | PRecord
6775
6876
77+
6978-- TO REPORT
7079
80+
7181toReport :: P.Dealiaser -> Error -> Report.Report
7282toReport dealiaser err =
7383 case err of
74− Mismatch (MismatchInfo hint leftType rightType note) ->
84+ Mismatch (MismatchInfo hint rootType leftType rightType maybeReason) ->
7585 let
7686 (subRegion, preHint, maybePostHint) = hintToString hint
7787
7888 postHint =
79− maybe "" (++"\n\n") note
89+ "TODO explain what went wrong!\n\n" ++ show maybeReason ++ "\n\n"
8090 ++ maybe "" (++"\n\n") maybePostHint
91+ ++ P.render (P.nest 4 (P.pretty dealiaser False rootType)) ++ "\n\n"
8192 ++ "As I infer the types of values flowing through your program, I see a conflict\n"
8293 ++ "between these two types:\n\n"
8394 ++ P.render (P.nest 4 (P.pretty dealiaser False leftType))
@@ -86,7 +97,7 @@ toReport dealiaser err =
8697 in
8798 Report.Report "TYPE MISMATCH" subRegion preHint postHint
8899
89− InfiniteType (InfiniteTypeInfo name var tipe) ->
100+ InfiniteType name var tipe ->
90101 let
91102 prettyVar =
92103 P.pretty dealiaser False var
@@ -97,7 +108,8 @@ toReport dealiaser err =
97108 Report.simple "INFINITE TYPE"
98109 ( "I am inferring weird self-referential type for `" ++ name ++ "`"
99110 )
100− ( "The bit of the type that is self-referential looks like this:\n\n"
111+ ( "TODO - do a better job\n\n"
112+ ++ "The bit of the type that is self-referential looks like this:\n\n"
101113 ++ P.render (P.nest 4 (prettyVar <+> P.equals <+> prettyType))
102114 ++ "\n\nThe cause is often that the usage of `" ++ name ++ "` is flipped around.\n\n"
103115 ++ "Maybe you are inserting a data structure into an element? Maybe you are giving\n"
@@ -308,3 +320,5 @@ ordinalize number =
308320 | otherwise = "th"
309321 in
310322 show number ++ ending
323+
324+
src/Type/Constrain/Expression.hs+78−82
@@ -3,7 +3,6 @@ module Type.Constrain.Expression where
33
44import Control.Arrow (second)
55import qualified Control.Monad as Monad
6−import qualified Data.List as List
76import qualified Data.Map as Map
87
98import qualified AST.Expression.General as E
@@ -28,7 +27,7 @@ constrain
2827 -> Type
2928 -> IO TypeConstraint
3029constrain env annotatedExpr@(A.A region expression) tipe =
31− let list t = Env.get env Env.types "List" <| t
30+ let list t = Env.getType env "List" <| t
3231 (<?) = CInstance region
3332 in
3433 case expression of
@@ -40,21 +39,22 @@ constrain env annotatedExpr@(A.A region expression) tipe =
4039 exists $ \unif ->
4140 let
4241 shaderTipe a u v =
43− Env.get env Env.types "WebGL.Shader" <| a <| u <| v
42+ Env.getType env "WebGL.Shader" <| a <| u <| v
4443
45− glTipe =
46− Env.get env Env.types . Lit.glTipeName
44+ glToType glTipe =
45+ Env.getType env (Lit.glTipeName glTipe)
4746
4847 makeRec accessor baseRec =
4948 let decls = accessor gltipe
5049 in
51− if Map.size decls == 0
52− then baseRec
53− else record (Map.map (\t -> [glTipe t]) decls) baseRec
50+ if Map.size decls == 0 then
51+ baseRec
52+ else
53+ record (Map.map glToType decls) baseRec
5454
5555 attribute = makeRec Lit.attribute attr
5656 uniform = makeRec Lit.uniform unif
57− varying = makeRec Lit.varying (termN EmptyRecord1)
57+ varying = makeRec Lit.varying (TermN EmptyRecord1)
5858 in
5959 return (CEqual Error.Shader region tipe (shaderTipe attribute uniform varying))
6060
@@ -104,8 +104,8 @@ constrain env annotatedExpr@(A.A region expression) tipe =
104104 constrainCase env region expr branches tipe
105105
106106 E.Data name exprs ->
107− do vars <- Monad.forM exprs $ \_ -> variable Flexible
108− let pairs = zip exprs (map varN vars)
107+ do vars <- Monad.forM exprs $ \_ -> mkVar Nothing
108+ let pairs = zip exprs (map VarN vars)
109109 (ctipe, cs) <- Monad.foldM step (tipe, CTrue) (reverse pairs)
110110 return $ ex vars (cs /\ name <? ctipe)
111111 where
@@ -115,31 +115,31 @@ constrain env annotatedExpr@(A.A region expression) tipe =
115115
116116 E.Access expr label ->
117117 exists $ \t ->
118− constrain env expr (record (Map.singleton label [tipe]) t)
118+ constrain env expr (record (Map.singleton label tipe) t)
119119
120120 E.Update expr fields ->
121121 exists $ \t ->
122− do oldVars <- Monad.forM fields $ \_ -> variable Flexible
123− let oldFields = ST.fieldMap (zip (map fst fields) (map varN oldVars))
122+ do oldVars <- mapM (\_ -> mkVar Nothing) fields
123+ let oldFields = Map.fromList (zip (map fst fields) (map VarN oldVars))
124124 cOld <- ex oldVars <$> constrain env expr (record oldFields t)
125125
126− newVars <- Monad.forM fields $ \_ -> variable Flexible
127− let newFields = ST.fieldMap (zip (map fst fields) (map varN newVars))
126+ newVars <- mapM (\_ -> mkVar Nothing) fields
127+ let newFields = Map.fromList (zip (map fst fields) (map VarN newVars))
128128 let cNew = CEqual Error.Record region tipe (record newFields t)
129129
130− cs <- Monad.zipWithM (constrain env) (map snd fields) (map varN newVars)
130+ cs <- Monad.zipWithM (constrain env) (map snd fields) (map VarN newVars)
131131
132132 return $ cOld /\ ex newVars (CAnd (cNew : cs))
133133
134134 E.Record fields ->
135− do vars <- Monad.forM fields (\_ -> variable Flexible)
135+ do vars <- Monad.forM fields (\_ -> mkVar Nothing)
136136 fieldCons <-
137137 Monad.zipWithM
138138 (constrain env)
139139 (map snd fields)
140− (map varN vars)
141− let fields' = ST.fieldMap (zip (map fst fields) (map varN vars))
142− let recordType = record fields' (termN EmptyRecord1)
140+ (map VarN vars)
141+ let fields' = Map.fromList (zip (map fst fields) (map VarN vars))
142+ let recordType = record fields' (TermN EmptyRecord1)
143143 return (ex vars (CAnd (fieldCons ++ [CEqual Error.Record region tipe recordType])))
144144
145145 E.Let defs body ->
@@ -178,14 +178,14 @@ constrainApp
178178 -> Type
179179 -> IO TypeConstraint
180180constrainApp env region f args tipe =
181− do funcVar <- variable Flexible
182− funcCon <- constrain env f (varN funcVar)
181+ do funcVar <- mkVar Nothing
182+ funcCon <- constrain env f (VarN funcVar)
183183
184184 (vars, argCons, numberOfArgsCons, argMatchCons, _, returnVar) <-
185185 argConstraints env maybeName region (length args) funcVar 1 args
186186
187187 let returnCon =
188− CEqual (Error.Function maybeName) region (varN returnVar) tipe
188+ CEqual (Error.Function maybeName) region (VarN returnVar) tipe
189189
190190 return $ ex (funcVar : vars) $
191191 CAnd (funcCon : argCons ++ numberOfArgsCons ++ argMatchCons ++ [returnCon])
@@ -214,10 +214,10 @@ argConstraints env name region totalArgs overallVar index args =
214214 return ([], [], [], [], Nothing, overallVar)
215215
216216 expr@(A.A subregion _) : rest ->
217− do argVar <- variable Flexible
218− argCon <- constrain env expr (varN argVar)
219− argIndexVar <- variable Flexible
220− localReturnVar <- variable Flexible
217+ do argVar <- mkVar Nothing
218+ argCon <- constrain env expr (VarN argVar)
219+ argIndexVar <- mkVar Nothing
220+ localReturnVar <- mkVar Nothing
221221
222222 (vars, argConRest, numberOfArgsRest, argMatchRest, restRegion, returnVar) <-
223223 argConstraints env name region totalArgs localReturnVar (index + 1) rest
@@ -229,15 +229,15 @@ argConstraints env name region totalArgs overallVar index args =
229229 CEqual
230230 (Error.FunctionArity name (index - 1) totalArgs arityRegion)
231231 region
232− (varN argIndexVar ==> varN localReturnVar)
233− (varN overallVar)
232+ (VarN argIndexVar ==> VarN localReturnVar)
233+ (VarN overallVar)
234234
235235 let argMatchCon =
236236 CEqual
237237 (Error.UnexpectedArg name index subregion)
238238 region
239− (varN argIndexVar)
240− (varN argVar)
239+ (VarN argIndexVar)
240+ (VarN argVar)
241241
242242 return
243243 ( argVar : argIndexVar : localReturnVar : vars
@@ -262,26 +262,26 @@ constrainBinop
262262 -> Type
263263 -> IO TypeConstraint
264264constrainBinop env region op leftExpr@(A.A leftRegion _) rightExpr@(A.A rightRegion _) tipe =
265− do leftVar <- variable Flexible
266− rightVar <- variable Flexible
265+ do leftVar <- mkVar Nothing
266+ rightVar <- mkVar Nothing
267267
268− leftCon <- constrain env leftExpr (varN leftVar)
269− rightCon <- constrain env rightExpr (varN rightVar)
268+ leftCon <- constrain env leftExpr (VarN leftVar)
269+ rightCon <- constrain env rightExpr (VarN rightVar)
270270
271− leftVar' <- variable Flexible
272− rightVar' <- variable Flexible
273− answerVar <- variable Flexible
271+ leftVar' <- mkVar Nothing
272+ rightVar' <- mkVar Nothing
273+ answerVar <- mkVar Nothing
274274
275− let opType = varN leftVar' ==> varN rightVar' ==> varN answerVar
275+ let opType = VarN leftVar' ==> VarN rightVar' ==> VarN answerVar
276276
277277 return $
278278 ex [leftVar,rightVar,leftVar',rightVar',answerVar] $ CAnd $
279279 [ leftCon
280280 , rightCon
281281 , CInstance region (V.toString op) opType
282− , CEqual (Error.BinopLeft op leftRegion) region (varN leftVar') (varN leftVar)
283− , CEqual (Error.BinopRight op rightRegion) region (varN rightVar') (varN rightVar)
284− , CEqual (Error.Binop op) region tipe (varN answerVar)
282+ , CEqual (Error.BinopLeft op leftRegion) region (VarN leftVar') (VarN leftVar)
283+ , CEqual (Error.BinopRight op rightRegion) region (VarN rightVar') (VarN rightVar)
284+ , CEqual (Error.Binop op) region tipe (VarN answerVar)
285285 ]
286286
287287
@@ -302,12 +302,12 @@ constrainList env region exprs tipe =
302302 return $ ex vars (CAnd (exprCons ++ cons))
303303 where
304304 elementConstraint expr@(A.A region' _) =
305− do var <- variable Flexible
306− con <- constrain env expr (varN var)
305+ do var <- mkVar Nothing
306+ con <- constrain env expr (VarN var)
307307 return ( (var, region'), con )
308308
309309 varToCon var =
310− CEqual Error.List region tipe (Env.get env Env.types "List" <| varN var)
310+ CEqual Error.List region tipe (Env.getType env "List" <| VarN var)
311311
312312
313313-- CONSTRAIN IF EXPRESSIONS
@@ -334,17 +334,17 @@ constrainIf env region branches finally tipe =
334334 return $ ex (condVars ++ vars) (CAnd (condCons ++ branchExprCons ++ cons))
335335 where
336336 bool =
337− Env.get env Env.types "Bool"
337+ Env.getType env "Bool"
338338
339339 constrainCondition condition@(A.A condRegion _) =
340− do condVar <- variable Flexible
341− condCon <- constrain env condition (varN condVar)
342− let boolCon = CEqual Error.IfCondition condRegion (varN condVar) bool
340+ do condVar <- mkVar Nothing
341+ condCon <- constrain env condition (VarN condVar)
342+ let boolCon = CEqual Error.IfCondition condRegion (VarN condVar) bool
343343 return (condVar, CAnd [ condCon, boolCon ])
344344
345345 constrainBranch expr@(A.A branchRegion _) =
346− do branchVar <- variable Flexible
347− exprCon <- constrain env expr (varN branchVar)
346+ do branchVar <- mkVar Nothing
347+ exprCon <- constrain env expr (VarN branchVar)
348348 return
349349 ( (branchVar, branchRegion)
350350 , exprCon
@@ -355,7 +355,7 @@ constrainIf env region branches finally tipe =
355355 [(thenVar, _), (elseVar, _)] ->
356356 return
357357 ( [thenVar,elseVar]
358− , [ CEqual Error.IfBranches region (varN thenVar) (varN elseVar)
358+ , [ CEqual Error.IfBranches region (VarN thenVar) (VarN elseVar)
359359 , varToCon thenVar
360360 ]
361361 )
@@ -364,7 +364,7 @@ constrainIf env region branches finally tipe =
364364 pairCons region Error.MultiIfBranch varToCon branchInfo
365365
366366 varToCon var =
367− CEqual Error.If region (varN var) tipe
367+ CEqual Error.If region (VarN var) tipe
368368
369369
370370-- CONSTRAIN CASE EXPRESSIONS
@@ -377,27 +377,27 @@ constrainCase
377377 -> Type
378378 -> IO TypeConstraint
379379constrainCase env region expr branches tipe =
380− do exprVar <- variable Flexible
381− exprCon <- constrain env expr (varN exprVar)
380+ do exprVar <- mkVar Nothing
381+ exprCon <- constrain env expr (VarN exprVar)
382382
383383 (branchInfo, branchExprCons) <-
384− unzip <$> mapM (branch (varN exprVar)) branches
384+ unzip <$> mapM (branch (VarN exprVar)) branches
385385
386386 (vars, cons) <- pairCons region Error.CaseBranch varToCon branchInfo
387387
388388 return $ ex (exprVar : vars) (CAnd (exprCon : branchExprCons ++ cons))
389389 where
390390 branch patternType (pattern, branchExpr@(A.A branchRegion _)) =
391− do branchVar <- variable Flexible
391+ do branchVar <- mkVar Nothing
392392 fragment <- Pattern.constrain env pattern patternType
393− branchCon <- constrain env branchExpr (varN branchVar)
393+ branchCon <- constrain env branchExpr (VarN branchVar)
394394 return
395395 ( (branchVar, branchRegion)
396396 , CLet [Fragment.toScheme fragment] branchCon
397397 )
398398
399399 varToCon var =
400− CEqual Error.Case region tipe (varN var)
400+ CEqual Error.Case region tipe (VarN var)
401401
402402
403403-- COLLECT PAIRS
@@ -419,11 +419,11 @@ pairCons
419419pairCons region pairHint varToCon items =
420420 let
421421 pairToCon (Pair index var1 var2 subregion) =
422− CEqual (pairHint index subregion) region (varN var1) (varN var2)
422+ CEqual (pairHint index subregion) region (VarN var1) (VarN var2)
423423 in
424424 case collectPairs 2 items of
425425 Nothing ->
426− do var <- variable Flexible
426+ do var <- mkVar Nothing
427427 return ([var], [varToCon var])
428428
429429 Just (pairs, var) ->
@@ -514,28 +514,26 @@ constrainAnnotatedDef
514514 -> IO Info
515515constrainAnnotatedDef env info qs patternRegion typeRegion name expr tipe =
516516 do -- Some mistake may be happening here. Currently, qs is always [].
517− rigidVars <- Monad.forM qs (\_ -> variable Rigid)
517+ rigidVars <- mapM mkRigid qs
518518
519− flexiVars <- Monad.forM qs (\_ -> variable Flexible)
519+ flexiVars <- mapM mkNamedVar qs
520520
521− let inserts = zipWith (\arg typ -> Map.insert arg (varN typ)) qs flexiVars
522−
523− let env' = env { Env.value = List.foldl' (\x f -> f x) (Env.value env) inserts }
521+ let env' = Env.addValues env (zip qs flexiVars)
524522
525523 (vars, typ) <- Env.instantiateType env tipe Map.empty
526524
527525 let scheme =
528526 Scheme
529− { rigidQuantifiers = []
530− , flexibleQuantifiers = flexiVars ++ vars
531− , constraint = CTrue
532− , header = Map.singleton name (A.A patternRegion typ)
533− }
534−
535− var <- variable Flexible
536− defCon <- constrain env' expr (varN var)
527+ { _rigidQuantifiers = []
528+ , _flexibleQuantifiers = flexiVars ++ vars
529+ , _constraint = CTrue
530+ , _header = Map.singleton name (A.A patternRegion typ)
531+ }
532+
533+ var <- mkVar Nothing
534+ defCon <- constrain env' expr (VarN var)
537535 let annCon =
538− CEqual (Error.BadTypeAnnotation name) typeRegion typ (varN var)
536+ CEqual (Error.BadTypeAnnotation name) typeRegion typ (VarN var)
539537
540538 return $ info
541539 { iSchemes = scheme : iSchemes info
@@ -553,15 +551,13 @@ constrainUnannotatedDef
553551 -> IO Info
554552constrainUnannotatedDef env info qs patternRegion name expr =
555553 do -- Some mistake may be happening here. Currently, qs is always [].
556− rigidVars <- Monad.forM qs (\_ -> variable Rigid)
557−
558− v <- variable Flexible
554+ rigidVars <- mapM mkRigid qs
559555
560− let tipe = varN v
556+ v <- mkVar Nothing
561557
562− let inserts = zipWith (\arg typ -> Map.insert arg (varN typ)) qs rigidVars
558+ let tipe = VarN v
563559
564− let env' = env { Env.value = List.foldl' (\x f -> f x) (Env.value env) inserts }
560+ let env' = Env.addValues env (zip qs rigidVars)
565561
566562 con <- constrain env' expr tipe
567563
src/Type/Constrain/Literal.hs+25−14
@@ -18,20 +18,31 @@ constrain env region literal tipe =
1818 return (T.CEqual (Error.Literal name) region tipe tipe')
1919 where
2020 prim name =
21− return (Env.get env Env.types name)
21+ return (Env.getType env name)
2222
23− litType =
23+ (name, litType) =
2424 case literal of
25− L.IntNum _ -> T.varN `fmap` T.variable (T.Is T.Number)
26− L.FloatNum _ -> prim "Float"
27− L.Chr _ -> prim "Char"
28− L.Str _ -> prim "String"
29− L.Boolean _ -> prim "Bool"
25+ L.IntNum _ ->
26+ ( "number"
27+ , T.VarN <$> T.mkVar (Just T.Number)
28+ )
3029
31− name =
32− case literal of
33− L.IntNum _ -> "number"
34− L.FloatNum _ -> "float"
35− L.Chr _ -> "character"
36− L.Str _ -> "string"
37− L.Boolean _ -> "boolean"
30+ L.FloatNum _ ->
31+ ( "float"
32+ , prim "Float"
33+ )
34+
35+ L.Chr _ ->
36+ ( "character"
37+ , prim "Char"
38+ )
39+
40+ L.Str _ ->
41+ ( "string"
42+ , prim "String"
43+ )
44+
45+ L.Boolean _ ->
46+ ( "boolean"
47+ , prim "Bool"
48+ )
src/Type/Constrain/Pattern.hs+11−12
@@ -1,4 +1,3 @@
1−{-# LANGUAGE FlexibleInstances #-}
21module Type.Constrain.Pattern where
32
43import Control.Arrow (second)
@@ -26,7 +25,7 @@ constrain env (A.A region pattern) tipe =
2625 CEqual (Error.Pattern patternError) region leftType rightType
2726
2827 rvar v =
29− A.A region (varN v)
28+ A.A region (VarN v)
3029 in
3130 case pattern of
3231 P.Anything ->
@@ -37,22 +36,22 @@ constrain env (A.A region pattern) tipe =
3736 return $ emptyFragment { typeConstraint = c }
3837
3938 P.Var name ->
40− do v <- variable Flexible
39+ do variable <- mkVar Nothing
4140 return $ Fragment
42− { typeEnv = Map.singleton name (rvar v)
43− , vars = [v]
41+ { typeEnv = Map.singleton name (rvar variable)
42+ , vars = [variable]
4443 , typeConstraint =
45− equal (Error.PVar name) (varN v) tipe
44+ equal (Error.PVar name) (VarN variable) tipe
4645 }
4746
4847 P.Alias name p ->
49− do v <- variable Flexible
48+ do variable <- mkVar Nothing
5049 fragment <- constrain env p tipe
5150 return $ fragment
52− { typeEnv = Map.insert name (rvar v) (typeEnv fragment)
53− , vars = v : vars fragment
51+ { typeEnv = Map.insert name (rvar variable) (typeEnv fragment)
52+ , vars = variable : vars fragment
5453 , typeConstraint =
55− equal (Error.PAlias name) (varN v) tipe
54+ equal (Error.PAlias name) (VarN variable) tipe
5655 /\ typeConstraint fragment
5756 }
5857
@@ -73,13 +72,13 @@ constrain env (A.A region pattern) tipe =
7372
7473 P.Record fields ->
7574 do pairs <-
76− mapM (\name -> (,) name <$> variable Flexible) fields
75+ mapM (\name -> (,) name <$> mkVar Nothing) fields
7776
7877 let tenv =
7978 Map.fromList (map (second rvar) pairs)
8079
8180 let unannotatedTenv =
82− Map.map (\v -> [A.drop v]) tenv
81+ Map.map A.drop tenv
8382
8483 con <- exists $ \t ->
8584 return (equal Error.PRecord tipe (record unannotatedTenv t))
src/Type/Environment.hs+104−93
@@ -1,11 +1,18 @@
1−module Type.Environment where
1+{-# OPTIONS_GHC -Wall #-}
2+module Type.Environment
3+ ( Environment
4+ , initialize
5+ , getType, freshDataScheme, ctorNames
6+ , addValues
7+ , instantiateType
8+ )
9+ where
210
3−import Control.Monad (forM)
411import qualified Control.Monad.State as State
5−import qualified Data.Traversable as Traverse
12+import qualified Data.List as List
13+import Data.Map ((!))
614import qualified Data.Map as Map
715import qualified Data.Set as Set
8−import Data.List (isPrefixOf)
916
1017import qualified AST.Type as T
1118import qualified AST.Variable as V
@@ -18,22 +25,22 @@ type VarDict = Map.Map String Variable
1825
1926
2027data Environment = Environment
21− { constructor :: Map.Map String (IO (Int, [Variable], [Type], Type))
22− , types :: TypeDict
23− , value :: TypeDict
28+ { _constructor :: Map.Map String (IO (Int, [Variable], [Type], Type))
29+ , _types :: TypeDict
30+ , _value :: TypeDict
2431 }
2532
2633
27−initialEnvironment :: [Module.CanonicalAdt] -> IO Environment
28−initialEnvironment datatypes =
34+initialize :: [Module.CanonicalAdt] -> IO Environment
35+initialize datatypes =
2936 do types <- makeTypes datatypes
3037 let env =
3138 Environment
32− { constructor = Map.empty
33− , value = Map.empty
34− , types = types
39+ { _constructor = Map.empty
40+ , _value = Map.empty
41+ , _types = types
3542 }
36− return $ env { constructor = makeConstructors env datatypes }
43+ return $ env { _constructor = makeConstructors env datatypes }
3744
3845
3946makeTypes :: [Module.CanonicalAdt] -> IO TypeDict
@@ -43,14 +50,14 @@ makeTypes datatypes =
4350 return (Map.fromList (adts ++ bs))
4451 where
4552 makeImported :: (V.Canonical, Module.AdtInfo V.Canonical) -> IO (String, Type)
46− makeImported (var, _) =
47− do tvar <- namedVar Constant var
48− return (V.toString var, varN tvar)
53+ makeImported (name, _) =
54+ do tvar <- mkAtom name
55+ return (V.toString name, VarN tvar)
4956
5057 makeBuiltin :: (String, Int) -> IO (String, Type)
5158 makeBuiltin (name, _) =
52− do name' <- namedVar Constant (V.builtin name)
53− return (name, varN name')
59+ do name' <- mkAtom (V.builtin name)
60+ return (name, VarN name')
5461
5562 builtins :: [(String, Int)]
5663 builtins =
@@ -72,17 +79,17 @@ makeConstructors env datatypes =
7279 Map.fromList builtins
7380 where
7481 list t =
75− (types env Map.! "List") <| t
82+ (_types env ! "List") <| t
7683
7784 inst :: Int -> ([Type] -> ([Type], Type)) -> IO (Int, [Variable], [Type], Type)
7885 inst numTVars tipe =
79− do vars <- forM [1..numTVars] $ \_ -> variable Flexible
80− let (args, result) = tipe (map (varN) vars)
86+ do vars <- mapM (\_ -> mkVar Nothing) [1..numTVars]
87+ let (args, result) = tipe (map (VarN) vars)
8188 return (length args, vars, args, result)
8289
8390 tupleCtor n =
8491 let name = "_Tuple" ++ show n
85− in (name, inst n $ \vs -> (vs, foldl (<|) (types env Map.! name) vs))
92+ in (name, inst n $ \vs -> (vs, foldl (<|) (_types env ! name) vs))
8693
8794 builtins :: [ (String, IO (Int, [Variable], [Type], Type)) ]
8895 builtins =
@@ -112,44 +119,62 @@ ctorToType env (name, (tvars, ctors)) =
112119 return (types, returnType)
113120
114121
115−get :: Environment -> (Environment -> Map.Map String a) -> String -> a
116−get env subDict key =
122+
123+-- ACCESS TYPES
124+
125+
126+get :: (Environment -> Map.Map String a) -> Environment -> String -> a
127+get subDict env key =
117128 Map.findWithDefault (error msg) key (subDict env)
118129 where
119130 msg = "Could not find type constructor `" ++ key ++ "` while checking types."
120131
121132
122−freshDataScheme
123− :: Environment
124− -> String
125− -> IO (Int, [Variable], [Type], Type)
126−freshDataScheme env name =
127− get env constructor name
133+getType :: Environment -> String -> Type
134+getType =
135+ get _types
128136
129137
130−instantiateType
131− :: Environment
132− -> T.Canonical
133− -> VarDict
134− -> IO ([Variable], Type)
138+freshDataScheme :: Environment -> String -> IO (Int, [Variable], [Type], Type)
139+freshDataScheme =
140+ get _constructor
141+
142+
143+ctorNames :: Environment -> [String]
144+ctorNames env =
145+ Map.keys (_constructor env)
146+
147+
148+-- UPDATE ENVIRONMENT
149+
150+
151+addValues :: Environment -> [(String, Variable)] -> Environment
152+addValues env newValues =
153+ env
154+ { _value =
155+ List.foldl'
156+ (\dict (name, var) -> Map.insert name (VarN var) dict)
157+ (_value env)
158+ newValues
159+ }
160+
161+
162+
163+-- INSTANTIATE TYPES
164+
165+
166+instantiateType :: Environment -> T.Canonical -> VarDict -> IO ([Variable], Type)
135167instantiateType env sourceType dict =
136168 do (tipe, dict') <- State.runStateT (instantiator env sourceType) dict
137169 return (Map.elems dict', tipe)
138170
139171
140−instantiator
141− :: Environment
142− -> T.Canonical
143− -> State.StateT VarDict IO Type
172+instantiator :: Environment -> T.Canonical -> State.StateT VarDict IO Type
144173instantiator env sourceType =
145174 instantiatorHelp env Set.empty sourceType
146175
147176
148−instantiatorHelp
149− :: Environment
150− -> Set.Set String
151− -> T.Canonical
152− -> State.StateT VarDict IO Type
177+instantiatorHelp :: Environment -> Set.Set String -> T.Canonical -> State.StateT VarDict IO Type
153178instantiatorHelp env aliasVars sourceType =
154179 let go = instantiatorHelp env aliasVars
155180 in
@@ -157,70 +182,56 @@ instantiatorHelp env aliasVars sourceType =
157182 T.Lambda t1 t2 ->
158183 (==>) <$> go t1 <*> go t2
159184
160− T.Var x ->
161− do dict <- State.get
162− case Set.member x aliasVars of
163− True ->
164− return (PlaceHolder x)
165− False ->
166− case Map.lookup x dict of
167− Just v ->
168− return (varN v)
169−
170− Nothing ->
171− do v <- State.liftIO $ namedVar flex (V.local x)
172− State.put (Map.insert x v dict)
173− return (varN v)
174− where
175− flex | "number" `isPrefixOf` x = Is Number
176− | "comparable" `isPrefixOf` x = Is Comparable
177− | "appendable" `isPrefixOf` x = Is Appendable
178− | otherwise = Flexible
185+ T.Var name ->
186+ if Set.member name aliasVars then
187+ return (PlaceHolder name)
188+
189+ else
190+ do dict <- State.get
191+ case Map.lookup name dict of
192+ Just variable ->
193+ return (VarN variable)
194+
195+ Nothing ->
196+ do variable <- State.liftIO (mkNamedVar name)
197+ State.put (Map.insert name variable dict)
198+ return (VarN variable)
179199
180200 T.Aliased name args aliasType ->
181− do args' <- mapM (\(arg,tipe) -> (,) arg <$> go tipe) args
182− aliasedType' <-
201+ do targs <- mapM (\(arg,tipe) -> (,) arg <$> go tipe) args
202+ realType <-
183203 case aliasType of
184204 T.Filled tipe ->
185205 instantiatorHelp env Set.empty tipe
206+
186207 T.Holey tipe ->
187208 instantiatorHelp env (Set.fromList (map fst args)) tipe
188209
189− case aliasedType' of
190− PlaceHolder _ ->
191− error "problem instantiating type"
192−
193− VarN maybeSubAlias v ->
194− case maybeSubAlias of
195− Nothing ->
196− return (VarN (Just (name,args')) v)
197− Just _subAlias ->
198− return (TermN (Just (name,args')) (Var1 aliasedType'))
199−
200− TermN maybeSubAlias t ->
201− case maybeSubAlias of
202− Nothing ->
203− return (TermN (Just (name, args')) t)
204− Just _subAlias ->
205− return (TermN (Just (name,args')) (Var1 aliasedType'))
210+ return (AliasN name targs realType)
206211
207212 T.Type name ->
208− case Map.lookup (V.toString name) (types env) of
209− Just t -> return t
213+ case Map.lookup (V.toString name) (_types env) of
214+ Just tipe ->
215+ return tipe
216+
210217 Nothing ->
211218 error $
212219 "Could not find type constructor `" ++
213220 V.toString name ++ "` while checking types."
214221
215− T.App t ts ->
216− do t' <- go t
217− ts' <- mapM go ts
218− return $ foldl (<|) t' ts'
222+ T.App func args ->
223+ do tfunc <- go func
224+ targs <- mapM go args
225+ return $ foldl (<|) tfunc targs
219226
220227 T.Record fields ext ->
221− do fields' <- Traverse.traverse (mapM go) (T.fieldMap fields)
222− ext' <-
228+ do tfields <- traverse go (Map.fromList fields)
229+ text <-
223230 case ext of
224− Nothing -> return $ termN EmptyRecord1
225− Just x -> go x
226− return $ termN (Record1 fields' ext')
231+ Nothing ->
232+ return $ TermN EmptyRecord1
233+
234+ Just extType ->
235+ go extType
236+
237+ return $ TermN (Record1 tfields text)
src/Type/Inference.hs+5−6
@@ -42,13 +42,12 @@ infer interfaces modul =
4242genConstraints
4343 :: Module.Interfaces
4444 -> Module.CanonicalModule
45− -> IO (Env.TypeDict, T.TypeConstraint)
45+ -> IO (Map.Map String T.Type, T.TypeConstraint)
4646genConstraints interfaces modul =
47− do env <-
48− Env.initialEnvironment (canonicalizeAdts interfaces modul)
47+ do env <- Env.initialize (canonicalizeAdts interfaces modul)
4948
5049 ctors <-
51− forM (Map.keys (Env.constructor env)) $ \name ->
50+ forM (Env.ctorNames env) $ \name ->
5251 do (_, vars, args, result) <- Env.freshDataScheme env name
5352 return (name, (vars, foldr (T.==>) result args))
5453
@@ -60,10 +59,10 @@ genConstraints interfaces modul =
6059 let header = Map.map snd (Map.fromList allTypes)
6160 let environ = T.CLet [ T.Scheme vars [] T.CTrue (Map.map (A.A undefined) header) ]
6261
63− fvar <- T.variable T.Flexible
62+ fvar <- T.mkVar Nothing
6463
6564 constraint <-
66− TcExpr.constrain env (program (body modul)) (T.varN fvar)
65+ TcExpr.constrain env (program (body modul)) (T.VarN fvar)
6766
6867 return (header, environ constraint)
6968
src/Type/PrettyPrint.hsdeleted−20
@@ -1,20 +0,0 @@
1−module Type.PrettyPrint where
2−
3−import Text.PrettyPrint
4−
5−
6−data ParensWhen = Fn | App | Never
7−
8−
9−class PrettyType a where
10− pretty :: ParensWhen -> a -> Doc
11−
12−
13−commaSep :: [Doc] -> Doc
14−commaSep docs =
15− sep (punctuate comma docs)
16−
17−
18−parensIf :: Bool -> Doc -> Doc
19−parensIf bool doc =
20− if bool then parens doc else doc
src/Type/Solve.hs+152−98
@@ -2,7 +2,7 @@ module Type.Solve (solve) where
22
33import Control.Applicative ((<|>))
44import Control.Monad
5−import Control.Monad.State (StateT, execStateT, liftIO)
5+import Control.Monad.State (execStateT, liftIO)
66import Control.Monad.Except (ExceptT, throwError)
77import qualified Data.Foldable as F
88import qualified Data.List as List
@@ -14,21 +14,22 @@ import qualified AST.Type as Type
1414import qualified Reporting.Annotation as A
1515import qualified Reporting.Error.Type as Error
1616import qualified Type.State as TS
17−import Type.Type
17+import Type.Type as Type
1818import Type.Unify
1919
2020
21+
2122{-| Every variable has rank less than or equal to the maxRank of the pool.
2223This sorts variables into the young and old pools accordingly.
2324-}
24−generalize :: TS.Pool -> StateT TS.SolverState IO ()
25+generalize :: TS.Pool -> TS.Solver ()
2526generalize youngPool =
2627 do youngMark <- TS.uniqueMark
2728 let youngRank = TS.maxRank youngPool
2829 let insert dict var =
2930 do descriptor <- liftIO $ UF.descriptor var
30− liftIO $ UF.modifyDescriptor var (\desc -> desc { mark = youngMark })
31− return $ Map.insertWith (++) (rank descriptor) [var] dict
31+ liftIO $ UF.modifyDescriptor var (\desc -> desc { _mark = youngMark })
32+ return $ Map.insertWith (++) (_rank descriptor) [var] dict
3233
3334 -- Sort the youngPool variables by rank.
3435 rankDict <- foldM insert Map.empty (TS.inhabitants youngPool)
@@ -58,63 +59,98 @@ generalize youngPool =
5859 True -> return ()
5960 False -> do
6061 desc <- liftIO $ UF.descriptor var
61− case rank desc < youngRank of
62− True -> TS.register var >> return ()
63− False -> do
64− let flex' = case flex desc of { Flexible -> Rigid ; other -> other }
65− liftIO $ UF.setDescriptor var (desc { rank = noRank, flex = flex' })
62+ case _rank desc < youngRank of
63+ True ->
64+ TS.register var >> return ()
65+ False ->
66+ liftIO $ UF.setDescriptor var $ desc
67+ { _rank = noRank
68+ , _content = rigidify (_content desc)
69+ }
6670
6771 mapM_ registerIfLowerRank (Map.findWithDefault [] youngRank rankDict)
6872
6973
74+rigidify :: Content -> Content
75+rigidify content =
76+ case content of
77+ Var Flex maybeSuper _ ->
78+ Var Rigid maybeSuper Nothing
79+
80+ _ ->
81+ content
82+
83+
7084-- adjust the ranks of variables such that ranks never increase as you
7185-- move deeper into a variable.
72−adjustRank :: Int -> Int -> Int -> Variable -> StateT TS.SolverState IO Int
86+adjustRank :: Int -> Int -> Int -> Variable -> TS.Solver Int
7387adjustRank youngMark visitedMark groupRank var =
7488 do descriptor <- liftIO $ UF.descriptor var
75− case () of
76− () | mark descriptor == youngMark ->
77− do -- Set the variable as marked first because it may be cyclic.
78− liftIO $ UF.modifyDescriptor var $ \desc ->
79− desc { mark = visitedMark }
80− rank' <- maybe (return groupRank) adjustTerm (structure descriptor)
81− liftIO $ UF.modifyDescriptor var $ \desc ->
82− desc { rank = rank' }
83− return rank'
84−
85− | mark descriptor /= visitedMark ->
86− do let rank' = min groupRank (rank descriptor)
87− liftIO $ UF.setDescriptor var (descriptor { mark = visitedMark, rank = rank' })
88− return rank'
89−
90− | otherwise ->
91− return (rank descriptor)
92− where
93− adjust =
94− adjustRank youngMark visitedMark groupRank
95−
96− adjustTerm term =
97− case term of
98− App1 a b ->
99− max `liftM` adjust a `ap` adjust b
100−
101− Fun1 a b ->
102− max `liftM` adjust a `ap` adjust b
103−
104− Var1 x ->
105− adjust x
106−
107− EmptyRecord1 ->
108− return outermostRank
109−
110− Record1 fields extension ->
111− do ranks <- mapM adjust (concat (Map.elems fields))
112− rnk <- adjust extension
113− return . maximum $ rnk : ranks
89+ adjustRankHelp youngMark visitedMark groupRank var descriptor
90+
91+
92+adjustRankHelp :: Int -> Int -> Int -> Variable -> Descriptor -> TS.Solver Int
93+adjustRankHelp youngMark visitedMark groupRank var descriptor =
94+ if _mark descriptor == youngMark then
95+
96+ do -- Set the variable as marked first because it may be cyclic.
97+ liftIO $ UF.modifyDescriptor var $ \desc ->
98+ desc { _mark = visitedMark }
99+
100+ maxRank <-
101+ adjustRankContent youngMark visitedMark groupRank (_content descriptor)
102+
103+ liftIO $ UF.modifyDescriptor var $ \desc ->
104+ desc { _rank = maxRank }
105+
106+ return maxRank
107+
108+ else if _mark descriptor /= visitedMark then
109+
110+ do let minRank = min groupRank (_rank descriptor)
111+ liftIO $ UF.setDescriptor var (descriptor { _mark = visitedMark, _rank = minRank })
112+ return minRank
113+
114+ else
115+
116+ return (_rank descriptor)
117+
118+
119+adjustRankContent :: Int -> Int -> Int -> Content -> TS.Solver Int
120+adjustRankContent youngMark visitedMark groupRank content =
121+ let
122+ go = adjustRank youngMark visitedMark groupRank
123+ in
124+ case content of
125+ Error ->
126+ return groupRank
127+
128+ Atom _ ->
129+ return groupRank
130+
131+ Var _ _ _ ->
132+ return groupRank
133+
134+ Alias _ args realVar ->
135+ maximum <$> mapM go (realVar : map snd args)
136+
137+ Structure (App1 func arg) ->
138+ max <$> go func <*> go arg
139+
140+ Structure (Fun1 arg result) ->
141+ max <$> go arg <*> go result
142+
143+ Structure EmptyRecord1 ->
144+ return outermostRank
145+
146+ Structure (Record1 fields extension) ->
147+ maximum <$> mapM go (extension : Map.elems fields)
148+
114149
115150
116151-- SOLVER
117152
153+
118154solve :: TypeConstraint -> ExceptT [A.Located Error.Error] IO TS.SolverState
119155solve constraint =
120156 do state <-
@@ -126,7 +162,7 @@ solve constraint =
126162 throwError errors
127163
128164
129−actuallySolve :: TypeConstraint -> StateT TS.SolverState IO ()
165+actuallySolve :: TypeConstraint -> TS.Solver ()
130166actuallySolve constraint =
131167 case constraint of
132168 CTrue ->
@@ -151,7 +187,7 @@ actuallySolve constraint =
151187
152188 CLet schemes constraint' ->
153189 do oldEnv <- TS.getEnv
154− headers <- Map.unions `fmap` mapM solveScheme schemes
190+ headers <- Map.unions <$> mapM solveScheme schemes
155191 TS.modifyEnv $ \env -> Map.union headers env
156192 actuallySolve constraint'
157193 mapM occurs $ Map.toList headers
@@ -165,17 +201,17 @@ actuallySolve constraint =
165201 TS.makeInstance tipe
166202
167203 Nothing ->
168− if List.isPrefixOf "Native." name
169− then liftIO (variable Flexible)
170− else error ("Could not find `" ++ name ++ "` when solving type constraints.")
204+ if List.isPrefixOf "Native." name then
205+ liftIO (mkVar Nothing)
206+
207+ else
208+ error ("Could not find `" ++ name ++ "` when solving type constraints.")
171209
172210 t <- TS.flatten term
173211 unify (Error.Instance name) region freshCopy t
174212
175213
176−solveScheme
177− :: TypeScheme
178− -> StateT TS.SolverState IO (Map.Map String (A.Located Variable))
214+solveScheme :: TypeScheme -> TS.Solver (Map.Map String (A.Located Variable))
179215solveScheme scheme =
180216 let
181217 flatten (A.A region term) =
@@ -210,26 +246,37 @@ solveScheme scheme =
210246-- Checks that all of the given variables belong to distinct equivalence classes.
211247-- Also checks that their structure is Nothing, so they represent a variable, not
212248-- a more complex term.
213−allDistinct :: [Variable] -> StateT TS.SolverState IO ()
249+allDistinct :: [Variable] -> TS.Solver ()
214250allDistinct vars =
215− do seen <- TS.uniqueMark
251+ do seenMark <- TS.uniqueMark
216252 forM_ vars $ \var ->
217253 do desc <- liftIO $ UF.descriptor var
218− case structure desc of
219− Just _ ->
220− crash "Cannot generalize something that is not a type variable."
254+ case _content desc of
255+ Structure _ ->
256+ crash "Can only generalize type variables, not structures."
257+
258+ Atom _ ->
259+ crash "Can only generalize type variables, not structures."
260+
261+ Alias _ _ _ ->
262+ crash "Can only generalize type variables, not aliases."
263+
264+ Error ->
265+ crash "Can only generalize type variables, not error types."
266+
267+ Var _ _ _ ->
268+ if _mark desc == seenMark then
269+ crash "Duplicate variable during generalization."
221270
222− Nothing ->
223− if mark desc == seen
224− then crash "Duplicate variable during generalization."
225− else liftIO (UF.setDescriptor var (desc { mark = seen }))
271+ else
272+ liftIO (UF.setDescriptor var (desc { _mark = seenMark }))
226273
227274
228275-- Check that a variable has rank == noRank, meaning that it can be generalized.
229−isGeneric :: Variable -> StateT TS.SolverState IO ()
276+isGeneric :: Variable -> TS.Solver ()
230277isGeneric var =
231278 do desc <- liftIO $ UF.descriptor var
232− if rank desc == noRank
279+ if _rank desc == noRank
233280 then return ()
234281 else crash "Unable to generalize a type variable. It is not unranked."
235282
@@ -237,59 +284,66 @@ isGeneric var =
237284crash :: String -> a
238285crash msg =
239286 error $
240− "It looks like something went wrong with the type inference algorithm.\n"
241− ++ msg ++ "\n"
287+ "It looks like something went wrong with the type inference algorithm.\n\n"
288+ ++ msg ++ "\n\n"
242289 ++ "Please create a minimal example that triggers this problem and report it to\n"
243290 ++ "<https://github.com/elm-lang/elm-compiler/issues>"
244291
245292
246−occurs :: (String, A.Located Variable) -> StateT TS.SolverState IO ()
293+
294+-- OCCURS CHECK
295+
296+
297+occurs :: (String, A.Located Variable) -> TS.Solver ()
247298occurs (name, A.A region variable) =
248− do maybePair <- liftIO $ occursHelp [] variable
249− case maybePair of
299+ do maybeInfinite <- liftIO $ occursHelp [] variable
300+ case maybeInfinite of
250301 Nothing ->
251302 return ()
252303
253− Just (t1, t2) ->
254− let
255− info = Error.InfiniteTypeInfo name t1 t2
256− in
257− TS.addError region (Error.InfiniteType info)
304+ Just infiniteType ->
305+ do overallType <- liftIO (Type.toSrcType variable)
306+ TS.addError region (Error.InfiniteType name overallType infiniteType)
258307
259308
260−occursHelp
261− :: [Variable]
262− -> Variable
263− -> IO (Maybe (Type.Canonical, Type.Canonical))
309+occursHelp :: [Variable] -> Variable -> IO (Maybe Type.Canonical)
264310occursHelp seen var =
265311 if elem var seen then
266− do desc <- UF.descriptor var
267− UF.setDescriptor var (desc { structure = Nothing })
268− var' <- UF.fresh desc
269− srcVar <- toSrcType var
270− srcVar' <- toSrcType var'
271− return (Just (srcVar, srcVar'))
312+ do infiniteDescriptor <- UF.descriptor var
313+ structureVar <- UF.fresh infiniteDescriptor
314+ UF.setDescriptor var (infiniteDescriptor { _content = Error })
315+ srcVar <- Type.toSrcType structureVar
316+ return (Just srcVar)
317+
272318 else
273319 do desc <- UF.descriptor var
274− case structure desc of
275− Nothing ->
320+ case _content desc of
321+ Atom _ ->
276322 return Nothing
277323
278− Just struct ->
279− let go = occursHelp (var:seen)
324+ Var _ _ _ ->
325+ return Nothing
326+
327+ Error ->
328+ return Nothing
329+
330+ Alias _ args _ ->
331+ -- TODO is it okay to only check args?
332+ F.asum <$> mapM (occursHelp (var:seen) . snd) args
333+
334+ Structure term ->
335+ let
336+ go = occursHelp (var:seen)
280337 in
281− case struct of
338+ case term of
282339 App1 a b ->
283340 (<|>) <$> go a <*> go b
284341
285342 Fun1 a b ->
286343 (<|>) <$> go a <*> go b
287344
288− Var1 a ->
289− go a
290−
291345 EmptyRecord1 ->
292346 return Nothing
293347
294348 Record1 fields ext ->
295− F.asum <$> mapM go (ext : concat (Map.elems fields))
349+ F.asum <$> mapM go (ext : Map.elems fields)
src/Type/State.hs+197−136
@@ -1,12 +1,9 @@
1−{-# LANGUAGE FlexibleContexts #-}
2−{-# LANGUAGE MultiParamTypeClasses #-}
1+{-# OPTIONS_GHC -Wall #-}
32module Type.State where
43
5−import Control.Applicative ((<|>))
6−import Control.Monad.State
4+import qualified Control.Monad.State as State
75import Data.Map ((!))
86import qualified Data.Map as Map
9−import qualified Data.Traversable as Traversable
107import qualified Data.UnionFind.IO as UF
118
129import qualified Reporting.Annotation as A
@@ -37,6 +34,9 @@ emptyPool =
3734type Env = Map.Map String (A.Located Variable)
3835
3936
37+type Solver = State.StateT SolverState IO
38+
39+
4040-- Keeps track of the environment, type variable pool, and a list of errors
4141data SolverState = SS
4242 { sEnv :: Env
@@ -58,191 +58,257 @@ initialState =
5858 }
5959
6060
61−modifyEnv :: (MonadState SolverState m) => (Env -> Env) -> m ()
61+modifyEnv :: (Env -> Env) -> Solver ()
6262modifyEnv f =
63− modify $ \state -> state { sEnv = f (sEnv state) }
63+ State.modify $ \state -> state { sEnv = f (sEnv state) }
6464
6565
66−modifyPool :: (MonadState SolverState m) => (Pool -> Pool) -> m ()
66+modifyPool :: (Pool -> Pool) -> Solver ()
6767modifyPool f =
68− modify $ \state -> state { sPool = f (sPool state) }
68+ State.modify $ \state -> state { sPool = f (sPool state) }
6969
7070
71−addError :: R.Region -> Error.Error -> StateT SolverState IO ()
71+addError :: R.Region -> Error.Error -> Solver ()
7272addError region err =
73− modify $ \state -> state { sError = A.A region err : sError state }
73+ State.modify $ \state -> state { sError = A.A region err : sError state }
7474
7575
76−switchToPool :: (MonadState SolverState m) => Pool -> m ()
76+switchToPool :: Pool -> Solver ()
7777switchToPool pool =
7878 modifyPool (\_ -> pool)
7979
8080
81−getPool :: StateT SolverState IO Pool
81+getPool :: Solver Pool
8282getPool =
83− gets sPool
83+ State.gets sPool
8484
8585
86−getEnv :: StateT SolverState IO Env
86+getEnv :: Solver Env
8787getEnv =
88− gets sEnv
88+ State.gets sEnv
8989
9090
91−saveLocalEnv :: StateT SolverState IO ()
91+saveLocalEnv :: Solver ()
9292saveLocalEnv =
9393 do currentEnv <- getEnv
94− modify $ \state -> state { sSavedEnv = currentEnv }
94+ State.modify $ \state -> state { sSavedEnv = currentEnv }
9595
9696
97−uniqueMark :: StateT SolverState IO Int
97+uniqueMark :: Solver Int
9898uniqueMark =
99− do state <- get
99+ do state <- State.get
100100 let mark = sMark state
101− put $ state { sMark = mark + 1 }
101+ State.put $ state { sMark = mark + 1 }
102102 return mark
103103
104104
105−nextRankPool :: StateT SolverState IO Pool
105+nextRankPool :: Solver Pool
106106nextRankPool =
107107 do pool <- getPool
108108 return $ Pool { maxRank = maxRank pool + 1, inhabitants = [] }
109109
110110
111−register :: Variable -> StateT SolverState IO Variable
111+register :: Variable -> Solver Variable
112112register variable =
113113 do modifyPool $ \pool -> pool { inhabitants = variable : inhabitants pool }
114114 return variable
115115
116116
117−introduce :: Variable -> StateT SolverState IO Variable
117+introduce :: Variable -> Solver Variable
118118introduce variable =
119119 do pool <- getPool
120− liftIO $ UF.modifyDescriptor variable (\desc -> desc { rank = maxRank pool })
120+ State.liftIO $ UF.modifyDescriptor variable (\desc -> desc { _rank = maxRank pool })
121121 register variable
122122
123123
124−flatten :: Type -> StateT SolverState IO Variable
124+flatten :: Type -> Solver Variable
125125flatten term =
126126 flattenHelp Map.empty term
127127
128128
129−flattenHelp :: Map.Map String Variable -> Type -> StateT SolverState IO Variable
130−flattenHelp aliasDict term =
131− case term of
129+flattenHelp :: Map.Map String Variable -> Type -> Solver Variable
130+flattenHelp aliasDict termN =
131+ case termN of
132132 PlaceHolder name ->
133− return (aliasDict ! name)
134−
135− VarN maybeAlias v ->
136− do maybeAlias' <- Traversable.traverse flattenAlias maybeAlias
137− liftIO $ UF.modifyDescriptor v $ \desc ->
138− desc { alias = maybeAlias' <|> alias desc }
139− return v
140−
141− TermN maybeAlias subTerm ->
142− do maybeAlias' <- Traversable.traverse flattenAlias maybeAlias
143− let localDict = maybe aliasDict (Map.fromList . snd) maybeAlias'
144− flatStructure <- traverseTerm (flattenHelp localDict) subTerm
145− pool <- getPool
146− var <-
147− liftIO . UF.fresh $ Descriptor
148− { structure = Just flatStructure
149− , rank = maxRank pool
150− , flex = Flexible
151− , name = Nothing
152− , copy = Nothing
153− , mark = noMark
154− , alias = maybeAlias'
133+ return (aliasDict ! name)
134+
135+ AliasN name args realType ->
136+ do flatArgs <- mapM (traverse (flattenHelp aliasDict)) args
137+ flatVar <- flattenHelp (Map.fromList flatArgs) realType
138+ pool <- getPool
139+ variable <-
140+ State.liftIO . UF.fresh $ Descriptor
141+ { _content = Alias name flatArgs flatVar
142+ , _rank = maxRank pool
143+ , _mark = noMark
144+ , _copy = Nothing
145+ }
146+ register variable
147+
148+ VarN v ->
149+ return v
150+
151+ TermN term1 ->
152+ do variableTerm <- traverseTerm (flattenHelp aliasDict) term1
153+ pool <- getPool
154+ variable <-
155+ State.liftIO . UF.fresh $ Descriptor
156+ { _content = Structure variableTerm
157+ , _rank = maxRank pool
158+ , _mark = noMark
159+ , _copy = Nothing
160+ }
161+ register variable
162+
163+
164+makeInstance :: Variable -> Solver Variable
165+makeInstance var =
166+ do alreadyCopiedMark <- uniqueMark
167+ freshVar <- makeCopy alreadyCopiedMark var
168+ _ <- restore alreadyCopiedMark var
169+ return freshVar
170+
171+
172+makeCopy :: Int -> Variable -> Solver Variable
173+makeCopy alreadyCopiedMark variable =
174+ do desc <- State.liftIO $ UF.descriptor variable
175+ makeCopyHelp desc alreadyCopiedMark variable
176+
177+
178+makeCopyHelp :: Descriptor -> Int -> Variable -> Solver Variable
179+makeCopyHelp descriptor alreadyCopiedMark variable =
180+ if _mark descriptor == alreadyCopiedMark then
181+ case _copy descriptor of
182+ Just copiedVariable ->
183+ return copiedVariable
184+
185+ Nothing ->
186+ error $
187+ "Error copying type variable. This should be impossible." ++
188+ " Please report an error to the github repo!"
189+
190+ else if _rank descriptor /= noRank || not (needsCopy (_content descriptor)) then
191+ return variable
192+
193+ else
194+ do pool <- getPool
195+ newVar <-
196+ State.liftIO $ UF.fresh $ Descriptor
197+ { _content = error "will be filled in soon!"
198+ , _rank = maxRank pool
199+ , _mark = noMark
200+ , _copy = Nothing
155201 }
156− register var
157− where
158− flattenAlias (name, args) =
159− let flattenPair (arg, subTerm) =
160− (,) arg <$> flattenHelp aliasDict subTerm
161− in
162− (,) name <$> mapM flattenPair args
202+ _ <- register newVar
163203
204+ -- Link the original variable to the new variable. This lets us
205+ -- avoid making multiple copies of the variable we are instantiating.
206+ --
207+ -- Need to do this before recursively copying the content of
208+ -- the variable to avoid looping on cyclic terms.
209+ State.liftIO $ UF.modifyDescriptor variable $ \desc ->
210+ desc { _mark = alreadyCopiedMark, _copy = Just newVar }
164211
212+ -- Now we recursively copy the content of the variable.
213+ -- We have already marked the variable as copied, so we
214+ -- will not repeat this work or crawl this variable again.
215+ let oldContent = _content descriptor
216+ newContent <-
217+ case oldContent of
218+ Structure term ->
219+ Structure <$> traverseTerm (makeCopy alreadyCopiedMark) term
165220
221+ Atom _ ->
222+ return oldContent
166223
167−makeInstance :: Variable -> StateT SolverState IO Variable
168−makeInstance var =
169− do alreadyCopied <- uniqueMark
170− freshVar <- makeCopy alreadyCopied var
171− restore alreadyCopied var
172− return freshVar
224+ Var Rigid maybeSuper _ ->
225+ return (Var Flex maybeSuper Nothing)
226+
227+ Var Flex _ _ ->
228+ return oldContent
229+
230+ Alias name args realType ->
231+ Alias name
232+ <$> mapM (traverse (makeCopy alreadyCopiedMark)) args
233+ <*> makeCopy alreadyCopiedMark realType
234+
235+ Error ->
236+ return oldContent
237+
238+ State.liftIO $ UF.modifyDescriptor newVar $ \desc ->
239+ desc { _content = newContent }
173240
241+ return newVar
174242
175−makeCopy :: Int -> Variable -> StateT SolverState IO Variable
176−makeCopy alreadyCopied variable = do
177− desc <- liftIO $ UF.descriptor variable
178− case () of
179− () | mark desc == alreadyCopied ->
180− case copy desc of
181− Just v ->
182− return v
183− Nothing ->
184− error $
185− "Error copying type variable. This should be impossible." ++
186− " Please report an error to the github repo!"
187−
188− | rank desc /= noRank || flex desc == Constant ->
243+
244+needsCopy :: Content -> Bool
245+needsCopy content =
246+ case content of
247+ Structure _ ->
248+ True
249+
250+ Atom _ ->
251+ False
252+
253+ Var _ _ _ ->
254+ True
255+
256+ Alias _ _ _ ->
257+ True
258+
259+ Error ->
260+ False
261+
262+
263+
264+restore :: Int -> Variable -> Solver Variable
265+restore alreadyCopiedMark variable =
266+ do desc <- State.liftIO $ UF.descriptor variable
267+ if _mark desc /= alreadyCopiedMark
268+ then
189269 return variable
190270
191− | otherwise ->
192− do pool <- getPool
193− newVar <-
194− liftIO $ UF.fresh $ Descriptor
195− { structure = Nothing
196− , rank = maxRank pool
197− , mark = noMark
198− , flex =
199− case flex desc of
200− Is s -> Is s
201− _ -> Flexible
202− , copy = Nothing
203− , name =
204− case flex desc of
205− Rigid -> Nothing
206− _ -> name desc
207− , alias = Nothing
208− }
209− register newVar
210−
211− -- Link the original variable to the new variable. This lets us
212− -- avoid making multiple copies of the variable we are instantiating.
213− --
214− -- Need to do this before recursively copying the structure of
215− -- the variable to avoid looping on cyclic terms.
216− liftIO $ UF.modifyDescriptor variable $ \desc ->
217− desc { mark = alreadyCopied, copy = Just newVar }
218−
219− -- Now we recursively copy the structure of the variable.
220− -- We have already marked the variable as copied, so we
221− -- will not repeat this work or crawl this variable again.
222− case structure desc of
223− Nothing ->
224− return newVar
225−
226− Just term ->
227− do newTerm <- traverseTerm (makeCopy alreadyCopied) term
228− liftIO $ UF.modifyDescriptor newVar $ \desc ->
229− desc { structure = Just newTerm }
230− return newVar
231−
232−
233−restore :: Int -> Variable -> StateT SolverState IO Variable
234−restore alreadyCopied variable =
235− do desc <- liftIO $ UF.descriptor variable
236− case mark desc /= alreadyCopied of
237− True -> return variable
238− False ->
239− do restoredStructure <-
240− Traversable.traverse (traverseTerm (restore alreadyCopied)) (structure desc)
241− liftIO $ UF.modifyDescriptor variable $ \desc ->
242− desc { mark = noMark, rank = noRank, structure = restoredStructure }
271+ else
272+ do restoredContent <-
273+ restoreContent alreadyCopiedMark (_content desc)
274+ State.liftIO $ UF.setDescriptor variable $ Descriptor
275+ { _content = restoredContent
276+ , _rank = noRank
277+ , _mark = noMark
278+ , _copy = Nothing
279+ }
243280 return variable
244281
245282
283+
284+restoreContent :: Int -> Content -> Solver Content
285+restoreContent alreadyCopiedMark content =
286+ let
287+ go = restore alreadyCopiedMark
288+ in
289+ case content of
290+ Structure term ->
291+ Structure <$> traverseTerm go term
292+
293+ Atom _ ->
294+ return content
295+
296+ Var _ _ _ ->
297+ return content
298+
299+ Alias name args var ->
300+ Alias name
301+ <$> mapM (traverse go) args
302+ <*> go var
303+
304+ Error ->
305+ return content
306+
307+
308+
309+-- TERM TRAVERSAL
310+
311+
246312traverseTerm :: (Monad f, Applicative f) => (a -> f b) -> Term1 a -> f (Term1 b)
247313traverseTerm f term =
248314 case term of
@@ -252,13 +318,8 @@ traverseTerm f term =
252318 Fun1 a b ->
253319 Fun1 <$> f a <*> f b
254320
255− Var1 x ->
256− Var1 <$> f x
257−
258321 EmptyRecord1 ->
259322 return EmptyRecord1
260323
261324 Record1 fields ext ->
262− Record1
263− <$> Traversable.traverse (mapM f) fields
264− <*> f ext
325+ Record1 <$> traverse f fields <*> f ext
src/Type/Type.hs+219−444
@@ -1,108 +1,117 @@
1+{-# OPTIONS_GHC -Wall #-}
12module Type.Type where
23
34import Control.Monad.State (StateT)
45import qualified Control.Monad.State as State
5−import qualified Data.Char as Char
6+import qualified Data.List as List
67import qualified Data.Map as Map
78import qualified Data.Set as Set
89import qualified Data.Traversable as Traverse (traverse)
910import qualified Data.UnionFind.IO as UF
10−import Text.PrettyPrint as P
11−import System.IO.Unsafe
1211
1312import qualified AST.Type as T
1413import qualified AST.Variable as Var
1514import qualified Reporting.Annotation as A
1615import qualified Reporting.Error.Type as Error
1716import qualified Reporting.Region as R
18−import Type.PrettyPrint
17+
1918
2019
2120-- CONCRETE TYPES
2221
23−type Type = TermN Variable
2422
25−type Variable = UF.Point Descriptor
23+type Type =
24+ TermN Variable
25+
26+
27+type Variable =
28+ UF.Point Descriptor
29+
2630
27−type TypeConstraint = Constraint Type Variable
31+type TypeConstraint =
32+ Constraint Type Variable
2833
29−type TypeScheme = Scheme Type Variable
3034
31−type Alias a = Maybe (Var.Canonical, [(String,a)])
35+type TypeScheme =
36+ Scheme Type Variable
37+
3238
3339
3440-- TYPE PRIMITIVES
3541
42+
3643data Term1 a
3744 = App1 a a
3845 | Fun1 a a
39− | Var1 a
4046 | EmptyRecord1
41− | Record1 (Map.Map String [a]) a
47+ | Record1 (Map.Map String a) a
4248
4349
4450data TermN a
4551 = PlaceHolder String
46− | VarN (Alias (TermN a)) a
47− | TermN (Alias (TermN a)) (Term1 (TermN a))
48−
52+ | AliasN Var.Canonical [(String, TermN a)] (TermN a)
53+ | VarN a
54+ | TermN (Term1 (TermN a))
4955
50−varN :: a -> TermN a
51−varN =
52− VarN Nothing
5356
54−
55−termN :: (Term1 (TermN a)) -> TermN a
56−termN =
57− TermN Nothing
58−
59−
60−record :: Map.Map String [TermN a] -> TermN a -> TermN a
57+record :: Map.Map String (TermN a) -> TermN a -> TermN a
6158record fs rec =
62− termN (Record1 fs rec)
59+ TermN (Record1 fs rec)
60+
6361
6462
6563-- DESCRIPTORS
6664
65+
6766data Descriptor = Descriptor
68− { structure :: Maybe (Term1 Variable)
69− , rank :: Int
70− , flex :: Flex
71− , name :: Maybe TypeName
72− , copy :: Maybe Variable
73− , mark :: Int
74− , alias :: Alias Variable
67+ { _content :: Content
68+ , _rank :: Int
69+ , _mark :: Int
70+ , _copy :: Maybe Variable
7571 }
7672
73+
74+data Content
75+ = Structure (Term1 Variable)
76+ | Atom Var.Canonical
77+ | Var Flex (Maybe Super) (Maybe String)
78+ | Alias Var.Canonical [(String,Variable)] Variable
79+ | Error
80+
81+
82+data Flex
83+ = Rigid
84+ | Flex
85+
86+
87+data Super
88+ = Number
89+ | Comparable
90+ | Appendable
91+ | CompAppend
92+ deriving (Eq)
93+
94+
7795noRank :: Int
7896noRank = -1
7997
98+
8099outermostRank :: Int
81100outermostRank = 0
82101
102+
83103noMark :: Int
84104noMark = 0
85105
106+
86107initialMark :: Int
87108initialMark = 1
88109
89−data Flex
90− = Rigid
91− | Flexible
92− | Constant
93− | Is SuperType
94− | Error
95− deriving (Eq)
96−
97−data SuperType
98− = Number
99− | Comparable
100− | Appendable
101− deriving (Eq)
102110
103111
104112-- CONSTRAINTS
105113
114+
106115data Constraint a b
107116 = CTrue
108117 | CSaveEnv
@@ -111,66 +120,88 @@ data Constraint a b
111120 | CLet [Scheme a b] (Constraint a b)
112121 | CInstance R.Region SchemeName a
113122
123+
114124type SchemeName = String
115125
116−type TypeName = Var.Canonical
117126
118127data Scheme a b = Scheme
119− { rigidQuantifiers :: [b]
120− , flexibleQuantifiers :: [b]
121− , constraint :: Constraint a b
122− , header :: Map.Map String (A.Located a)
128+ { _rigidQuantifiers :: [b]
129+ , _flexibleQuantifiers :: [b]
130+ , _constraint :: Constraint a b
131+ , _header :: Map.Map String (A.Located a)
123132 }
124133
125134
135+
126136-- TYPE HELPERS
127137
138+
128139infixr 9 ==>
129140
141+
130142(==>) :: Type -> Type -> Type
131143(==>) a b =
132− termN (Fun1 a b)
144+ TermN (Fun1 a b)
133145
134146
135147(<|) :: TermN a -> TermN a -> TermN a
136148(<|) f a =
137− termN (App1 f a)
138−
149+ TermN (App1 f a)
139150
140−-- VARIABLE HELPERS
141151
142−namedVar :: Flex -> Var.Canonical -> IO Variable
143−namedVar flex name = UF.fresh $ Descriptor
144− { structure = Nothing
145− , rank = noRank
146− , flex = flex
147− , name = Just name
148− , copy = Nothing
149− , mark = noMark
150− , alias = Nothing
151− }
152152
153+-- VARIABLE CREATION
153154
154−variable :: Flex -> IO Variable
155−variable flex =
156− UF.fresh (descriptor flex)
157155
158−
159−descriptor :: Flex -> Descriptor
160−descriptor flex =
156+mkDescriptor :: Content -> Descriptor
157+mkDescriptor content =
161158 Descriptor
162− { structure = Nothing
163− , rank = noRank
164− , flex = flex
165− , name = Nothing
166− , copy = Nothing
167− , mark = noMark
168− , alias = Nothing
159+ { _content = content
160+ , _rank = noRank
161+ , _mark = noMark
162+ , _copy = Nothing
169163 }
170164
171165
166+mkAtom :: Var.Canonical -> IO Variable
167+mkAtom name =
168+ UF.fresh $ mkDescriptor (Atom name)
169+
170+
171+mkVar :: Maybe Super -> IO Variable
172+mkVar maybeSuper =
173+ UF.fresh $ mkDescriptor (Var Flex maybeSuper Nothing)
174+
175+
176+mkNamedVar :: String -> IO Variable
177+mkNamedVar name =
178+ UF.fresh $ mkDescriptor (Var Flex (toSuper name) Nothing)
179+
180+
181+mkRigid :: String -> IO Variable
182+mkRigid name =
183+ UF.fresh $ mkDescriptor (Var Rigid (toSuper name) (Just name))
184+
185+
186+toSuper :: String -> Maybe Super
187+toSuper name =
188+ if List.isPrefixOf "number" name then
189+ Just Number
190+
191+ else if List.isPrefixOf "comparable" name then
192+ Just Comparable
193+
194+ else if List.isPrefixOf "appendable" name then
195+ Just Appendable
196+
197+ else
198+ Nothing
199+
200+
201+
172202-- CONSTRAINT HELPERS
173203
204+
174205monoscheme :: Map.Map String (A.Located a) -> Scheme a b
175206monoscheme headers =
176207 Scheme [] [] CTrue headers
@@ -200,401 +231,178 @@ fl rqs constraint =
200231
201232exists :: (Type -> IO TypeConstraint) -> IO TypeConstraint
202233exists f =
203− do v <- variable Flexible
204− ex [v] <$> f (varN v)
234+ do v <- mkVar Nothing
235+ ex [v] <$> f (VarN v)
205236
206237
207238existsNumber :: (Type -> IO TypeConstraint) -> IO TypeConstraint
208239existsNumber f =
209− do v <- variable (Is Number)
210− ex [v] <$> f (varN v)
211−
212−
213−-- TYPES TO PRETTY STRINGS
214−
215−instance PrettyType a => PrettyType (UF.Point a) where
216− pretty when point =
217− unsafePerformIO $ fmap (pretty when) (UF.descriptor point)
218−
219−
220−instance PrettyType a => PrettyType (Term1 a) where
221− pretty when term =
222− let prty = pretty Never in
223− case term of
224− App1 f x ->
225− parensIf needed (px <+> pretty App x)
226− where
227− px = prty f
228− needed =
229− case when of
230− App -> True
231− _ -> False
232−
233− Fun1 arg body ->
234− parensIf needed (pretty Fn arg <+> P.text "->" <+> prty body)
235− where
236− needed =
237− case when of
238− Never -> False
239− _ -> True
240−
241− Var1 x ->
242− prty x
243−
244− EmptyRecord1 ->
245− P.braces P.empty
246−
247− Record1 fields ext ->
248− P.braces (extend <+> commaSep prettyFields)
249− where
250− prettyExt = prty ext
251−
252− extend
253− | P.render prettyExt == "{}" =
254− P.empty
255− | otherwise =
256− prettyExt <+> P.text "|"
257−
258− mkPretty f t =
259− P.text f <+> P.text ":" <+> prty t
260−
261− prettyFields =
262− concatMap (\(f,ts) -> map (mkPretty f) ts) (Map.toList fields)
263−
264−
265−instance PrettyType a => PrettyType (TermN a) where
266− pretty when term =
267− case term of
268− PlaceHolder _ ->
269− error "problem prettifying type, probably indicates a bigger problem"
270−
271− VarN alias x ->
272− either alias (pretty when x)
273−
274− TermN alias t1 ->
275− either alias (pretty when t1)
276− where
277− either maybeAlias doc =
278− case maybeAlias of
279− Nothing -> doc
280− Just (name, args) ->
281− P.hang
282− (P.text (Var.toString name))
283− 2
284− (P.sep (map (pretty App . snd) args))
285−
286−
287−instance PrettyType Descriptor where
288− pretty when desc =
289− case (alias desc, structure desc, name desc) of
290− (Just (name, args), _, _) ->
291− P.hang
292− (P.text (Var.toString name))
293− 4
294− (P.sep (map (pretty App . snd) args))
295−
296− (_, Just term, _) ->
297− pretty when term
298−
299− (_, _, Just name)
300− | Var.isTuple name ->
301− P.parens . P.text $ replicate (read (drop 6 (Var.toString name)) - 1) ','
302− | otherwise ->
303− P.text (Var.toString name)
304−
305− _ -> P.text "?"
306−
307−
308−instance (PrettyType a, PrettyType b) => PrettyType (Constraint a b) where
309− pretty _ constraint =
310− let prty = pretty Never in
311− case constraint of
312− CTrue ->
313− P.text "True"
314−
315− CSaveEnv ->
316− P.text "SaveTheEnvironment!!!"
317−
318− CEqual _ _ a b ->
319− prty a <+> P.text "=" <+> prty b
320−
321− CAnd [] ->
322− P.text "True"
323−
324− CAnd cs ->
325− P.parens . P.sep $ P.punctuate (P.text " and") (map (pretty Never) cs)
326−
327− CLet [Scheme [] fqs constraint header] CTrue | Map.null header ->
328− P.sep [ binder, pretty Never c ]
329− where
330− mergeExists vs c =
331− case c of
332− CLet [Scheme [] fqs' c' _] CTrue -> mergeExists (vs ++ fqs') c'
333− _ -> (vs, c)
334−
335− (fqs', c) = mergeExists fqs constraint
336−
337− binder =
338− if null fqs'
339− then P.empty
340− else
341− P.text "\x2203" <+> P.hsep (map (pretty Never) fqs') <> P.text "."
342−
343− CLet schemes constraint ->
344− P.fsep
345− [ P.hang (P.text "let") 4 (P.brackets . commaSep $ map (pretty Never) schemes)
346− , P.text "in", pretty Never constraint
347− ]
240+ do v <- mkVar (Just Number)
241+ ex [v] <$> f (VarN v)
348242
349− CInstance _region name tipe ->
350− P.text name <+> P.text "<" <+> prty tipe
351243
352244
353−instance (PrettyType a, PrettyType b) => PrettyType (Scheme a b) where
354− pretty _ (Scheme rqs fqs constraint headers) =
355− P.sep [ forall, cs, headers' ]
356− where
357− prty = pretty Never
358−
359− forall =
360− if null rqs && null fqs
361− then P.empty
362− else P.text "\x2200" <+> frees <+> rigids
363−
364− frees = P.hsep (map prty fqs)
365−
366− rigids =
367− if null rqs
368− then P.empty
369− else P.braces . P.hsep $ map prty rqs
245+-- CONVERT TO SOURCE TYPES
370246
371− cs =
372− case constraint of
373− CTrue -> P.empty
374− CAnd [] -> P.empty
375− _ -> P.brackets (pretty Never constraint)
376247
377− headers' =
378− if Map.size headers > 0 then dict else P.empty
248+-- TODO: Attach resulting type to the descriptor so that you
249+-- never have to do extra work, particularly nice for aliased types
250+toSrcType :: Variable -> IO T.Canonical
251+toSrcType variable =
252+ do usedNames <- getVarNames variable
253+ State.evalStateT (variableToSrcType variable) (makeNameState usedNames)
379254
380− dict =
381− P.parens . commaSep . map prettyPair $ Map.toList headers
382255
383− prettyPair (fieldName, A.A _ tipe) =
384− P.text fieldName <+> P.text ":" <+> pretty Never tipe
256+variableToSrcType :: Variable -> StateT NameState IO T.Canonical
257+variableToSrcType variable =
258+ do descriptor <- State.liftIO (UF.descriptor variable)
259+ case _content descriptor of
260+ Structure term ->
261+ termToSrcType term
385262
263+ Atom name ->
264+ return (T.Type name)
386265
387−-- CONVERT TO SOURCE TYPES
266+ Var _ _ (Just name) ->
267+ return (T.Var name)
388268
389−-- TODO: Attach resulting type to the descriptor so that you
390−-- never have to do extra work, particularly nice for aliased types
391−toSrcType :: Variable -> IO T.Canonical
392−toSrcType variable =
393− do addNames variable
394− variableToSrcType variable variable
269+ Var flex maybeSuper Nothing ->
270+ do freshName <- getFreshName maybeSuper
271+ State.liftIO $ UF.modifyDescriptor variable $ \desc ->
272+ desc { _content = Var flex maybeSuper (Just freshName) }
273+ return (T.Var freshName)
395274
275+ Alias name args realVariable ->
276+ do srcArgs <- mapM (\(arg,tvar) -> (,) arg <$> variableToSrcType tvar) args
277+ srcType <- variableToSrcType realVariable
278+ return (T.Aliased name srcArgs (T.Filled srcType))
396279
397−variableToSrcType :: Variable -> Variable -> IO T.Canonical
398−variableToSrcType rootVariable variable =
399− do desc <- UF.descriptor variable
400− srcType <- maybe (backupSrcType desc) (termToSrcType rootVariable) (structure desc)
401− case alias desc of
402− Nothing ->
403− return srcType
280+ Error ->
281+ return (T.Var "?")
404282
405− Just (name, args) ->
406− case srcType of
407− T.Type (Var.Canonical Var.BuiltIn _) ->
408− return srcType
409283
410− _ ->
411− do args' <- mapM (\(arg,tvar) -> (,) arg <$> variableToSrcType rootVariable tvar) args
412− return (T.Aliased name args' (T.Filled srcType))
413− where
414− backupSrcType :: Descriptor -> IO T.Canonical
415− backupSrcType desc =
416− case name desc of
417− Just v@(Var.Canonical _ x@(c:_))
418− | Char.isLower c ->
419− return (T.Var x)
420− | otherwise ->
421− return $ T.Type v
422−
423− _ ->
424− error $
425− concat
426− [ "Problem converting the following type "
427− , "from a type-checker type to a source-syntax type:"
428− , P.render (pretty Never rootVariable)
429− ]
430−
431−
432−termToSrcType :: Variable -> Term1 Variable -> IO T.Canonical
433−termToSrcType rootVariable term =
434− let go = variableToSrcType rootVariable in
284+termToSrcType :: Term1 Variable -> StateT NameState IO T.Canonical
285+termToSrcType term =
435286 case term of
436− App1 a b ->
437− do a' <- go a
438− b' <- go b
439− case a' of
287+ App1 func arg ->
288+ do srcFunc <- variableToSrcType func
289+ srcArg <- variableToSrcType arg
290+ case srcFunc of
440291 T.App f args ->
441− return $ T.App f (args ++ [b'])
292+ return (T.App f (args ++ [srcArg]))
293+
442294 _ ->
443− return $ T.App a' [b']
295+ return (T.App srcFunc [srcArg])
444296
445297 Fun1 a b ->
446− T.Lambda <$> go a <*> go b
447−
448− Var1 a ->
449− go a
298+ T.Lambda
299+ <$> variableToSrcType a
300+ <*> variableToSrcType b
450301
451302 EmptyRecord1 ->
452303 return $ T.Record [] Nothing
453304
454− Record1 tfields extension ->
455− do fields' <- Traverse.traverse (mapM go) tfields
456− let fields = concat [ map ((,) name) ts | (name,ts) <- Map.toList fields' ]
457− ext' <- dealias <$> go extension
305+ Record1 fields extension ->
306+ do srcFields <- Map.toList <$> Traverse.traverse variableToSrcType fields
307+ srcExt <- T.iteratedDealias <$> variableToSrcType extension
458308 return $
459− case ext' of
460− T.Record fs ext -> T.Record (fs ++ fields) ext
461− T.Var _ -> T.Record fields (Just ext')
462− _ -> error "Used toSrcType on a type that is not well-formed"
463− where
464− dealias :: T.Canonical -> T.Canonical
465− dealias tipe =
466− case tipe of
467− T.Aliased _ args tipe' ->
468− T.dealias args tipe'
469− _ ->
470− tipe
309+ case srcExt of
310+ T.Record subFields subExt ->
311+ T.Record (subFields ++ srcFields) subExt
471312
313+ T.Var _ ->
314+ T.Record srcFields (Just srcExt)
472315
473−-- ADD NAMES TO TYPES
316+ _ ->
317+ error "Used toSrcType on a type that is not well-formed"
474318
475−addNames :: Variable -> IO ()
476−addNames variable =
477− do usedNames <- getVarNames variable
478− let freeNames = makeFreeNames usedNames
479− State.runStateT (varAddNames variable) (NameState freeNames 0 0 0)
480− return ()
481319
482320
483−makeFreeNames :: Set.Set String -> [String]
484−makeFreeNames usedNames =
485− let makeName suffix =
486− map (:suffix) ['a'..'z']
487−
488− allNames =
489− concatMap makeName ("" : "'" : "_" : map show [ (0 :: Int) .. ])
490− in
491− filter (\name -> Set.notMember name usedNames) allNames
321+-- MANAGE FRESH VARIABLE NAMES
492322
493323
494324data NameState = NameState
495− { freeNames :: [String]
496− , numberPrimes :: Int
497− , comparablePrimes :: Int
498− , appendablePrimes :: Int
325+ { _freeNames :: [String]
326+ , _numberPrimes :: Int
327+ , _comparablePrimes :: Int
328+ , _appendablePrimes :: Int
329+ , _compAppendPrimes :: Int
499330 }
500331
501332
502−varAddNames :: Variable -> StateT NameState IO ()
503−varAddNames var =
504− do desc <- State.liftIO (UF.descriptor var)
505− case alias desc of
506− Nothing ->
507− return ()
508−
509− Just (_name, args) ->
510− mapM_ (\(v,t) -> (,) v <$> varAddNames t) args
511−
512− case structure desc of
513− Just term ->
514− termAddNames term
515−
516− Nothing ->
517− case name desc of
518− Just _ -> return ()
519− Nothing ->
520− do name' <- createName desc
521− State.liftIO $ UF.modifyDescriptor var $ \desc ->
522− desc { name = Just (Var.local name') }
523−
524−
525−termAddNames :: Term1 Variable -> StateT NameState IO ()
526−termAddNames term =
527− case term of
528− App1 a b ->
529− do varAddNames a
530− varAddNames b
333+makeNameState :: Set.Set String -> NameState
334+makeNameState usedNames =
335+ let
336+ makeName suffix =
337+ map (:suffix) ['a'..'z']
531338
532− Fun1 a b ->
533− do varAddNames a
534− varAddNames b
339+ allNames =
340+ concatMap makeName ("" : map show [ (1 :: Int) .. ])
535341
536− Var1 a ->
537− varAddNames a
342+ freeNames =
343+ filter (\name -> Set.notMember name usedNames) allNames
344+ in
345+ NameState freeNames 0 0 0 0
538346
539− EmptyRecord1 ->
540− return ()
541−
542− Record1 fields extension ->
543− do mapM_ varAddNames (concat (Map.elems fields))
544− varAddNames extension
545347
348+getFreshName :: (Monad m) => Maybe Super -> StateT NameState m String
349+getFreshName maybeSuper =
350+ case maybeSuper of
351+ Nothing ->
352+ do names <- State.gets _freeNames
353+ State.modify (\state -> state { _freeNames = tail names })
354+ return (head names)
546355
547−createName :: (Monad m) => Descriptor -> StateT NameState m String
548−createName desc =
549− case flex desc of
550− Is Number ->
551− do primes <- State.gets numberPrimes
552− State.modify (\state -> state { numberPrimes = primes + 1 })
356+ Just Number ->
357+ do primes <- State.gets _numberPrimes
358+ State.modify (\state -> state { _numberPrimes = primes + 1 })
553359 return ("number" ++ replicate primes '\'')
554360
555− Is Comparable ->
556− do primes <- State.gets comparablePrimes
557− State.modify (\state -> state { comparablePrimes = primes + 1 })
361+ Just Comparable ->
362+ do primes <- State.gets _comparablePrimes
363+ State.modify (\state -> state { _comparablePrimes = primes + 1 })
558364 return ("comparable" ++ replicate primes '\'')
559365
560− Is Appendable ->
561− do primes <- State.gets appendablePrimes
562− State.modify (\state -> state { appendablePrimes = primes + 1 })
366+ Just Appendable ->
367+ do primes <- State.gets _appendablePrimes
368+ State.modify (\state -> state { _appendablePrimes = primes + 1 })
563369 return ("appendable" ++ replicate primes '\'')
564370
565− _ ->
566− do names <- State.gets freeNames
567− State.modify (\state -> state { freeNames = tail names })
568− return (head names)
371+ Just CompAppend ->
372+ do primes <- State.gets _compAppendPrimes
373+ State.modify (\state -> state { _compAppendPrimes = primes + 1 })
374+ return ("compappend" ++ replicate primes '\'')
375+
569376
570377
571378-- GET ALL VARIABLE NAMES
572379
380+
573381getVarNames :: Variable -> IO (Set.Set String)
574382getVarNames var =
575383 do desc <- UF.descriptor var
576384
577− let baseSet =
578− case name desc of
579− Just var -> Set.singleton (Var.toString var)
580− Nothing -> Set.empty
385+ case _content desc of
386+ Var _ _ (Just name) ->
387+ return (Set.singleton name)
388+
389+ Var _ _ Nothing ->
390+ return Set.empty
581391
582− structureSet <-
583− case structure desc of
584− Nothing -> return Set.empty
585− Just term -> getVarNamesTerm term
392+ Structure term ->
393+ getVarNamesTerm term
586394
587− aliasSet <-
588− case alias desc of
589− Nothing ->
590− return Set.empty
395+ Alias _name args realVar ->
396+ do let argSet = Set.fromList (map fst args)
397+ realSet <- getVarNames realVar
398+ sets <- mapM (getVarNames . snd) args
399+ return (Set.unions (realSet : argSet : sets))
591400
592− Just (_name, args) ->
593− do let set = Set.fromList (map fst args)
594− sets <- mapM (getVarNames . snd) args
595− return (Set.unions (set : sets))
401+ Atom _ ->
402+ return Set.empty
596403
597− return (Set.unions [ baseSet, structureSet, aliasSet ])
404+ Error ->
405+ return Set.empty
598406
599407
600408getVarNamesTerm :: Term1 Variable -> IO (Set.Set String)
@@ -607,43 +415,10 @@ getVarNamesTerm term =
607415 Fun1 a b ->
608416 Set.union <$> go a <*> go b
609417
610− Var1 a ->
611− go a
612−
613418 EmptyRecord1 ->
614419 return Set.empty
615420
616421 Record1 fields extension ->
617− do fieldVars <- Set.unions <$> mapM go (concat (Map.elems fields))
422+ do fieldVars <- Set.unions <$> mapM go (Map.elems fields)
618423 Set.union fieldVars <$> go extension
619424
620−
621−-- COLLECT APPLICATIONS
622−
623−data AppStructure
624− = List Variable
625− | Tuple [Variable]
626− | Other
627−
628−
629−collectApps :: Variable -> IO AppStructure
630−collectApps var =
631− go [] var
632− where
633− go vars var = do
634− desc <- UF.descriptor var
635− case (structure desc, vars) of
636− (Nothing, [v]) ->
637− case name desc of
638− Just n | Var.isList n -> return (List v)
639− _ -> return Other
640−
641− (Nothing, vs) ->
642− case name desc of
643− Just n | Var.isTuple n -> return (Tuple vs)
644− _ -> return Other
645−
646− (Just term, _) ->
647− case term of
648− App1 a b -> go (vars ++ [b]) a
649− _ -> return Other
src/Type/Unify.hs+593−376
@@ -1,12 +1,10 @@
1+{-# OPTIONS_GHC -Wall #-}
12module Type.Unify (unify) where
23
3−import Control.Applicative ((<|>))
4−import Control.Monad.Except (ExceptT, throwError, runExceptT)
5−import Control.Monad.State as State
6−import qualified Data.List as List
4+import Control.Monad (zipWithM_)
5+import Control.Monad.Except (ExceptT, lift, liftIO, throwError, runExceptT)
76import qualified Data.Map as Map
87import qualified Data.UnionFind.IO as UF
9−import Text.PrettyPrint (render)
108
119import qualified AST.Type as AstType
1210import qualified AST.Variable as Var
@@ -14,435 +12,654 @@ import qualified Reporting.Region as R
1412import qualified Reporting.Error.Type as Error
1513import qualified Type.State as TS
1614import Type.Type as Type
17−import Type.PrettyPrint
18−import Elm.Utils ((|>))
19−
20−
21−unify
22− :: Error.Hint
23− -> R.Region
24− -> Variable
25− -> Variable
26− -> StateT TS.SolverState IO ()
27−unify hint region variable1 variable2 =
28− do result <- runExceptT (unifyHelp variable1 variable2)
15+
16+
17+
18+-- KICK OFF UNIFICATION
19+
20+
21+unify :: Error.Hint -> R.Region -> Variable -> Variable -> TS.Solver ()
22+unify hint region expected actual =
23+ do result <- runExceptT (guardedUnify ExpectedActual expected actual)
2924 case result of
3025 Right state ->
3126 return state
3227
33− Left (RawMismatch (leftType, rightType, note)) ->
34− TS.addError region $ Error.Mismatch $
35− Error.MismatchInfo hint leftType rightType note
28+ Left (Mismatch leftType rightType maybeReason) ->
29+ do rootType <- liftIO (Type.toSrcType expected)
30+ TS.addError region $ Error.Mismatch $
31+ Error.MismatchInfo hint rootType leftType rightType maybeReason
32+
3633
3734
38−-- ACTUALLY UNIFY STUFF
35+-- UNIFICATION HELPERS
36+
3937
4038type Unify =
41− ExceptT RawMismatch (StateT TS.SolverState IO)
39+ ExceptT Mismatch TS.Solver
40+
41+
42+data Context = Context
43+ { _orientation :: Orientation
44+ , _first :: Variable
45+ , _firstDesc :: Descriptor
46+ , _second :: Variable
47+ , _secondDesc :: Descriptor
48+ }
49+
50+
51+data Orientation = ExpectedActual | ActualExpected
52+
53+
54+reorient :: Context -> Context
55+reorient (Context orientation var1 desc1 var2 desc2) =
56+ let
57+ otherOrientation =
58+ case orientation of
59+ ExpectedActual -> ActualExpected
60+ ActualExpected -> ExpectedActual
61+ in
62+ Context otherOrientation var2 desc2 var1 desc1
63+
64+
65+
66+-- ERROR MESSAGES
67+
68+
69+data Mismatch
70+ = Mismatch AstType.Canonical AstType.Canonical (Maybe Error.Reason)
71+
4272
73+mismatch :: Context -> Maybe Error.Reason -> Unify a
74+mismatch (Context orientation first _ second _) maybeReason =
75+ let
76+ (expected, actual) =
77+ case orientation of
78+ ExpectedActual ->
79+ (first, second)
80+
81+ ActualExpected ->
82+ (second, first)
83+ in
84+ do errorMsg <- liftIO $
85+ do expectedSrcType <- Type.toSrcType expected
86+ actualSrcType <- Type.toSrcType actual
87+ return (Mismatch expectedSrcType actualSrcType maybeReason)
88+ mergeHelp expected actual Error
89+ throwError errorMsg
90+
91+
92+rigidityError :: Context -> Maybe String -> Unify ()
93+rigidityError context maybeName =
94+ mismatch context (Just (Error.Rigid maybeName))
95+
96+
97+
98+-- MERGE
99+
100+
101+merge :: Context -> Content -> Unify ()
102+merge (Context _ first _ second _) content =
103+ mergeHelp first second content
104+
105+
106+mergeHelp :: Variable -> Variable -> Content -> Unify ()
107+mergeHelp first second content =
108+ liftIO $ UF.union' first second $ \desc1 desc2 ->
109+ return $
110+ Descriptor
111+ { _content = content
112+ , _rank = min (_rank desc1) (_rank desc2)
113+ , _mark = noMark
114+ , _copy = Nothing
115+ }
43116
44−newtype RawMismatch =
45− RawMismatch (AstType.Canonical, AstType.Canonical, Maybe String)
46117
118+fresh :: Context -> Content -> Unify Variable
119+fresh (Context _ _ desc1 _ desc2) content =
120+ do freshVariable <-
121+ liftIO $ UF.fresh $
122+ Descriptor
123+ { _content = content
124+ , _rank = min (_rank desc1) (_rank desc2)
125+ , _mark = noMark
126+ , _copy = Nothing
127+ }
128+ lift (TS.register freshVariable)
47129
48−typeError
49− :: UF.Point Descriptor
50− -> UF.Point Descriptor
51− -> Maybe String
52− -> Unify a
53−typeError leftType rightType note =
54− do leftSrcType <- liftIO (Type.toSrcType leftType)
55− rightSrcType <- liftIO (Type.toSrcType rightType)
56− liftIO $ do
57− UF.setDescriptor leftType (Type.descriptor Error)
58− UF.setDescriptor rightType (Type.descriptor Error)
59− throwError (RawMismatch (leftSrcType, rightSrcType, note))
60130
61131
62−unifyHelp :: Variable -> Variable -> Unify ()
63−unifyHelp variable1 variable2 =
64− do equivalent <- liftIO $ UF.equivalent variable1 variable2
132+-- ACTUALLY UNIFY THINGS
133+
134+
135+guardedUnify :: Orientation -> Variable -> Variable -> Unify ()
136+guardedUnify orientation left right =
137+ do equivalent <- liftIO $ UF.equivalent left right
65138 if equivalent
66− then return ()
67− else actuallyUnify variable1 variable2
68−
69−
70−actuallyUnify :: Variable -> Variable -> Unify ()
71−actuallyUnify variable1 variable2 = do
72− desc1 <- liftIO $ UF.descriptor variable1
73− desc2 <- liftIO $ UF.descriptor variable2
74− let name' = pickName desc1 desc2
75− flex' = pickFlex desc1 desc2
76− rank' = pickRank desc1 desc2
77− alias' = pickAlias desc1 desc2
78−
79− merge1 :: Unify ()
80− merge1 =
81− liftIO $ do
82− if rank desc1 < rank desc2
83− then UF.union variable2 variable1
84− else UF.union variable1 variable2
85− UF.modifyDescriptor variable1 $ \desc ->
86− desc { structure = structure desc1
87− , flex = flex'
88− , name = name'
89− , alias = alias'
90− }
91−
92− merge2 :: Unify ()
93− merge2 =
94− liftIO $ do
95− if rank desc1 < rank desc2
96− then UF.union variable2 variable1
97− else UF.union variable1 variable2
98− UF.modifyDescriptor variable2 $ \desc ->
99− desc { structure = structure desc2
100− , flex = flex'
101− , name = name'
102− , alias = alias'
103− }
104−
105− merge =
106− if rank desc1 < rank desc2 then merge1 else merge2
107−
108− fresh :: Maybe (Term1 Variable) -> Unify Variable
109− fresh structure =
110− do v <- liftIO . UF.fresh $ Descriptor
111− { structure = structure
112− , rank = rank'
113− , flex = flex'
114− , name = name'
115− , copy = Nothing
116− , mark = noMark
117− , alias = alias'
118− }
119− lift (TS.register v)
120−
121− flexAndUnify v =
122− do liftIO $ UF.modifyDescriptor v $ \desc -> desc { flex = Flexible }
123− unifyHelp variable1 variable2
124−
125− unifyNumber svar (Var.Canonical home name) =
126− case home of
127− Var.BuiltIn | name `elem` ["Int","Float"] ->
128− flexAndUnify svar
129−
130− Var.Local | List.isPrefixOf "number" name ->
131− flexAndUnify svar
132−
133− Var.TopLevel _ | List.isPrefixOf "number" name ->
134− flexAndUnify svar
135−
136− _ ->
137− typeError variable1 variable2 Nothing
138−
139− comparableError maybeHint =
140− typeError variable1 variable2 $ Just $
141− "Note: comparable types include Int, Float, Char, String, lists, and tuples."
142− ++ maybe "" ("\n"++) maybeHint
143−
144− appendableError =
145− typeError variable1 variable2 $ Just $
146− "Note: appendable types include only Strings, Lists, and Text."
147−
148− unifyComparable v (Var.Canonical home name) =
149− case home of
150− Var.BuiltIn | name `elem` ["Int","Float","Char","String"] ->
151− flexAndUnify v
152− Var.Local | List.isPrefixOf "comparable" name ->
153− flexAndUnify v
154− _ ->
155− comparableError Nothing
156−
157− unifyComparableStructure varSuper varFlex =
158− do struct <- liftIO $ collectApps varFlex
159− case struct of
160− Other ->
161− comparableError Nothing
162−
163− List v ->
164− do flexAndUnify varSuper
165− unifyHelp v =<< liftIO (variable $ Is Comparable)
166−
167− Tuple vs ->
168− if length vs > 6 then
169− comparableError $ Just $
170− "Furthermore, it cannot be a tuple with more than 6 elements."
171− else
172− do flexAndUnify varSuper
173− cmpVars <- liftIO $ forM [1..length vs] $ \_ -> variable (Is Comparable)
174− zipWithM_ unifyHelp vs cmpVars
175−
176− unifyAppendable v cvar =
177− let
178− canUnify =
179− Var.isPrim "String" cvar
180− || Var.isText cvar
181− || Var.isLocal (List.isPrefixOf "comparable") cvar
182− || Var.isLocal (List.isPrefixOf "appendable") cvar
183− in
184− if canUnify then
185− flexAndUnify v
186− else
187− appendableError
188−
189− unifyAppendableStructure varSuper varFlex =
190− do struct <- liftIO $ collectApps varFlex
191− case struct of
192− List _ -> flexAndUnify varSuper
193− _ -> appendableError
194−
195− rigidError var =
196− typeError variable1 variable2 $ Just $
197− rigidErrorMessage (render (pretty Never var))
198−
199− superUnify =
200− case (flex desc1, flex desc2, name desc1, name desc2) of
201− (Is super1, Is super2, _, _)
202− | super1 == super2 -> merge
203− (Is Number, Is Comparable, _, _) -> merge1
204− (Is Comparable, Is Number, _, _) -> merge2
205−
206− (Is Number, _, _, Just name) -> unifyNumber variable1 name
207− (_, Is Number, Just name, _) -> unifyNumber variable2 name
208−
209− (Is Appendable, _, _, Just name) -> unifyAppendable variable1 name
210− (_, Is Appendable, Just name, _) -> unifyAppendable variable2 name
211− (Is Appendable, _, _, _) -> unifyAppendableStructure variable1 variable2
212− (_, Is Appendable, _, _) -> unifyAppendableStructure variable2 variable1
213−
214− (Is Comparable, _, _, Just name) -> unifyComparable variable1 name
215− (_, Is Comparable, Just name, _) -> unifyComparable variable2 name
216− (Is Comparable, _, _, _) -> unifyComparableStructure variable1 variable2
217− (_, Is Comparable, _, _) -> unifyComparableStructure variable2 variable1
218−
219− (Rigid, _, _, _) -> rigidError variable1
220− (_, Rigid, _, _) -> rigidError variable2
221− _ -> typeError variable1 variable2 Nothing
222−
223− case (structure desc1, structure desc2) of
224− (Nothing, Nothing)
225− | flex desc1 == Flexible && flex desc1 == Flexible ->
226− merge
227−
228− (Nothing, _)
229− | flex desc1 == Flexible -> merge2
230− | flex desc1 == Error -> return ()
231−
232− (_, Nothing)
233− | flex desc2 == Flexible -> merge1
234− | flex desc2 == Error -> return ()
235−
236− (Just (Var1 v), _) ->
237− unifyHelp v variable2
238−
239− (_, Just (Var1 v)) ->
240− unifyHelp variable1 v
241−
242− (Nothing, _) ->
243− superUnify
244−
245− (_, Nothing) ->
246− superUnify
247−
248− (Just type1, Just type2) ->
249− case (type1,type2) of
250− (App1 term1 term2, App1 term1' term2') ->
251− do merge
252− unifyHelp term1 term1'
253− unifyHelp term2 term2'
254− (Fun1 term1 term2, Fun1 term1' term2') ->
255− do merge
256− unifyHelp term1 term1'
257− unifyHelp term2 term2'
139+ then return ()
140+ else
141+ do leftDesc <- liftIO $ UF.descriptor left
142+ rightDesc <- liftIO $ UF.descriptor right
143+ actuallyUnify (Context orientation left leftDesc right rightDesc)
258144
259− (EmptyRecord1, EmptyRecord1) ->
260− return ()
261145
262− (Record1 fields ext, EmptyRecord1) | Map.null fields -> unifyHelp ext variable2
263− (EmptyRecord1, Record1 fields ext) | Map.null fields -> unifyHelp variable1 ext
146+subUnify :: Context -> Variable -> Variable -> Unify ()
147+subUnify context var1 var2 =
148+ guardedUnify (_orientation context) var1 var2
149+
264150
265− (Record1 _ _, Record1 _ _) ->
266− recordUnify fresh variable1 variable2
151+actuallyUnify :: Context -> Unify ()
152+actuallyUnify context@(Context _ _ firstDesc _ secondDesc) =
153+ let
154+ secondContent = _content secondDesc
155+ in
156+ case _content firstDesc of
157+ Error ->
158+ -- If there was an error, just pretend it is okay. This lets us avoid
159+ -- "cascading" errors where one problem manifests as multiple message.
160+ return ()
267161
268− _ -> typeError variable1 variable2 Nothing
162+ Var Flex Nothing _ ->
163+ unifyFlex context secondContent
269164
165+ Var Flex (Just super) _ ->
166+ unifySuper context super secondContent
270167
271−-- RIGID ERROR
168+ Var Rigid maybeSuper maybeName ->
169+ unifyRigid context maybeSuper maybeName secondContent
272170
273−rigidErrorMessage :: String -> String
274−rigidErrorMessage var =
275− "Could not unify user provided type variable `" ++ var ++ "`. The most likely cases are:\n\n"
276− ++ " 1. The type you wrote down is too general. It says any type can go through\n"
277− ++ " but in fact only a certain type can.\n"
278− ++ " 2. A type variable is probably being shared between two type annotations.\n"
279− ++ " They are treated as different things in the current implementation, so\n"
280− ++ " Try commenting out some type annotations and see what happens."
171+ Atom name ->
172+ unifyAtom context name secondContent
281173
174+ Alias name args realVar ->
175+ unifyAlias context name args realVar secondContent
282176
283−-- RECORD UNIFICATION
177+ Structure term ->
178+ unifyStructure context term secondContent
284179
285−recordUnify
286− :: (Maybe (Term1 Variable) -> Unify Variable)
287− -> Variable
288− -> Variable
289− -> Unify ()
290−recordUnify fresh variable1 variable2 =
291− do (ExpandedRecord fields1 ext1) <- liftIO (gatherFields variable1)
292− (ExpandedRecord fields2 ext2) <- liftIO (gatherFields variable2)
293180
294− unifyOverlappingFields fields1 fields2
295181
296− let freshRecord fields ext =
297− fresh (Just (Record1 fields ext))
182+-- UNIFY FLEXIBLE VARIABLES
298183
299− let uniqueFields1 = diffFields fields1 fields2
300− let uniqueFields2 = diffFields fields2 fields1
301184
302− let addFieldMismatchError missingFields =
303− typeError variable1 variable2 $ Just $
304− fieldMismatchError missingFields
185+unifyFlex :: Context -> Content -> Unify ()
186+unifyFlex context otherContent =
187+ case otherContent of
188+ Error ->
189+ return ()
305190
306− case (ext1, ext2) of
307− (Empty _, Empty _) ->
308− case Map.null uniqueFields1 && Map.null uniqueFields2 of
309− True -> return ()
310− False -> typeError variable1 variable2 Nothing
191+ Var Flex _ _ ->
192+ merge context otherContent
311193
312− (Empty var1, Extension var2) ->
313− case (Map.null uniqueFields1, Map.null uniqueFields2) of
314− (_, False) -> addFieldMismatchError uniqueFields2
315− (True, True) -> unifyHelp var1 var2
316− (False, True) ->
317− do subRecord <- freshRecord uniqueFields1 var1
318− unifyHelp subRecord var2
194+ Var Rigid _ _ ->
195+ merge context otherContent
319196
320− (Extension var1, Empty var2) ->
321− case (Map.null uniqueFields1, Map.null uniqueFields2) of
322− (False, _) -> addFieldMismatchError uniqueFields1
323− (True, True) -> unifyHelp var1 var2
324− (True, False) ->
325− do subRecord <- freshRecord uniqueFields2 var2
326− unifyHelp var1 subRecord
197+ Atom _ ->
198+ merge context otherContent
327199
328− (Extension var1, Extension var2) ->
329− case (Map.null uniqueFields1, Map.null uniqueFields2) of
330− (True, True) ->
331− unifyHelp var1 var2
200+ Alias _ _ _ ->
201+ merge context otherContent
332202
333− (True, False) ->
334− do subRecord <- freshRecord uniqueFields2 var2
335− unifyHelp var1 subRecord
203+ Structure _ ->
204+ merge context otherContent
205+
206+
207+
208+-- UNIFY RIGID VARIABLES
209+
210+
211+unifyRigid :: Context -> Maybe Super -> Maybe String -> Content -> Unify ()
212+unifyRigid context maybeSuper maybeName otherContent =
213+ case otherContent of
214+ Error ->
215+ return ()
216+
217+ Var Flex otherMaybeSuper _ ->
218+ if maybeSuper == otherMaybeSuper then
219+ merge context (Var Rigid maybeSuper maybeName)
220+ else
221+ rigidityError context maybeName
222+
223+ Var Rigid _ _ ->
224+ rigidityError context maybeName
225+
226+ Atom _ ->
227+ rigidityError context maybeName
228+
229+ Alias _ _ _ ->
230+ rigidityError context maybeName
231+
232+ Structure _ ->
233+ rigidityError context maybeName
234+
235+
236+-- UNIFY SUPER VARIABLES
237+
238+
239+unifySuper :: Context -> Super -> Content -> Unify ()
240+unifySuper context super otherContent =
241+ case otherContent of
242+ Structure term ->
243+ unifySuperStructure context super term
244+
245+ Atom name ->
246+ if atomMatchesSuper super name then
247+ merge context otherContent
248+ else
249+ mismatch context Nothing
250+
251+ Var Rigid Nothing maybeName ->
252+ rigidityError context maybeName
253+
254+ Var Rigid (Just otherSuper) maybeName ->
255+ if super == otherSuper then
256+ merge context otherContent
257+ else
258+ rigidityError context maybeName
259+
260+ Var Flex Nothing _ ->
261+ merge context (Var Flex (Just super) Nothing)
262+
263+ Var Flex (Just otherSuper) _ ->
264+ case combineSupers super otherSuper of
265+ Nothing ->
266+ mismatch context Nothing
267+
268+ Just newSuper ->
269+ merge context (Var Flex (Just newSuper) Nothing)
270+
271+ Alias _ _ realVar ->
272+ subUnify context (_first context) realVar
273+
274+ Error ->
275+ return ()
276+
277+
278+combineSupers :: Super -> Super -> Maybe Super
279+combineSupers firstSuper secondSuper =
280+ case (firstSuper, secondSuper) of
281+ (Number , Number ) -> Just Number
282+ (Comparable, Number ) -> Just Number
283+ (Number , Comparable) -> Just Number
284+
285+ (Comparable, Comparable) -> Just Comparable
286+ (Appendable, Appendable) -> Just Appendable
287+
288+ (Appendable, Comparable) -> Just CompAppend
289+ (Comparable, Appendable) -> Just CompAppend
290+
291+ (CompAppend, CompAppend) -> Just CompAppend
292+ (CompAppend, Comparable) -> Just CompAppend
293+ (Comparable, CompAppend) -> Just CompAppend
294+ (CompAppend, Appendable) -> Just CompAppend
295+ (Appendable, CompAppend) -> Just CompAppend
296+
297+ (_ , _ ) -> Nothing
298+
299+
300+isPrimitiveFrom :: [String] -> Var.Canonical -> Bool
301+isPrimitiveFrom prims var =
302+ any (\p -> Var.isPrim p var) prims
303+
304+
305+atomMatchesSuper :: Super -> Var.Canonical -> Bool
306+atomMatchesSuper super name =
307+ case super of
308+ Number ->
309+ isPrimitiveFrom ["Int", "Float"] name
310+
311+ Comparable ->
312+ isPrimitiveFrom ["Int", "Float", "Char", "String"] name
313+
314+ Appendable ->
315+ Var.isPrim "String" name || Var.isText name
316+
317+ CompAppend ->
318+ Var.isPrim "String" name
319+
320+
321+unifySuperStructure :: Context -> Super -> Term1 Variable -> Unify ()
322+unifySuperStructure context super term =
323+ do appStructure <- liftIO (collectApps (Structure term))
324+ case appStructure of
325+ Other ->
326+ mismatch context Nothing
327+
328+ List variable ->
329+ case super of
330+ Number ->
331+ mismatch context Nothing
332+
333+ Appendable ->
334+ merge context (Structure term)
335+
336+ Comparable ->
337+ do merge context (Structure term)
338+ unifyComparableRecursive (_orientation context) variable
339+
340+ CompAppend ->
341+ do merge context (Structure term)
342+ unifyComparableRecursive (_orientation context) variable
343+
344+ Tuple entries ->
345+ case super of
346+ Number ->
347+ mismatch context Nothing
348+
349+ Appendable ->
350+ mismatch context Nothing
351+
352+ Comparable ->
353+ if length entries > 6 then
354+ mismatch context (Just (Error.TooLongComparableTuple (length entries)))
355+
356+ else
357+ do merge context (Structure term)
358+ mapM_ (unifyComparableRecursive (_orientation context)) entries
359+
360+ CompAppend ->
361+ mismatch context Nothing
362+
363+
364+unifyComparableRecursive :: Orientation -> Variable -> Unify ()
365+unifyComparableRecursive orientation var =
366+ do compVar <-
367+ liftIO $
368+ do desc <- UF.descriptor var
369+ UF.fresh $
370+ Descriptor
371+ { _content = Var Flex (Just Comparable) Nothing
372+ , _rank = _rank desc
373+ , _mark = noMark
374+ , _copy = Nothing
375+ }
376+
377+ guardedUnify orientation compVar var
378+
379+
380+data AppStructure
381+ = List Variable
382+ | Tuple [Variable]
383+ | Other
384+
385+
386+collectApps :: Content -> IO AppStructure
387+collectApps content =
388+ collectAppsHelp [] content
389+
390+
391+collectAppsHelp :: [Variable] -> Content -> IO AppStructure
392+collectAppsHelp args content =
393+ case (content, args) of
394+ (Structure (App1 func arg), _) ->
395+ collectAppsHelp (args ++ [arg]) =<< getContent func
396+
397+ (Atom name, [arg]) | Var.isList name ->
398+ return (List arg)
399+
400+ (Atom name, _) | Var.isTuple name ->
401+ return (Tuple args)
402+
403+ _ ->
404+ return Other
405+
406+
407+getContent :: Variable -> IO Content
408+getContent variable =
409+ _content <$> UF.descriptor variable
410+
411+
412+
413+-- UNIFY ATOMS
414+
415+
416+unifyAtom :: Context -> Var.Canonical -> Content -> Unify ()
417+unifyAtom context name otherContent =
418+ case otherContent of
419+ Error ->
420+ return ()
421+
422+ Var Flex Nothing _ ->
423+ merge context (Atom name)
424+
425+ Var Flex (Just super) _ ->
426+ if atomMatchesSuper super name then
427+ merge context (Atom name)
428+
429+ else
430+ mismatch context Nothing
431+
432+ Var Rigid _ maybeName ->
433+ rigidityError context maybeName
434+
435+ Atom otherName ->
436+ if name == otherName then
437+ merge context otherContent
438+
439+ else
440+ mismatch context Nothing
441+
442+ Alias _ _ realVar ->
443+ subUnify context (_first context) realVar
444+
445+ Structure _ ->
446+ mismatch context Nothing
447+
448+
449+
450+-- UNIFY ALIASES
451+
452+unifyAlias :: Context -> Var.Canonical -> [(String, Variable)] -> Variable -> Content -> Unify ()
453+unifyAlias context name args realVar otherContent =
454+ case otherContent of
455+ Error ->
456+ return ()
457+
458+ Var Flex Nothing _ ->
459+ merge context (Alias name args realVar)
460+
461+ Var _ _ _ ->
462+ subUnify context realVar (_second context)
463+
464+ Atom _ ->
465+ subUnify context realVar (_second context)
466+
467+
468+ Alias otherName otherArgs otherRealVar ->
469+ if name == otherName then
470+ do merge context otherContent
471+ zipWithM_ (subUnify context) (map snd args) (map snd otherArgs)
472+
473+ else
474+ subUnify context realVar otherRealVar
475+
476+ Structure _ ->
477+ subUnify context realVar (_second context)
478+
479+
480+
481+-- UNIFY STRUCTURES
482+
483+
484+unifyStructure :: Context -> Term1 Variable -> Content -> Unify ()
485+unifyStructure context term otherContent =
486+ case otherContent of
487+ Error ->
488+ return ()
489+
490+ Var Flex Nothing _ ->
491+ merge context (Structure term)
492+
493+ Var Flex (Just super) _ ->
494+ unifySuper (reorient context) super (Structure term)
495+
496+ Var Rigid _ maybeName ->
497+ rigidityError context maybeName
498+
499+ Atom _ ->
500+ mismatch context Nothing
501+
502+ Alias _ _ realVar ->
503+ subUnify context (_first context) realVar
504+
505+ Structure otherTerm ->
506+ case (term, otherTerm) of
507+ (App1 func arg, App1 otherFunc otherArg) ->
508+ do merge context otherContent
509+ subUnify context func otherFunc
510+ subUnify context arg otherArg
511+
512+ (Fun1 arg result, Fun1 otherArg otherResult) ->
513+ do merge context otherContent
514+ subUnify context arg otherArg
515+ subUnify context result otherResult
516+
517+ (EmptyRecord1, EmptyRecord1) ->
518+ merge context otherContent
519+
520+ (Record1 fields ext, EmptyRecord1) | Map.null fields ->
521+ subUnify context ext (_second context)
522+
523+ (EmptyRecord1, Record1 fields ext) | Map.null fields ->
524+ subUnify context (_first context) ext
525+
526+ (Record1 fields extension, Record1 otherFields otherExtension) ->
527+ do firstStructure <- gatherFields context fields extension
528+ secondStructure <- gatherFields context otherFields otherExtension
529+ unifyRecord context firstStructure secondStructure
530+
531+ _ ->
532+ mismatch context Nothing
533+
534+
535+
536+-- UNIFY RECORDS
537+
538+
539+unifyRecord :: Context -> RecordStructure -> RecordStructure -> Unify ()
540+unifyRecord context firstStructure secondStructure =
541+ do let (RecordStructure expFields expVar expStruct) = firstStructure
542+ let (RecordStructure actFields actVar actStruct) = secondStructure
543+
544+ -- call after unifying extension, make sure record shape matches before
545+ -- looking into whether the particular field types match.
546+ let unifySharedFields otherFields ext =
547+ do let sharedFields = Map.intersectionWith (,) expFields actFields
548+ _ <- traverse (uncurry (subUnify context)) sharedFields
549+ let allFields = Map.union (Map.map fst sharedFields) otherFields
550+ merge context (Structure (Record1 allFields ext))
551+
552+ let uniqueExpFields = Map.difference expFields actFields
553+ let uniqueActFields = Map.difference actFields expFields
554+
555+ case (expStruct, actStruct) of
556+ (Empty, Empty) ->
557+ if Map.null uniqueExpFields && Map.null uniqueActFields then
558+ do mergeHelp expVar actVar (Structure EmptyRecord1)
559+ unifySharedFields Map.empty expVar
560+
561+ else
562+ mismatch context (Just (Error.MessyFields (Map.keys uniqueExpFields) (Map.keys uniqueActFields)))
563+
564+ (Empty, Extension) ->
565+ case (Map.null uniqueExpFields, Map.null uniqueActFields) of
566+ (_, False) ->
567+ mismatch context (Just (Error.ActualFields (Map.keys uniqueActFields)))
568+
569+ (True, True) ->
570+ do subUnify context expVar actVar
571+ unifySharedFields Map.empty expVar
336572
337573 (False, True) ->
338− do subRecord <- freshRecord uniqueFields1 var1
339− unifyHelp subRecord var2
574+ do subRecord <- fresh context (Structure (Record1 uniqueExpFields expVar))
575+ subUnify context subRecord actVar
576+ unifySharedFields Map.empty subRecord
340577
341− (False, False) ->
342− do record1' <- freshRecord uniqueFields1 =<< fresh Nothing
343− record2' <- freshRecord uniqueFields2 =<< fresh Nothing
344− unifyHelp record1' var2
345− unifyHelp var1 record2'
346−
347−
348−unifyOverlappingFields
349− :: Map.Map String [Variable]
350− -> Map.Map String [Variable]
351− -> Unify ()
352−unifyOverlappingFields fields1 fields2 =
353− Map.intersectionWith (zipWith unifyHelp) fields1 fields2
354− |> Map.elems
355− |> concat
356− |> sequence_
357−
358−
359−diffFields :: Map.Map String [a] -> Map.Map String [a] -> Map.Map String [a]
360−diffFields fields1 fields2 =
361− let eat (_:xs) (_:ys) = eat xs ys
362− eat xs _ = xs
363− in
364− Map.union (Map.intersectionWith eat fields1 fields2) fields1
365− |> Map.filter (not . null)
578+ (Extension, Empty) ->
579+ case (Map.null uniqueExpFields, Map.null uniqueActFields) of
580+ (False, _) ->
581+ mismatch context (Just (Error.ExpectedFields (Map.keys uniqueExpFields)))
366582
583+ (True, True) ->
584+ do subUnify context expVar actVar
585+ unifySharedFields Map.empty expVar
367586
368−data ExpandedRecord = ExpandedRecord
369− { _fields :: Map.Map String [Variable]
370− , _extension :: Extension
371− }
587+ (True, False) ->
588+ do subRecord <- fresh context (Structure (Record1 uniqueActFields actVar))
589+ subUnify context expVar subRecord
590+ unifySharedFields Map.empty subRecord
372591
373−data Extension = Empty Variable | Extension Variable
592+ (Extension, Extension) ->
593+ case (Map.null uniqueExpFields, Map.null uniqueActFields) of
594+ (True, True) ->
595+ do subUnify context expVar actVar
596+ unifySharedFields Map.empty expVar
374597
598+ (True, False) ->
599+ do subRecord <- fresh context (Structure (Record1 uniqueActFields actVar))
600+ subUnify context expVar subRecord
601+ unifySharedFields Map.empty subRecord
375602
376−gatherFields :: Variable -> IO ExpandedRecord
377−gatherFields var =
378− do desc <- UF.descriptor var
379− case structure desc of
380− (Just (Record1 fields ext)) ->
381− do (ExpandedRecord deeperFields rootExt) <- gatherFields ext
382− return (ExpandedRecord (Map.unionWith (++) fields deeperFields) rootExt)
603+ (False, True) ->
604+ do subRecord <- fresh context (Structure (Record1 uniqueExpFields expVar))
605+ subUnify context subRecord actVar
606+ unifySharedFields Map.empty subRecord
383607
384− (Just EmptyRecord1) ->
385− return (ExpandedRecord Map.empty (Empty var))
608+ (False, False) ->
609+ do let subFields = Map.union uniqueExpFields uniqueActFields
610+ subExt <- fresh context (Var Flex Nothing Nothing)
611+ expRecord <- fresh context (Structure (Record1 uniqueActFields subExt))
612+ actRecord <- fresh context (Structure (Record1 uniqueExpFields subExt))
613+ subUnify context expVar expRecord
614+ subUnify context actRecord actVar
615+ unifySharedFields subFields subExt
386616
387− _ ->
388− return (ExpandedRecord Map.empty (Extension var))
389617
390618
391−-- assumes that one of the dicts has stuff in it
392−fieldMismatchError :: Map.Map String a -> String
393−fieldMismatchError missingFields =
394− case Map.keys missingFields of
395− [] ->
396− ""
619+-- GATHER RECORD STRUCTURE
397620
398− [key] ->
399− "Looks like a record is missing the field `" ++ key ++ "`"
400621
401− keys ->
402− "Looks like a record is missing fields "
403− ++ List.intercalate ", " (init keys) ++ ", and " ++ last keys
622+data RecordStructure = RecordStructure
623+ { _fields :: Map.Map String Variable
624+ , _extVar :: Variable
625+ , _extStruct :: ExtensionStructure
626+ }
404627
405628
629+data ExtensionStructure
630+ = Empty
631+ | Extension
406632
407−pickAlias :: Descriptor -> Descriptor -> Alias Variable
408−pickAlias desc1 desc2 =
409− alias desc1 <|> alias desc2
410633
634+gatherFields :: Context -> Map.Map String Variable -> Variable -> Unify RecordStructure
635+gatherFields context fields variable =
636+ do desc <- liftIO (UF.descriptor variable)
637+ case _content desc of
638+ Structure (Record1 subFields subExt) ->
639+ gatherFields context (Map.union fields subFields) subExt
411640
412−pickRank :: Descriptor -> Descriptor -> Int
413−pickRank desc1 desc2 =
414− min (rank desc1) (rank desc2)
641+ Structure (EmptyRecord1) ->
642+ return (RecordStructure fields variable Empty)
415643
644+ Structure (App1 _ _) ->
645+ mismatch context (Just Error.NotRecord)
416646
417−pickFlex :: Descriptor -> Descriptor -> Flex
418−pickFlex desc1 desc2 =
419− case (flex desc1, flex desc2) of
420− ( f , Flexible ) -> f
421− ( Flexible , f ) -> f
422− ( Is Number , Is _ ) -> Is Number
423− ( Is _ , Is Number ) -> Is Number
424− ( Is super , Is _ ) -> Is super
425− ( _ , _ ) -> Flexible
647+ Structure (Fun1 _ _) ->
648+ mismatch context (Just Error.NotRecord)
426649
650+ Atom _ ->
651+ mismatch context (Just Error.NotRecord)
427652
428−pickName :: Descriptor -> Descriptor -> Maybe Var.Canonical
429−pickName desc1 desc2 =
430− case (name desc1, name desc2) of
431− (Nothing, Nothing) ->
432− Nothing
653+ Var _ Nothing _ ->
654+ return (RecordStructure fields variable Extension)
433655
434− (Just name1, Nothing) ->
435− Just name1
656+ Var _ (Just _) _ ->
657+ mismatch context (Just Error.NotRecord)
436658
437− (Nothing, Just name2) ->
438− Just name2
659+ -- TODO may be dropping useful alias info here
660+ Alias _ _ var ->
661+ gatherFields context fields var
439662
440− (Just name1, Just name2) ->
441− case (flex desc1, flex desc2) of
442− ( _ , Flexible ) -> Just name1
443− ( Flexible , _ ) -> Just name2
444− ( Is Number , Is _ ) -> Just name1
445− ( Is _ , Is Number ) -> Just name2
446− ( Is _ , Is _ ) -> Just name1
447− ( _ , _ ) -> Nothing
663+ Error ->
664+ return (RecordStructure fields variable Extension)
448665