1{-# OPTIONS_GHC -Wall #-}
2module Type.Constrain.Expression
5 , constrainRecursiveDefs
10import qualified Data.Map.Strict as Map
11import qualified Data.Name as Name
13import qualified AST.Canonical as Can
14import qualified AST.Utils.Shader as Shader
15import qualified Data.Index as Index
16import qualified Elm.ModuleName as ModuleName
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 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`
37 Map.Map Name.Name Type
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 E.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 E.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 (A.At accessRegion 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
130 let context = RecordAccess (A.toRegion expr) (getAccessName expr) accessRegion field
131 recordCon <- constrain rtv expr (FromContext region context recordType)
133 return $ exists [ fieldVar, extVar ] $
136 , CEqual region (Access field) fieldType expected
139 Can.Update name expr fields ->
140 constrainUpdate rtv region name 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 _src types ->
152 constrainShader region types expected
159constrainLambda :: RTV -> A.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 -> A.Region -> Can.Expr -> [Can.Expr] -> Expected Type -> IO Constraint
185constrainCall rtv region func@(A.At funcRegion _) 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 category = CallResult maybeName
201 return $ exists (funcVar:resultVar:argVars) $
204 , CEqual funcRegion category funcType (FromContext region (CallArity maybeName (length args)) arityType)
206 , CEqual region category resultType expected
210constrainArg :: RTV -> A.Region -> MaybeName -> Index.ZeroBased -> Can.Expr -> IO (Variable, Type, Constraint)
211constrainArg rtv region maybeName index arg =
212 do argVar <- mkFlexVar
213 let argType = VarN argVar
214 argCon <- constrain rtv arg (FromContext region (CallArg maybeName index) argType)
215 return (argVar, argType, argCon)
218getName :: Can.Expr -> MaybeName
219getName (A.At _ expr) =
221 Can.VarLocal name -> FuncName name
222 Can.VarTopLevel _ name -> FuncName name
223 Can.VarForeign _ name _ -> FuncName name
224 Can.VarCtor _ _ name _ _ -> CtorName name
225 Can.VarOperator op _ _ _ -> OpName op
226 Can.VarKernel _ name -> FuncName name
230getAccessName :: Can.Expr -> Maybe Name.Name
231getAccessName (A.At _ expr) =
233 Can.VarLocal name -> Just name
234 Can.VarTopLevel _ name -> Just name
235 Can.VarForeign _ name _ -> Just name
243constrainBinop :: RTV -> A.Region -> Name.Name -> Can.Annotation -> Can.Expr -> Can.Expr -> Expected Type -> IO Constraint
244constrainBinop rtv region op annotation leftExpr rightExpr expected =
245 do leftVar <- mkFlexVar
246 rightVar <- mkFlexVar
247 answerVar <- mkFlexVar
248 let leftType = VarN leftVar
249 let rightType = VarN rightVar
250 let answerType = VarN answerVar
251 let binopType = leftType ==> rightType ==> answerType
253 let opCon = CForeign region op annotation (NoExpectation binopType)
255 leftCon <- constrain rtv leftExpr (FromContext region (OpLeft op) leftType)
256 rightCon <- constrain rtv rightExpr (FromContext region (OpRight op) rightType)
258 return $ exists [ leftVar, rightVar, answerVar ] $
263 , CEqual region (CallResult (OpName op)) answerType expected
271constrainList :: RTV -> A.Region -> [Can.Expr] -> Expected Type -> IO Constraint
272constrainList rtv region entries expected =
273 do entryVar <- mkFlexVar
274 let entryType = VarN entryVar
275 let listType = AppN ModuleName.list Name.list [entryType]
278 Index.indexedTraverse (constrainListEntry rtv region entryType) entries
280 return $ exists [entryVar] $
283 , CEqual region List listType expected
287constrainListEntry :: RTV -> A.Region -> Type -> Index.ZeroBased -> Can.Expr -> IO Constraint
288constrainListEntry rtv region tipe index expr =
289 constrain rtv expr (FromContext region (ListEntry index) tipe)
293-- CONSTRAIN IF EXPRESSIONS
296constrainIf :: RTV -> A.Region -> [(Can.Expr, Can.Expr)] -> Can.Expr -> Expected Type -> IO Constraint
297constrainIf rtv region branches final expected =
298 do let boolExpect = FromContext region IfCondition Type.bool
299 let (conditions, exprs) = foldr (\(c,e) (cs,es) -> (c:cs,e:es)) ([],[final]) branches
302 traverse (\c -> constrain rtv c boolExpect) conditions
305 FromAnnotation name arity _ tipe ->
306 do branchCons <- Index.indexedForA exprs $ \index expr ->
307 constrain rtv expr (FromAnnotation name arity (TypedIfBranch index) tipe)
315 do branchVar <- mkFlexVar
316 let branchType = VarN branchVar
318 branchCons <- Index.indexedForA exprs $ \index expr ->
319 constrain rtv expr (FromContext region (IfBranch index) branchType)
321 return $ exists [branchVar] $
325 , CEqual region If branchType expected
330-- CONSTRAIN CASE EXPRESSIONS
333constrainCase :: RTV -> A.Region -> Can.Expr -> [Can.CaseBranch] -> Expected Type -> IO Constraint
334constrainCase rtv region expr branches expected =
335 do ptrnVar <- mkFlexVar
336 let ptrnType = VarN ptrnVar
337 exprCon <- constrain rtv expr (NoExpectation ptrnType)
340 FromAnnotation name arity _ tipe ->
341 do branchCons <- Index.indexedForA branches $ \index branch ->
342 constrainCaseBranch rtv branch
343 (PFromContext region (PCaseMatch index) ptrnType)
344 (FromAnnotation name arity (TypedCaseBranch index) tipe)
346 return $ exists [ptrnVar] $ CAnd (exprCon:branchCons)
349 do branchVar <- mkFlexVar
350 let branchType = VarN branchVar
352 branchCons <- Index.indexedForA branches $ \index branch ->
353 constrainCaseBranch rtv branch
354 (PFromContext region (PCaseMatch index) ptrnType)
355 (FromContext region (CaseBranch index) branchType)
357 return $ exists [ptrnVar,branchVar] $
361 , CEqual region Case branchType expected
365constrainCaseBranch :: RTV -> Can.CaseBranch -> PExpected Type -> Expected Type -> IO Constraint
366constrainCaseBranch rtv (Can.CaseBranch pattern expr) pExpect bExpect =
367 do (Pattern.State headers pvars revCons) <-
368 Pattern.add pattern pExpect Pattern.emptyState
370 CLet [] pvars headers (CAnd (reverse revCons))
371 <$> constrain rtv expr bExpect
378constrainRecord :: RTV -> A.Region -> Map.Map Name.Name Can.Expr -> Expected Type -> IO Constraint
379constrainRecord rtv region fields expected =
380 do dict <- traverse (constrainField rtv) fields
382 let getType (_, t, _) = t
383 let recordType = RecordN (Map.map getType dict) EmptyRecordN
384 let recordCon = CEqual region Record recordType expected
386 let vars = Map.foldr (\(v,_,_) vs -> v:vs) [] dict
387 let cons = Map.foldr (\(_,_,c) cs -> c:cs) [recordCon] dict
389 return $ exists vars (CAnd cons)
392constrainField :: RTV -> Can.Expr -> IO (Variable, Type, Constraint)
393constrainField rtv expr =
396 con <- constrain rtv expr (NoExpectation tipe)
397 return (var, tipe, con)
401-- CONSTRAIN RECORD UPDATE
404constrainUpdate :: RTV -> A.Region -> Name.Name -> Can.Expr -> Map.Map Name.Name Can.FieldUpdate -> Expected Type -> IO Constraint
405constrainUpdate rtv region name expr fields expected =
406 do extVar <- mkFlexVar
407 fieldDict <- Map.traverseWithKey (constrainUpdateField rtv region) fields
409 recordVar <- mkFlexVar
410 let recordType = VarN recordVar
411 let fieldsType = RecordN (Map.map (\(_,t,_) -> t) fieldDict) (VarN extVar)
413 -- NOTE: fieldsType is separate so that Error propagates better
414 let fieldsCon = CEqual region Record recordType (NoExpectation fieldsType)
415 let recordCon = CEqual region Record recordType expected
417 let vars = Map.foldr (\(v,_,_) vs -> v:vs) [recordVar,extVar] fieldDict
418 let cons = Map.foldr (\(_,_,c) cs -> c:cs) [recordCon] fieldDict
420 con <- constrain rtv expr (FromContext region (RecordUpdateKeys name fields) recordType)
422 return $ exists vars $ CAnd (fieldsCon:con:cons)
425constrainUpdateField :: RTV -> A.Region -> Name.Name -> Can.FieldUpdate -> IO (Variable, Type, Constraint)
426constrainUpdateField rtv region field (Can.FieldUpdate _ expr) =
429 con <- constrain rtv expr (FromContext region (RecordUpdateValue field) tipe)
430 return (var, tipe, con)
437constrainTuple :: RTV -> A.Region -> Can.Expr -> Can.Expr -> Maybe Can.Expr -> Expected Type -> IO Constraint
438constrainTuple rtv region a b maybeC expected =
441 let aType = VarN aVar
442 let bType = VarN bVar
444 aCon <- constrain rtv a (NoExpectation aType)
445 bCon <- constrain rtv b (NoExpectation bType)
449 do let tupleType = TupleN aType bType Nothing
450 let tupleCon = CEqual region Tuple tupleType expected
451 return $ exists [ aVar, bVar ] $ CAnd [ aCon, bCon, tupleCon ]
455 let cType = VarN cVar
457 cCon <- constrain rtv c (NoExpectation cType)
459 let tupleType = TupleN aType bType (Just cType)
460 let tupleCon = CEqual region Tuple tupleType expected
462 return $ exists [ aVar, bVar, cVar ] $ CAnd [ aCon, bCon, cCon, tupleCon ]
469constrainShader :: A.Region -> Shader.Types -> Expected Type -> IO Constraint
470constrainShader region (Shader.Types attributes uniforms varyings) expected =
471 do attrVar <- mkFlexVar
473 let attrType = VarN attrVar
474 let unifType = VarN unifVar
477 AppN ModuleName.webgl Name.shader
478 [ toShaderRecord attributes attrType
479 , toShaderRecord uniforms unifType
480 , toShaderRecord varyings EmptyRecordN
483 return $ exists [ attrVar, unifVar ] $
484 CEqual region Shader shaderType expected
487toShaderRecord :: Map.Map Name.Name Shader.Type -> Type -> Type
488toShaderRecord types baseRecType =
489 if Map.null types then
492 RecordN (Map.map glToType types) baseRecType
495glToType :: Shader.Type -> Type
498 Shader.V2 -> Type.vec2
499 Shader.V3 -> Type.vec3
500 Shader.V4 -> Type.vec4
501 Shader.M4 -> Type.mat4
502 Shader.Int -> Type.int
503 Shader.Float -> Type.float
504 Shader.Texture -> Type.texture
508-- CONSTRAIN DESTRUCTURES
511constrainDestruct :: RTV -> A.Region -> Can.Pattern -> Can.Expr -> Constraint -> IO Constraint
512constrainDestruct rtv region pattern expr bodyCon =
513 do patternVar <- mkFlexVar
514 let patternType = VarN patternVar
516 (Pattern.State headers pvars revCons) <-
517 Pattern.add pattern (PNoExpectation patternType) Pattern.emptyState
520 constrain rtv expr (FromContext region Destructure patternType)
522 return $ CLet [] (patternVar:pvars) headers (CAnd (reverse (exprCon:revCons))) bodyCon
529constrainDef :: RTV -> Can.Def -> Constraint -> IO Constraint
530constrainDef rtv def bodyCon =
532 Can.Def (A.At region name) args expr ->
533 do (Args vars tipe resultType (Pattern.State headers pvars revCons)) <-
537 constrain rtv expr (NoExpectation resultType)
543 , _header = Map.singleton name (A.At region tipe)
549 , _headerCon = CAnd (reverse revCons)
555 Can.TypedDef (A.At region name) freeVars typedArgs expr srcResultType ->
556 do let newNames = Map.difference freeVars rtv
557 newRigids <- Map.traverseWithKey (\n _ -> nameToRigid n) newNames
558 let newRtv = Map.union rtv (Map.map VarN newRigids)
560 (TypedArgs tipe resultType (Pattern.State headers pvars revCons)) <-
561 constrainTypedArgs newRtv name typedArgs srcResultType
563 let expected = FromAnnotation name (length typedArgs) TypedBody resultType
565 constrain newRtv expr expected
569 { _rigidVars = Map.elems newRigids
571 , _header = Map.singleton name (A.At region tipe)
577 , _headerCon = CAnd (reverse revCons)
585-- CONSTRAIN RECURSIVE DEFS
590 { _vars :: [Variable]
591 , _cons :: [Constraint]
592 , _headers :: Map.Map Name.Name (A.Located Type)
596{-# NOINLINE emptyInfo #-}
602constrainRecursiveDefs :: RTV -> [Can.Def] -> Constraint -> IO Constraint
603constrainRecursiveDefs rtv defs bodyCon =
604 recDefsHelp rtv defs bodyCon emptyInfo emptyInfo
607recDefsHelp :: RTV -> [Can.Def] -> Constraint -> Info -> Info -> IO Constraint
608recDefsHelp rtv defs bodyCon rigidInfo flexInfo =
611 do let (Info rigidVars rigidCons rigidHeaders) = rigidInfo
612 let (Info flexVars flexCons flexHeaders ) = flexInfo
614 CLet rigidVars [] rigidHeaders CTrue $
615 CLet [] flexVars flexHeaders (CLet [] [] flexHeaders CTrue (CAnd flexCons)) $
616 CAnd [ CAnd rigidCons, bodyCon ]
620 Can.Def (A.At region name) args expr ->
621 do let (Info flexVars flexCons flexHeaders) = flexInfo
623 (Args newFlexVars tipe resultType (Pattern.State headers pvars revCons)) <-
624 argsHelp args (Pattern.State Map.empty flexVars [])
627 constrain rtv expr (NoExpectation resultType)
634 , _headerCon = CAnd (reverse revCons)
638 recDefsHelp rtv otherDefs bodyCon rigidInfo $
640 { _vars = newFlexVars
641 , _cons = defCon : flexCons
642 , _headers = Map.insert name (A.At region tipe) flexHeaders
645 Can.TypedDef (A.At region name) freeVars typedArgs expr srcResultType ->
646 do let newNames = Map.difference freeVars rtv
647 newRigids <- Map.traverseWithKey (\n _ -> nameToRigid n) newNames
648 let newRtv = Map.union rtv (Map.map VarN newRigids)
650 (TypedArgs tipe resultType (Pattern.State headers pvars revCons)) <-
651 constrainTypedArgs newRtv name typedArgs srcResultType
654 constrain newRtv expr $
655 FromAnnotation name (length typedArgs) TypedBody resultType
662 , _headerCon = CAnd (reverse revCons)
666 let (Info rigidVars rigidCons rigidHeaders) = rigidInfo
667 recDefsHelp rtv otherDefs bodyCon
669 { _vars = Map.foldr (:) rigidVars newRigids
670 , _cons = CLet (Map.elems newRigids) [] Map.empty defCon CTrue : rigidCons
671 , _headers = Map.insert name (A.At region tipe) rigidHeaders
683 { _a_vars :: [Variable]
686 , _a_state :: Pattern.State
690constrainArgs :: [Can.Pattern] -> IO Args
692 argsHelp args Pattern.emptyState
695argsHelp :: [Can.Pattern] -> Pattern.State -> IO Args
699 do resultVar <- mkFlexVar
700 let resultType = VarN resultVar
701 return $ Args [resultVar] resultType resultType state
703 pattern : otherArgs ->
704 do argVar <- mkFlexVar
705 let argType = VarN argVar
707 (Args vars tipe result newState) <-
708 argsHelp otherArgs =<<
709 Pattern.add pattern (PNoExpectation argType) state
711 return (Args (argVar:vars) (FunN argType tipe) result newState)
715-- CONSTRAIN TYPED ARGS
722 , _t_state :: Pattern.State
726constrainTypedArgs :: Map.Map Name.Name Type -> Name.Name -> [(Can.Pattern, Can.Type)] -> Can.Type -> IO TypedArgs
727constrainTypedArgs rtv name args srcResultType =
728 typedArgsHelp rtv name Index.first args srcResultType Pattern.emptyState
731typedArgsHelp :: Map.Map Name.Name Type -> Name.Name -> Index.ZeroBased -> [(Can.Pattern, Can.Type)] -> Can.Type -> Pattern.State -> IO TypedArgs
732typedArgsHelp rtv name index args srcResultType state =
735 do resultType <- Instantiate.fromSrcType rtv srcResultType
736 return $ TypedArgs resultType resultType state
738 (pattern@(A.At region _), srcType) : otherArgs ->
739 do argType <- Instantiate.fromSrcType rtv srcType
740 let expected = PFromContext region (PTypedArg name index) argType
742 (TypedArgs tipe resultType newState) <-
743 typedArgsHelp rtv name (Index.next index) otherArgs srcResultType =<<
744 Pattern.add pattern expected state
746 return (TypedArgs (FunN argType tipe) resultType 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