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.Error.Type as E
19import Reporting.Error.Type (Expected(..), Context(..), SubContext(..), MaybeName(..), Category(..), PExpected(..), PContext(..))
20import qualified Reporting.Region as R
21import qualified Type.Constrain.Pattern as Pattern
22import qualified Type.Instantiate as Instantiate
23import Type.Type as Type hiding (Descriptor(..))
30-- As we step past type annotations, the free type variables are added to
31-- the "rigid type variables" dict. Allowing sharing of rigid variables
32-- between nested type annotations.
34-- So if you have a top-level type annotation like (func : a -> b) the RTV
35-- dictionary will hold variables for `a` and `b`
41constrain :: RTV -> Can.Expr -> Expected Type -> IO Constraint
42constrain rtv (A.At region expression) expected =
45 return (CLocal region name expected)
47 Can.VarTopLevel _ name ->
48 return (CLocal region name expected)
53 Can.VarForeign _ name annotation ->
54 return $ CForeign region name annotation expected
56 Can.VarCtor _ _ name _ annotation ->
57 return $ CForeign region name annotation expected
59 Can.VarDebug _ name annotation ->
60 return $ CForeign region name annotation expected
62 Can.VarOperator op _ _ annotation ->
63 return $ CForeign region op annotation expected
66 return $ CEqual region String Type.string expected
69 return $ CEqual region Char Type.char expected
72 do var <- mkFlexNumber
73 return $ exists [var] $ CEqual region E.Number (VarN var) expected
76 return $ CEqual region Float Type.float expected
79 constrainList rtv region elements expected
82 do numberVar <- mkFlexNumber
83 let numberType = VarN numberVar
84 numberCon <- constrain rtv expr (FromContext region Negate numberType)
85 let negateCon = CEqual region E.Number numberType expected
86 return $ exists [numberVar] $ CAnd [ numberCon, negateCon ]
88 Can.Binop op _ _ annotation leftExpr rightExpr ->
89 constrainBinop rtv region op annotation leftExpr rightExpr expected
91 Can.Lambda args body ->
92 constrainLambda rtv region args body expected
95 constrainCall rtv region func args expected
97 Can.If branches finally ->
98 constrainIf rtv region branches finally expected
100 Can.Case expr branches ->
101 constrainCase rtv region expr branches expected
105 =<< constrain rtv body expected
107 Can.LetRec defs body ->
108 constrainRecursiveDefs rtv defs
109 =<< constrain rtv body expected
111 Can.LetDestruct pattern expr body ->
112 constrainDestruct rtv region pattern expr
113 =<< constrain rtv body expected
115 Can.Accessor field ->
116 do extVar <- mkFlexVar
117 fieldVar <- mkFlexVar
118 let extType = VarN extVar
119 let fieldType = VarN fieldVar
120 let recordType = RecordN (Map.singleton field fieldType) extType
121 return $ exists [ fieldVar, extVar ] $
122 CEqual region (Accessor field) (FunN recordType fieldType) expected
124 Can.Access expr field ->
125 do extVar <- mkFlexVar
126 fieldVar <- mkFlexVar
127 let extType = VarN extVar
128 let fieldType = VarN fieldVar
129 let recordType = RecordN (Map.singleton field fieldType) extType
132 constrain rtv expr (FromContext region (RecordAccess field) recordType)
134 return $ exists [ fieldVar, extVar ] $
137 , CEqual region (Access field) fieldType expected
140 Can.Update expr fields ->
141 constrainUpdate rtv region expr fields expected
144 constrainRecord rtv region fields expected
147 return $ CEqual region Unit UnitN expected
149 Can.Tuple a b maybeC ->
150 constrainTuple rtv region a b maybeC expected
152 Can.Shader _uid _src glType ->
153 constrainShader region glType expected
160constrainLambda :: RTV -> R.Region -> [Can.Pattern] -> Can.Expr -> Expected Type -> IO Constraint
161constrainLambda rtv region args body expected =
162 do (Args vars tipe resultType (Pattern.State headers pvars revCons)) <-
166 constrain rtv body (NoExpectation resultType)
168 return $ exists vars $
174 , _headerCon = CAnd (reverse revCons)
177 , CEqual region Lambda tipe expected
185constrainCall :: RTV -> R.Region -> Can.Expr -> [Can.Expr] -> Expected Type -> IO Constraint
186constrainCall rtv region func args expected =
187 do let maybeName = getName func
190 resultVar <- mkFlexVar
191 let funcType = VarN funcVar
192 let resultType = VarN resultVar
194 funcCon <- constrain rtv func (NoExpectation funcType)
196 (argVars, argTypes, argCons) <-
197 unzip3 <$> Index.indexedTraverse (constrainArg rtv region maybeName) args
199 let arityType = foldr FunN resultType argTypes
200 let resultCon = CEqual region (CallResult maybeName) resultType expected
202 return $ exists (funcVar:resultVar:argVars) $
208 , _eq = CAnd [ CAnd argCons, resultCon ]
209 , _neq = constrainCallBackup rtv region maybeName func args
214constrainArg :: RTV -> R.Region -> MaybeName -> Index.ZeroBased -> Can.Expr -> IO (Variable, Type, Constraint)
215constrainArg rtv region maybeName index arg =
216 do argVar <- mkFlexVar
217 let argType = VarN argVar
218 argCon <- constrain rtv arg (FromContext region (CallArg maybeName index) argType)
219 return (argVar, argType, argCon)
222constrainCallBackup :: RTV -> R.Region -> MaybeName -> Can.Expr -> [Can.Expr] -> IO Constraint
223constrainCallBackup rtv region maybeName func args =
224 do (argVars, argTypes, argCons) <-
225 unzip3 <$> Index.indexedTraverse (constrainArg rtv region maybeName) args
227 resultVar <- mkFlexVar
228 let resultType = VarN resultVar
229 let arityType = foldr FunN resultType argTypes
231 funcCon <- constrain rtv func (FromContext region (TooManyArgs maybeName (length args)) arityType)
233 return $ exists (resultVar:argVars) $ CAnd [ CAnd argCons, funcCon ]
236getName :: Can.Expr -> MaybeName
237getName (A.At _ expr) =
242 Can.VarTopLevel _ name ->
245 Can.VarForeign _ name _ ->
248 Can.VarCtor _ _ name _ _ ->
251 Can.VarOperator op _ _ _ ->
254 Can.VarKernel _ name ->
265constrainBinop :: RTV -> R.Region -> N.Name -> Can.Annotation -> Can.Expr -> Can.Expr -> Expected Type -> IO Constraint
266constrainBinop rtv region op annotation leftExpr rightExpr expected =
267 do leftVar <- mkFlexVar
268 rightVar <- mkFlexVar
269 answerVar <- mkFlexVar
270 let leftType = VarN leftVar
271 let rightType = VarN rightVar
272 let answerType = VarN answerVar
273 let binopType = leftType ==> rightType ==> answerType
275 let opCon = CForeign region op annotation (NoExpectation binopType)
277 leftCon <- constrain rtv leftExpr (FromContext region (OpLeft op) leftType)
278 rightCon <- constrain rtv rightExpr (FromContext region (OpRight op) rightType)
280 return $ exists [ leftVar, rightVar, answerVar ] $
285 , CEqual region (CallResult (OpName op)) answerType expected
293constrainList :: RTV -> R.Region -> [Can.Expr] -> Expected Type -> IO Constraint
294constrainList rtv region entries expected =
295 do entryVar <- mkFlexVar
296 let entryType = VarN entryVar
297 let listType = AppN ModuleName.list N.list [entryType]
300 Index.indexedTraverse (constrainListEntry rtv region entryType) entries
302 return $ exists [entryVar] $
305 , CEqual region List listType expected
309constrainListEntry :: RTV -> R.Region -> Type -> Index.ZeroBased -> Can.Expr -> IO Constraint
310constrainListEntry rtv region tipe index expr =
311 constrain rtv expr (FromContext region (ListEntry index) tipe)
315-- CONSTRAIN IF EXPRESSIONS
318constrainIf :: RTV -> R.Region -> [(Can.Expr, Can.Expr)] -> Can.Expr -> Expected Type -> IO Constraint
319constrainIf rtv region branches final expected =
320 do let boolExpect = FromContext region IfCondition Type.bool
321 let (conditions, exprs) = foldr (\(c,e) (cs,es) -> (c:cs,e:es)) ([],[final]) branches
324 traverse (\c -> constrain rtv c boolExpect) conditions
327 FromAnnotation name arity _ tipe ->
328 do branchCons <- Index.indexedForA exprs $ \index expr ->
329 constrain rtv expr (FromAnnotation name arity (TypedIfBranch index) tipe)
337 do branchVar <- mkFlexVar
338 let branchType = VarN branchVar
340 branchCons <- Index.indexedForA exprs $ \index expr ->
341 constrain rtv expr (FromContext region (IfBranch index) branchType)
343 return $ exists [branchVar] $
347 , CEqual region If branchType expected
352-- CONSTRAIN CASE EXPRESSIONS
355constrainCase :: RTV -> R.Region -> Can.Expr -> [Can.CaseBranch] -> Expected Type -> IO Constraint
356constrainCase rtv region expr branches expected =
357 do ptrnVar <- mkFlexVar
358 let ptrnType = VarN ptrnVar
359 exprCon <- constrain rtv expr (NoExpectation ptrnType)
362 FromAnnotation name arity _ tipe ->
363 do branchCons <- Index.indexedForA branches $ \index branch ->
364 constrainCaseBranch rtv branch
365 (PFromContext region (PCaseMatch index) ptrnType)
366 (FromAnnotation name arity (TypedCaseBranch index) tipe)
368 return $ exists [ptrnVar] $ CAnd (exprCon:branchCons)
371 do branchVar <- mkFlexVar
372 let branchType = VarN branchVar
374 branchCons <- Index.indexedForA branches $ \index branch ->
375 constrainCaseBranch rtv branch
376 (PFromContext region (PCaseMatch index) ptrnType)
377 (FromContext region (CaseBranch index) branchType)
379 return $ exists [ptrnVar,branchVar] $
383 , CEqual region Case branchType expected
387constrainCaseBranch :: RTV -> Can.CaseBranch -> PExpected Type -> Expected Type -> IO Constraint
388constrainCaseBranch rtv (Can.CaseBranch pattern expr) pExpect bExpect =
389 do (Pattern.State headers pvars revCons) <-
390 Pattern.add pattern pExpect Pattern.emptyState
392 CLet [] pvars headers (CAnd (reverse revCons))
393 <$> constrain rtv expr bExpect
400constrainRecord :: RTV -> R.Region -> Map.Map N.Name Can.Expr -> Expected Type -> IO Constraint
401constrainRecord rtv region fields expected =
402 do dict <- traverse (constrainField rtv) fields
404 let getType (_, t, _) = t
405 let recordType = RecordN (Map.map getType dict) EmptyRecordN
406 let recordCon = CEqual region Record recordType expected
408 let vars = Map.foldr (\(v,_,_) vs -> v:vs) [] dict
409 let cons = Map.foldr (\(_,_,c) cs -> c:cs) [recordCon] dict
411 return $ exists vars (CAnd cons)
414constrainField :: RTV -> Can.Expr -> IO (Variable, Type, Constraint)
415constrainField rtv expr =
418 con <- constrain rtv expr (NoExpectation tipe)
419 return (var, tipe, con)
423-- CONSTRAIN RECORD UPDATE
426constrainUpdate :: RTV -> R.Region -> Can.Expr -> Map.Map N.Name Can.Expr -> Expected Type -> IO Constraint
427constrainUpdate rtv region expr fields expected =
428 do sharedVar <- mkFlexVar
429 let sharedType = VarN sharedVar
431 oldVars <- traverse (\_ -> mkFlexVar) fields
432 let oldTypes = Map.map VarN oldVars
433 let oldRecordType = RecordN oldTypes sharedType
434 oldCon <- constrain rtv expr (FromContext region RecordUpdate oldRecordType)
436 newDict <- traverse (constrainField rtv) fields
438 let getType (_, t, _) = t
439 let newRecordType = RecordN (Map.map getType newDict) sharedType
440 let newCon = CEqual region Record newRecordType expected
442 let vars = Map.foldr (\(v,_,_) vs -> v:vs) (sharedVar : Map.elems oldVars) newDict
443 let cons = Map.foldr (\(_,_,c) cs -> c:cs) [newCon] newDict
445 return $ exists vars (CAnd (oldCon:cons))
452constrainTuple :: RTV -> R.Region -> Can.Expr -> Can.Expr -> Maybe Can.Expr -> Expected Type -> IO Constraint
453constrainTuple rtv region a b maybeC expected =
456 let aType = VarN aVar
457 let bType = VarN bVar
459 aCon <- constrain rtv a (NoExpectation aType)
460 bCon <- constrain rtv b (NoExpectation bType)
464 do let tupleType = TupleN aType bType Nothing
465 let tupleCon = CEqual region Tuple tupleType expected
466 return $ exists [ aVar, bVar ] $ CAnd [ aCon, bCon, tupleCon ]
470 let cType = VarN cVar
472 cCon <- constrain rtv c (NoExpectation cType)
474 let tupleType = TupleN aType bType (Just cType)
475 let tupleCon = CEqual region Tuple tupleType expected
477 return $ exists [ aVar, bVar, cVar ] $ CAnd [ aCon, bCon, cCon, tupleCon ]
484constrainShader :: R.Region -> Shader.Shader -> Expected Type -> IO Constraint
485constrainShader region (Shader.Shader attributes uniforms varyings) expected =
486 do attrVar <- mkFlexVar
488 let attrType = VarN attrVar
489 let unifType = VarN unifVar
492 AppN ModuleName.webgl N.shader
493 [ toShaderRecord attributes attrType
494 , toShaderRecord uniforms unifType
495 , toShaderRecord varyings EmptyRecordN
498 return $ exists [ attrVar, unifVar ] $
499 CEqual region Shader shaderType expected
502toShaderRecord :: Map.Map N.Name Shader.Type -> Type -> Type
503toShaderRecord types baseRecType =
504 if Map.null types then
507 RecordN (Map.map glToType types) baseRecType
510glToType :: Shader.Type -> Type
513 Shader.V2 -> Type.vec2
514 Shader.V3 -> Type.vec3
515 Shader.V4 -> Type.vec4
516 Shader.M4 -> Type.mat4
517 Shader.Int -> Type.int
518 Shader.Float -> Type.float
519 Shader.Texture -> Type.texture
523-- CONSTRAIN DESTRUCTURES
526constrainDestruct :: RTV -> R.Region -> Can.Pattern -> Can.Expr -> Constraint -> IO Constraint
527constrainDestruct rtv region pattern expr bodyCon =
528 do patternVar <- mkFlexVar
529 let patternType = VarN patternVar
531 (Pattern.State headers pvars revCons) <-
532 Pattern.add pattern (PNoExpectation patternType) Pattern.emptyState
535 constrain rtv expr (FromContext region Destructure patternType)
537 return $ CLet [] (patternVar:pvars) headers (CAnd (reverse (exprCon:revCons))) bodyCon
544constrainDef :: RTV -> Can.Def -> Constraint -> IO Constraint
545constrainDef rtv def bodyCon =
547 Can.Def (A.At region name) args expr ->
548 do (Args vars tipe resultType (Pattern.State headers pvars revCons)) <-
552 constrain rtv expr (NoExpectation resultType)
558 , _header = Map.singleton name (A.At region tipe)
564 , _headerCon = CAnd (reverse revCons)
570 Can.TypedDef (A.At region name) freeVars typedArgs expr srcResultType ->
571 do let newNames = Map.difference freeVars rtv
572 newRigids <- Map.traverseWithKey (\n _ -> nameToRigid n) newNames
573 let newRtv = Map.union rtv (Map.map VarN newRigids)
575 (TypedArgs tipe resultType (Pattern.State headers pvars revCons)) <-
576 constrainTypedArgs newRtv name typedArgs srcResultType
578 let expected = FromAnnotation name (length typedArgs) TypedBody resultType
580 constrain newRtv expr expected
584 { _rigidVars = Map.elems newRigids
586 , _header = Map.singleton name (A.At region tipe)
592 , _headerCon = CAnd (reverse revCons)
600-- CONSTRAIN RECURSIVE DEFS
605 { _vars :: [Variable]
606 , _cons :: [Constraint]
607 , _headers :: Map.Map N.Name (A.Located Type)
611{-# NOINLINE emptyInfo #-}
617constrainRecursiveDefs :: RTV -> [Can.Def] -> Constraint -> IO Constraint
618constrainRecursiveDefs rtv defs bodyCon =
619 recDefsHelp rtv defs bodyCon emptyInfo emptyInfo
622recDefsHelp :: RTV -> [Can.Def] -> Constraint -> Info -> Info -> IO Constraint
623recDefsHelp rtv defs bodyCon rigidInfo flexInfo =
626 do let (Info rigidVars rigidCons rigidHeaders) = rigidInfo
627 let (Info flexVars flexCons flexHeaders ) = flexInfo
629 CLet rigidVars [] rigidHeaders CTrue $
630 CLet [] flexVars flexHeaders (CLet [] [] flexHeaders CTrue (CAnd flexCons)) $
631 CAnd [ CAnd rigidCons, bodyCon ]
635 Can.Def (A.At region name) args expr ->
636 do let (Info flexVars flexCons flexHeaders) = flexInfo
638 (Args newFlexVars tipe resultType (Pattern.State headers pvars revCons)) <-
639 argsHelp args (Pattern.State Map.empty flexVars [])
642 constrain rtv expr (NoExpectation resultType)
649 , _headerCon = CAnd (reverse revCons)
653 recDefsHelp rtv otherDefs bodyCon rigidInfo $
655 { _vars = newFlexVars
656 , _cons = defCon : flexCons
657 , _headers = Map.insert name (A.At region tipe) flexHeaders
660 Can.TypedDef (A.At region name) freeVars typedArgs expr srcResultType ->
661 do let newNames = Map.difference freeVars rtv
662 newRigids <- Map.traverseWithKey (\n _ -> nameToRigid n) newNames
663 let newRtv = Map.union rtv (Map.map VarN newRigids)
665 (TypedArgs tipe resultType (Pattern.State headers pvars revCons)) <-
666 constrainTypedArgs newRtv name typedArgs srcResultType
669 constrain newRtv expr $
670 FromAnnotation name (length typedArgs) TypedBody resultType
677 , _headerCon = CAnd (reverse revCons)
681 let (Info rigidVars rigidCons rigidHeaders) = rigidInfo
682 recDefsHelp rtv otherDefs bodyCon
684 { _vars = Map.foldr (:) rigidVars newRigids
685 , _cons = defCon : rigidCons
686 , _headers = Map.insert name (A.At region tipe) rigidHeaders
698 { _a_vars :: [Variable]
701 , _a_state :: Pattern.State
705constrainArgs :: [Can.Pattern] -> IO Args
707 argsHelp args Pattern.emptyState
710argsHelp :: [Can.Pattern] -> Pattern.State -> IO Args
714 do resultVar <- mkFlexVar
715 let resultType = VarN resultVar
716 return $ Args [resultVar] resultType resultType state
718 pattern : otherArgs ->
719 do argVar <- mkFlexVar
720 let argType = VarN argVar
722 (Args vars tipe result newState) <-
723 argsHelp otherArgs =<<
724 Pattern.add pattern (PNoExpectation argType) state
726 return (Args (argVar:vars) (FunN argType tipe) result newState)
730-- CONSTRAIN TYPED ARGS
737 , _t_state :: Pattern.State
741constrainTypedArgs :: Map.Map N.Name Type -> N.Name -> [(Can.Pattern, Can.Type)] -> Can.Type -> IO TypedArgs
742constrainTypedArgs rtv name args srcResultType =
743 do resultType <- Instantiate.fromSrcType rtv srcResultType
744 typedArgsHelp rtv name Index.first args resultType Pattern.emptyState
747typedArgsHelp :: Map.Map N.Name Type -> N.Name -> Index.ZeroBased -> [(Can.Pattern, Can.Type)] -> Type -> Pattern.State -> IO TypedArgs
748typedArgsHelp rtv name index args resultType state =
751 return $ TypedArgs resultType resultType state
753 (pattern@(A.At region _), srcType) : otherArgs ->
754 do argType <- Instantiate.fromSrcType rtv srcType
755 let expected = PFromContext region (PTypedArg name index) argType
757 (TypedArgs tipe result newState) <-
758 typedArgsHelp rtv name (Index.next index) otherArgs resultType =<<
759 Pattern.add pattern expected state
761 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