1{-# OPTIONS_GHC -Wall #-}
2module Type.Constrain.Expression
5 , constrainRecursiveDefs
10import qualified Data.Map.Strict as Map
12import qualified AST.Canonical as Can
13import qualified AST.Module.Name as ModuleName
14import qualified AST.Utils.Shader as Shader
15import qualified Data.Index as Index
16import qualified Elm.Name as N
17import qualified Reporting.Annotation as A
18import qualified Reporting.Region as R
19import Type.Constraint as C
20import qualified Type.Constrain.Pattern as Pattern
21import qualified Type.Instantiate as Instantiate
22import Type.Type as Type hiding (Descriptor(..))
29-- As we step past type annotations, the free type variables are added to
30-- the "rigid type variables" dict. Allowing sharing of rigid variables
31-- between nested type annotations.
33-- So if you have a top-level type annotation like (func : a -> b) the RTV
34-- dictionary will hold variables for `a` and `b`
40constrain :: RTV -> Can.Expr -> Expected Type -> IO Constraint
41constrain rtv (A.At region expression) expected =
44 return (CLocal region name expected)
46 Can.VarTopLevel _ name ->
47 return (CLocal region name expected)
52 Can.VarForeign _ name annotation ->
53 return $ CForeign region name annotation expected
55 Can.VarCtor _ _ name _ annotation ->
56 return $ CForeign region name annotation expected
58 Can.VarDebug _ name annotation ->
59 return $ CForeign region name annotation expected
61 Can.VarOperator op _ _ annotation ->
62 return $ CForeign region op annotation expected
65 return $ CEqual region String Type.string expected
68 return $ CEqual region Char Type.char expected
71 do var <- mkFlexNumber
72 return $ exists [var] $ CEqual region C.Number (VarN var) expected
75 return $ CEqual region Float Type.float expected
78 constrainList rtv region elements expected
81 do numberVar <- mkFlexNumber
82 let numberType = VarN numberVar
83 numberCon <- constrain rtv expr (FromContext region Negate numberType)
84 let negateCon = CEqual region C.Number numberType expected
85 return $ exists [numberVar] $ CAnd [ numberCon, negateCon ]
87 Can.Binop op _ _ annotation leftExpr rightExpr ->
88 constrainBinop rtv region op annotation leftExpr rightExpr expected
90 Can.Lambda args body ->
91 constrainLambda rtv region args body expected
94 constrainCall rtv region func args expected
96 Can.If branches finally ->
97 constrainIf rtv region branches finally expected
99 Can.Case expr branches ->
100 constrainCase rtv region expr branches expected
104 =<< constrain rtv body expected
106 Can.LetRec defs body ->
107 constrainRecursiveDefs rtv defs
108 =<< constrain rtv body expected
110 Can.LetDestruct pattern expr body ->
111 constrainDestruct rtv region pattern expr
112 =<< constrain rtv body expected
114 Can.Accessor field ->
115 do extVar <- mkFlexVar
116 fieldVar <- mkFlexVar
117 let extType = VarN extVar
118 let fieldType = VarN fieldVar
119 let recordType = RecordN (Map.singleton field fieldType) extType
120 return $ exists [ fieldVar, extVar ] $
121 CEqual region (Accessor field) (FunN recordType fieldType) expected
123 Can.Access expr field ->
124 do extVar <- mkFlexVar
125 fieldVar <- mkFlexVar
126 let extType = VarN extVar
127 let fieldType = VarN fieldVar
128 let recordType = RecordN (Map.singleton field fieldType) extType
131 constrain rtv expr (FromContext region (RecordAccess field) recordType)
133 return $ exists [ fieldVar, extVar ] $
136 , CEqual region (Access field) fieldType expected
139 Can.Update expr fields ->
140 constrainUpdate rtv region expr fields expected
143 constrainRecord rtv region fields expected
146 return $ CEqual region Unit UnitN expected
148 Can.Tuple a b maybeC ->
149 constrainTuple rtv region a b maybeC expected
151 Can.Shader _uid _src glType ->
152 constrainShader region glType expected
159constrainLambda :: RTV -> R.Region -> [Can.Pattern] -> Can.Expr -> Expected Type -> IO Constraint
160constrainLambda rtv region args body expected =
161 do (Args vars tipe resultType (Pattern.State headers pvars revCons)) <-
165 constrain rtv body (NoExpectation resultType)
167 return $ exists vars $
173 , _headerCon = CAnd (reverse revCons)
176 , CEqual region Lambda tipe expected
184constrainCall :: RTV -> R.Region -> Can.Expr -> [Can.Expr] -> Expected Type -> IO Constraint
185constrainCall rtv region func args expected =
186 do let maybeName = getName func
189 resultVar <- mkFlexVar
190 let funcType = VarN funcVar
191 let resultType = VarN resultVar
193 funcCon <- constrain rtv func (NoExpectation funcType)
195 (argVars, argTypes, argCons) <-
196 unzip3 <$> Index.indexedTraverse (constrainArg rtv region maybeName) args
198 let arityType = foldr FunN resultType argTypes
199 let resultCon = CEqual region (CallResult maybeName) resultType expected
201 return $ exists (funcVar:resultVar:argVars) $
207 , _eq = CAnd [ CAnd argCons, resultCon ]
208 , _neq = constrainCallBackup rtv region maybeName func args
213constrainArg :: RTV -> R.Region -> MaybeName -> Index.ZeroBased -> Can.Expr -> IO (Variable, Type, Constraint)
214constrainArg rtv region maybeName index arg =
215 do argVar <- mkFlexVar
216 let argType = VarN argVar
217 argCon <- constrain rtv arg (FromContext region (CallArg maybeName index) argType)
218 return (argVar, argType, argCon)
221constrainCallBackup :: RTV -> R.Region -> MaybeName -> Can.Expr -> [Can.Expr] -> IO Constraint
222constrainCallBackup rtv region maybeName func args =
223 do (argVars, argTypes, argCons) <-
224 unzip3 <$> Index.indexedTraverse (constrainArg rtv region maybeName) args
226 resultVar <- mkFlexVar
227 let resultType = VarN resultVar
228 let arityType = foldr FunN resultType argTypes
230 funcCon <- constrain rtv func (FromContext region (TooManyArgs maybeName (length args)) arityType)
232 return $ exists (resultVar:argVars) $ CAnd [ CAnd argCons, funcCon ]
235getName :: Can.Expr -> MaybeName
236getName (A.At _ expr) =
241 Can.VarTopLevel _ name ->
244 Can.VarForeign _ name _ ->
247 Can.VarCtor _ _ name _ _ ->
250 Can.VarOperator op _ _ _ ->
253 Can.VarKernel _ name ->
264constrainBinop :: RTV -> R.Region -> N.Name -> Can.Annotation -> Can.Expr -> Can.Expr -> Expected Type -> IO Constraint
265constrainBinop rtv region op annotation leftExpr rightExpr expected =
266 do leftVar <- mkFlexVar
267 rightVar <- mkFlexVar
268 answerVar <- mkFlexVar
269 let leftType = VarN leftVar
270 let rightType = VarN rightVar
271 let answerType = VarN answerVar
272 let binopType = leftType ==> rightType ==> answerType
274 let opCon = CForeign region op annotation (NoExpectation binopType)
276 leftCon <- constrain rtv leftExpr (FromContext region (OpLeft op) leftType)
277 rightCon <- constrain rtv rightExpr (FromContext region (OpRight op) rightType)
279 return $ exists [ leftVar, rightVar, answerVar ] $
284 , CEqual region (CallResult (OpName op)) answerType expected
292constrainList :: RTV -> R.Region -> [Can.Expr] -> Expected Type -> IO Constraint
293constrainList rtv region entries expected =
294 do entryVar <- mkFlexVar
295 let entryType = VarN entryVar
296 let listType = AppN ModuleName.list N.list [entryType]
299 Index.indexedTraverse (constrainListEntry rtv region entryType) entries
301 return $ exists [entryVar] $
304 , CEqual region List listType expected
308constrainListEntry :: RTV -> R.Region -> Type -> Index.ZeroBased -> Can.Expr -> IO Constraint
309constrainListEntry rtv region tipe index expr =
310 constrain rtv expr (FromContext region (ListEntry index) tipe)
314-- CONSTRAIN IF EXPRESSIONS
317constrainIf :: RTV -> R.Region -> [(Can.Expr, Can.Expr)] -> Can.Expr -> Expected Type -> IO Constraint
318constrainIf rtv region branches final expected =
319 do let boolExpect = FromContext region IfCondition Type.bool
320 let (conditions, exprs) = foldr (\(c,e) (cs,es) -> (c:cs,e:es)) ([],[final]) branches
323 traverse (\c -> constrain rtv c boolExpect) conditions
326 FromAnnotation name arity _ tipe ->
327 do branchCons <- Index.indexedForA exprs $ \index expr ->
328 constrain rtv expr (FromAnnotation name arity (TypedIfBranch index) tipe)
336 do branchVar <- mkFlexVar
337 let branchType = VarN branchVar
339 branchCons <- Index.indexedForA exprs $ \index expr ->
340 constrain rtv expr (FromContext region (IfBranch index) branchType)
342 return $ exists [branchVar] $
346 , CEqual region If branchType expected
351-- CONSTRAIN CASE EXPRESSIONS
354constrainCase :: RTV -> R.Region -> Can.Expr -> [Can.CaseBranch] -> Expected Type -> IO Constraint
355constrainCase rtv region expr branches expected =
356 do ptrnVar <- mkFlexVar
357 let ptrnType = VarN ptrnVar
358 exprCon <- constrain rtv expr (NoExpectation ptrnType)
361 FromAnnotation name arity _ tipe ->
362 do branchCons <- Index.indexedForA branches $ \index branch ->
363 constrainCaseBranch rtv branch
364 (PFromContext region (PCaseMatch index) ptrnType)
365 (FromAnnotation name arity (TypedCaseBranch index) tipe)
367 return $ exists [ptrnVar] $ CAnd (exprCon:branchCons)
370 do branchVar <- mkFlexVar
371 let branchType = VarN branchVar
373 branchCons <- Index.indexedForA branches $ \index branch ->
374 constrainCaseBranch rtv branch
375 (PFromContext region (PCaseMatch index) ptrnType)
376 (FromContext region (CaseBranch index) branchType)
378 return $ exists [ptrnVar,branchVar] $
382 , CEqual region Case branchType expected
386constrainCaseBranch :: RTV -> Can.CaseBranch -> PExpected Type -> Expected Type -> IO Constraint
387constrainCaseBranch rtv (Can.CaseBranch pattern expr) pExpect bExpect =
388 do (Pattern.State headers pvars revCons) <-
389 Pattern.add pattern pExpect Pattern.emptyState
391 CLet [] pvars headers (CAnd (reverse revCons))
392 <$> constrain rtv expr bExpect
399constrainRecord :: RTV -> R.Region -> Map.Map N.Name Can.Expr -> Expected Type -> IO Constraint
400constrainRecord rtv region fields expected =
401 do dict <- traverse (constrainField rtv) fields
403 let getType (_, t, _) = t
404 let recordType = RecordN (Map.map getType dict) EmptyRecordN
405 let recordCon = CEqual region Record recordType expected
407 let vars = Map.foldr (\(v,_,_) vs -> v:vs) [] dict
408 let cons = Map.foldr (\(_,_,c) cs -> c:cs) [recordCon] dict
410 return $ exists vars (CAnd cons)
413constrainField :: RTV -> Can.Expr -> IO (Variable, Type, Constraint)
414constrainField rtv expr =
417 con <- constrain rtv expr (NoExpectation tipe)
418 return (var, tipe, con)
422-- CONSTRAIN RECORD UPDATE
425constrainUpdate :: RTV -> R.Region -> Can.Expr -> Map.Map N.Name Can.Expr -> Expected Type -> IO Constraint
426constrainUpdate rtv region expr fields expected =
427 do sharedVar <- mkFlexVar
428 let sharedType = VarN sharedVar
430 oldVars <- traverse (\_ -> mkFlexVar) fields
431 let oldTypes = Map.map VarN oldVars
432 let oldRecordType = RecordN oldTypes sharedType
433 oldCon <- constrain rtv expr (FromContext region RecordUpdate oldRecordType)
435 newDict <- traverse (constrainField rtv) fields
437 let getType (_, t, _) = t
438 let newRecordType = RecordN (Map.map getType newDict) sharedType
439 let newCon = CEqual region Record newRecordType expected
441 let vars = Map.foldr (\(v,_,_) vs -> v:vs) (sharedVar : Map.elems oldVars) newDict
442 let cons = Map.foldr (\(_,_,c) cs -> c:cs) [newCon] newDict
444 return $ exists vars (CAnd (oldCon:cons))
451constrainTuple :: RTV -> R.Region -> Can.Expr -> Can.Expr -> Maybe Can.Expr -> Expected Type -> IO Constraint
452constrainTuple rtv region a b maybeC expected =
455 let aType = VarN aVar
456 let bType = VarN bVar
458 aCon <- constrain rtv a (NoExpectation aType)
459 bCon <- constrain rtv b (NoExpectation bType)
463 do let tupleType = TupleN aType bType Nothing
464 let tupleCon = CEqual region Tuple tupleType expected
465 return $ exists [ aVar, bVar ] $ CAnd [ aCon, bCon, tupleCon ]
469 let cType = VarN cVar
471 cCon <- constrain rtv c (NoExpectation cType)
473 let tupleType = TupleN aType bType (Just cType)
474 let tupleCon = CEqual region Tuple tupleType expected
476 return $ exists [ aVar, bVar, cVar ] $ CAnd [ aCon, bCon, cCon, tupleCon ]
483constrainShader :: R.Region -> Shader.Shader -> Expected Type -> IO Constraint
484constrainShader region (Shader.Shader attributes uniforms varyings) expected =
485 do attrVar <- mkFlexVar
487 let attrType = VarN attrVar
488 let unifType = VarN unifVar
491 AppN ModuleName.webgl N.shader
492 [ toShaderRecord attributes attrType
493 , toShaderRecord uniforms unifType
494 , toShaderRecord varyings EmptyRecordN
497 return $ exists [ attrVar, unifVar ] $
498 CEqual region Shader shaderType expected
501toShaderRecord :: Map.Map N.Name Shader.Type -> Type -> Type
502toShaderRecord types baseRecType =
503 if Map.null types then
506 RecordN (Map.map glToType types) baseRecType
509glToType :: Shader.Type -> Type
512 Shader.V2 -> Type.vec2
513 Shader.V3 -> Type.vec3
514 Shader.V4 -> Type.vec4
515 Shader.M4 -> Type.mat4
516 Shader.Int -> Type.int
517 Shader.Float -> Type.float
518 Shader.Texture -> Type.texture
522-- CONSTRAIN DESTRUCTURES
525constrainDestruct :: RTV -> R.Region -> Can.Pattern -> Can.Expr -> Constraint -> IO Constraint
526constrainDestruct rtv region pattern expr bodyCon =
527 do patternVar <- mkFlexVar
528 let patternType = VarN patternVar
530 (Pattern.State headers pvars revCons) <-
531 Pattern.add pattern (PNoExpectation patternType) Pattern.emptyState
534 constrain rtv expr (FromContext region Destructure patternType)
536 return $ CLet [] (patternVar:pvars) headers (CAnd (reverse (exprCon:revCons))) bodyCon
543constrainDef :: RTV -> Can.Def -> Constraint -> IO Constraint
544constrainDef rtv def bodyCon =
546 Can.Def (A.At region name) args expr ->
547 do (Args vars tipe resultType (Pattern.State headers pvars revCons)) <-
551 constrain rtv expr (NoExpectation resultType)
557 , _header = Map.singleton name (A.At region tipe)
563 , _headerCon = CAnd (reverse revCons)
569 Can.TypedDef (A.At region name) freeVars typedArgs expr srcResultType ->
570 do let newNames = Map.difference freeVars rtv
571 newRigids <- Map.traverseWithKey (\n _ -> nameToRigid n) newNames
572 let newRtv = Map.union rtv (Map.map VarN newRigids)
574 (TypedArgs tipe resultType (Pattern.State headers pvars revCons)) <-
575 constrainTypedArgs newRtv name typedArgs srcResultType
577 let expected = FromAnnotation name (length typedArgs) TypedBody resultType
579 constrain newRtv expr expected
583 { _rigidVars = Map.elems newRigids
585 , _header = Map.singleton name (A.At region tipe)
591 , _headerCon = CAnd (reverse revCons)
599-- CONSTRAIN RECURSIVE DEFS
604 { _vars :: [Variable]
605 , _cons :: [Constraint]
606 , _headers :: Map.Map N.Name (A.Located Type)
610{-# NOINLINE emptyInfo #-}
616constrainRecursiveDefs :: RTV -> [Can.Def] -> Constraint -> IO Constraint
617constrainRecursiveDefs rtv defs bodyCon =
618 recDefsHelp rtv defs bodyCon emptyInfo emptyInfo
621recDefsHelp :: RTV -> [Can.Def] -> Constraint -> Info -> Info -> IO Constraint
622recDefsHelp rtv defs bodyCon rigidInfo flexInfo =
625 do let (Info rigidVars rigidCons rigidHeaders) = rigidInfo
626 let (Info flexVars flexCons flexHeaders ) = flexInfo
628 CLet rigidVars [] rigidHeaders CTrue $
629 CLet [] flexVars flexHeaders (CLet [] [] flexHeaders CTrue (CAnd flexCons)) $
630 CAnd [ CAnd rigidCons, bodyCon ]
634 Can.Def (A.At region name) args expr ->
635 do let (Info flexVars flexCons flexHeaders) = flexInfo
637 (Args newFlexVars tipe resultType (Pattern.State headers pvars revCons)) <-
638 argsHelp args (Pattern.State Map.empty flexVars [])
641 constrain rtv expr (NoExpectation resultType)
648 , _headerCon = CAnd (reverse revCons)
652 recDefsHelp rtv otherDefs bodyCon rigidInfo $
654 { _vars = newFlexVars
655 , _cons = defCon : flexCons
656 , _headers = Map.insert name (A.At region tipe) flexHeaders
659 Can.TypedDef (A.At region name) freeVars typedArgs expr srcResultType ->
660 do let newNames = Map.difference freeVars rtv
661 newRigids <- Map.traverseWithKey (\n _ -> nameToRigid n) newNames
662 let newRtv = Map.union rtv (Map.map VarN newRigids)
664 (TypedArgs tipe resultType (Pattern.State headers pvars revCons)) <-
665 constrainTypedArgs newRtv name typedArgs srcResultType
668 constrain newRtv expr $
669 FromAnnotation name (length typedArgs) TypedBody resultType
676 , _headerCon = CAnd (reverse revCons)
680 let (Info rigidVars rigidCons rigidHeaders) = rigidInfo
681 recDefsHelp rtv otherDefs bodyCon
683 { _vars = Map.foldr (:) rigidVars newRigids
684 , _cons = defCon : rigidCons
685 , _headers = Map.insert name (A.At region tipe) rigidHeaders
697 { _a_vars :: [Variable]
700 , _a_state :: Pattern.State
704constrainArgs :: [Can.Pattern] -> IO Args
706 argsHelp args Pattern.emptyState
709argsHelp :: [Can.Pattern] -> Pattern.State -> IO Args
713 do resultVar <- mkFlexVar
714 let resultType = VarN resultVar
715 return $ Args [resultVar] resultType resultType state
717 pattern : otherArgs ->
718 do argVar <- mkFlexVar
719 let argType = VarN argVar
721 (Args vars tipe result newState) <-
722 argsHelp otherArgs =<<
723 Pattern.add pattern (PNoExpectation argType) state
725 return (Args (argVar:vars) (FunN argType tipe) result newState)
729-- CONSTRAIN TYPED ARGS
736 , _t_state :: Pattern.State
740constrainTypedArgs :: Map.Map N.Name Type -> N.Name -> [(Can.Pattern, Can.Type)] -> Can.Type -> IO TypedArgs
741constrainTypedArgs rtv name args srcResultType =
742 do resultType <- Instantiate.fromSrcType rtv srcResultType
743 typedArgsHelp rtv name Index.first args resultType Pattern.emptyState
746typedArgsHelp :: Map.Map N.Name Type -> N.Name -> Index.ZeroBased -> [(Can.Pattern, Can.Type)] -> Type -> Pattern.State -> IO TypedArgs
747typedArgsHelp rtv name index args resultType state =
750 return $ TypedArgs resultType resultType state
752 (pattern@(A.At region _), srcType) : otherArgs ->
753 do argType <- Instantiate.fromSrcType rtv srcType
754 let expected = PFromContext region (PTypedArg name index) argType
756 (TypedArgs tipe result newState) <-
757 typedArgsHelp rtv name (Index.next index) otherArgs resultType =<<
758 Pattern.add pattern expected state
760 return (TypedArgs (FunN argType tipe) result newState)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list