1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Type.Constrain.Expression where
5import Control.Arrow (second)
6import qualified Control.Monad as Monad
7import qualified Data.Map as Map
8import qualified Data.Text as Text
11import qualified AST.Expression.Canonical as C
12import qualified AST.Literal as Lit
13import qualified AST.Pattern as P
14import qualified AST.Type as ST
15import qualified AST.Variable as V
16import qualified Reporting.Annotation as A
17import qualified Reporting.Error.Type as Error
18import qualified Reporting.Region as R
19import qualified Type.Constrain.Effects as Effects
20import qualified Type.Constrain.Literal as Literal
21import qualified Type.Constrain.Pattern as Pattern
22import qualified Type.Environment as Env
23import Type.Type hiding (Descriptor(..))
27constrain :: Env.Env -> C.Expr -> Type -> IO Constraint
28constrain env annotatedExpr@(A.A region expression) tipe =
31 Literal.constrain env region lit tipe
46 error "DANGER - Program AST nodes should not be in type inference."
48 C.SaveEnv moduleName effects ->
49 Effects.constrain env moduleName effects
51 C.GLShader _uid _src glType ->
56 Env.getType env "WebGL.Shader" <| a <| u <| v
59 Env.getType env (Lit.glTypeToText gl)
61 makeRec accessor baseRec =
62 let decls = accessor glType
64 if Map.null decls then
67 RecordN (Map.map glToType decls) baseRec
69 attribute = makeRec Lit.attribute attr
70 uniform = makeRec Lit.uniform unif
71 varying = makeRec Lit.varying EmptyRecordN
73 return (CEqual Error.Shader region (shaderTipe attribute uniform varying) tipe)
76 return (CInstance region (V.toText var) tipe)
79 constrainList env region exprs tipe
81 C.Binop op leftExpr rightExpr ->
82 constrainBinop env region op leftExpr rightExpr tipe
84 C.Lambda pattern body ->
87 do (Pattern.Info headers vars cons) <- Pattern.constrain env pattern argType
88 bodyCon <- constrain env body resType
90 ex vars (CLet [monoscheme headers] (cons /\ bodyCon))
91 /\ CEqual Error.Lambda region (argType ==> resType) tipe
95 (f:args) = C.collectApps annotatedExpr
97 constrainApp env region f args tipe
99 C.If branches finally ->
100 constrainIf env region branches finally tipe
102 C.Case expr branches ->
103 constrainCase env region expr branches tipe
106 do vars <- Monad.forM exprs $ \_ -> mkVar Nothing
107 let pairs = zip exprs (map VarN vars)
108 (ctipe, cs) <- Monad.foldM step (tipe, CTrue) (reverse pairs)
109 return $ ex vars (cs /\ CInstance region (V.toText name) ctipe)
112 do c' <- constrain env e x
113 return (x ==> t, c /\ c')
115 C.Access expr field ->
116 exists $ \recordType ->
118 do recordCon <- constrain env expr recordType
119 let maybeBody = C.collectFields expr
120 let desiredType = RecordN (Map.singleton field tipe) ext
121 let fieldCon = CEqual (Error.Access maybeBody field) region recordType desiredType
122 return $ recordCon /\ fieldCon
124 C.Update expr fields ->
126 do oldVars <- mapM (\_ -> mkVar Nothing) fields
127 let oldFields = Map.fromList (zip (map fst fields) (map VarN oldVars))
128 cOld <- ex oldVars <$> constrain env expr (RecordN oldFields t)
130 newVars <- mapM (\_ -> mkVar Nothing) fields
131 let newFields = Map.fromList (zip (map fst fields) (map VarN newVars))
132 let cNew = CEqual Error.Record region (RecordN newFields t) tipe
134 cs <- Monad.zipWithM (constrain env) (map snd fields) (map VarN newVars)
136 return $ cOld /\ ex newVars (CAnd (cNew : cs))
139 do vars <- Monad.forM fields (\_ -> mkVar Nothing)
145 let fields' = Map.fromList (zip (map fst fields) (map VarN vars))
146 let recordType = RecordN fields' EmptyRecordN
147 return (ex vars (CAnd (fieldCons ++ [CEqual Error.Record region recordType tipe])))
150 do bodyCon <- constrain env body tipe
152 (Info schemes rqs fqs headers c2 c1) <-
155 (Info [] [] [] Map.empty CTrue CTrue)
156 (concatMap expandPattern defs)
159 [ Scheme rqs fqs (CLet [monoscheme headers] c2) headers ]
161 return $ CLet schemes (CLet letScheme (c1 /\ bodyCon))
175constrainApp env region f args tipe =
176 do funcVar <- mkVar Nothing
177 funcCon <- constrain env f (VarN funcVar)
179 (vars, argCons, numberOfArgsCons, argMatchCons, _, returnVar) <-
180 argConstraints env maybeName region (length args) funcVar 1 args
183 CEqual (Error.Function maybeName) region (VarN returnVar) tipe
185 return $ ex (funcVar : vars) $
186 CAnd (funcCon : argCons ++ numberOfArgsCons ++ argMatchCons ++ [returnCon])
190 A.A _ (C.Var canonicalName) ->
205 -> IO ([Variable], [Constraint], [Constraint], [Constraint], Maybe R.Region, Variable)
206argConstraints env name region totalArgs overallVar index args =
209 return ([], [], [], [], Nothing, overallVar)
211 expr@(A.A subregion _) : rest ->
212 do argVar <- mkVar Nothing
213 argCon <- constrain env expr (VarN argVar)
214 argIndexVar <- mkVar Nothing
215 localReturnVar <- mkVar Nothing
217 (vars, argConRest, numberOfArgsRest, argMatchRest, restRegion, returnVar) <-
218 argConstraints env name region totalArgs localReturnVar (index + 1) rest
221 maybe subregion (R.merge subregion) restRegion
223 let numberOfArgsCon =
225 (Error.FunctionArity name (index - 1) totalArgs arityRegion)
227 (VarN argIndexVar ==> VarN localReturnVar)
232 (Error.UnexpectedArg name index totalArgs subregion)
238 ( argVar : argIndexVar : localReturnVar : vars
239 , argCon : argConRest
240 , numberOfArgsCon : numberOfArgsRest
241 , argMatchCon : argMatchRest
259constrainBinop env region op leftExpr@(A.A leftRegion _) rightExpr@(A.A rightRegion _) tipe =
260 do leftVar <- mkVar Nothing
261 rightVar <- mkVar Nothing
263 leftCon <- constrain env leftExpr (VarN leftVar)
264 rightCon <- constrain env rightExpr (VarN rightVar)
266 leftVar' <- mkVar Nothing
267 rightVar' <- mkVar Nothing
268 answerVar <- mkVar Nothing
270 let opType = VarN leftVar' ==> VarN rightVar' ==> VarN answerVar
273 ex [leftVar,rightVar,leftVar',rightVar',answerVar] $ CAnd $
276 , CInstance region (V.toText op) opType
277 , CEqual (Error.BinopLeft op leftRegion) region (VarN leftVar') (VarN leftVar)
278 , CEqual (Error.BinopRight op rightRegion) region (VarN rightVar') (VarN rightVar)
279 , CEqual (Error.Binop op) region (VarN answerVar) tipe
287constrainList :: Env.Env -> R.Region -> [C.Expr] -> Type -> IO Constraint
288constrainList env region exprs tipe =
289 do (exprInfo, exprCons) <-
290 unzip <$> mapM elementConstraint exprs
292 (vars, cons) <- pairCons region Error.ListElement varToCon exprInfo
294 return $ ex vars (CAnd (exprCons ++ cons))
296 elementConstraint expr@(A.A region' _) =
297 do var <- mkVar Nothing
298 con <- constrain env expr (VarN var)
299 return ( (var, region'), con )
302 CEqual Error.List region (Env.getType env "List" <| VarN var) tipe
306-- CONSTRAIN IF EXPRESSIONS
312 -> [(C.Expr, C.Expr)]
316constrainIf env region branches finally tipe =
317 do let (conditions, branchExprs) =
318 second (++ [finally]) (unzip branches)
320 (condVars, condCons) <-
321 unzip <$> mapM constrainCondition conditions
323 (branchInfo, branchExprCons) <-
324 unzip <$> mapM constrainBranch branchExprs
326 (vars,cons) <- branchCons branchInfo
328 return $ ex (condVars ++ vars) (CAnd (condCons ++ branchExprCons ++ cons))
331 Env.getType env "Bool"
333 constrainCondition condition@(A.A condRegion _) =
334 do condVar <- mkVar Nothing
335 condCon <- constrain env condition (VarN condVar)
336 let boolCon = CEqual Error.IfCondition condRegion (VarN condVar) bool
337 return (condVar, CAnd [ condCon, boolCon ])
339 constrainBranch expr@(A.A branchRegion _) =
340 do branchVar <- mkVar Nothing
341 exprCon <- constrain env expr (VarN branchVar)
343 ( (branchVar, branchRegion)
347 branchCons branchInfo =
349 [(thenVar, _), (elseVar, _)] ->
352 , [ CEqual Error.IfBranches region (VarN thenVar) (VarN elseVar)
358 pairCons region Error.MultiIfBranch varToCon branchInfo
361 CEqual Error.If region (VarN var) tipe
365-- CONSTRAIN CASE EXPRESSIONS
372 -> [(P.Canonical, C.Expr)]
375constrainCase env region expr branches tipe =
376 do exprVar <- mkVar Nothing
377 exprCon <- constrain env expr (VarN exprVar)
379 (branchInfo, branchExprCons) <-
380 unzip <$> mapM (branch (VarN exprVar)) branches
382 (vars, cons) <- pairCons region Error.CaseBranch varToCon branchInfo
384 return $ ex (exprVar : vars) (CAnd (exprCon : branchExprCons ++ cons))
386 branch patternType (pattern, branchExpr@(A.A branchRegion _)) =
387 do branchVar <- mkVar Nothing
388 scheme <- Pattern.infoToScheme <$> Pattern.constrain env pattern patternType
389 branchCon <- constrain env branchExpr (VarN branchVar)
391 ( (branchVar, branchRegion)
392 , CLet [scheme] branchCon
396 CEqual Error.Case region tipe (VarN var)
407 , _region :: R.Region
413 -> (Int -> R.Region -> Error.Hint)
414 -> (Variable -> Constraint)
415 -> [(Variable, R.Region)]
416 -> IO ([Variable], [Constraint])
417pairCons region pairHint varToCon items =
419 pairToCon (Pair index var1 var2 subregion) =
420 CEqual (pairHint index subregion) region (VarN var1) (VarN var2)
422 case collectPairs 2 items of
424 do var <- mkVar Nothing
425 return ([var], [varToCon var])
428 return (map fst items, map pairToCon pairs ++ [varToCon var])
431collectPairs :: Int -> [(Variable, R.Region)] -> Maybe ([Pair], Variable)
432collectPairs index items =
440 (var,_) : rest@((var',region) : _) ->
441 do (pairs, summaryVar) <- collectPairs (index+1) rest
442 return (Pair index var var' region : pairs, summaryVar)
449expandPattern :: C.Def -> [C.Def]
450expandPattern def@(C.Def facts lpattern expr maybeType) =
452 (A.A patternRegion pattern) =
460 mainDef : map toDef vars
463 P.boundVarList lpattern
466 Text.intercalate "$" ("" : vars)
469 A.A patternRegion (P.Var name)
472 A.A patternRegion (C.localVar name)
475 C.Def facts (pvar combinedName) expr maybeType
480 C.Case (localVar combinedName) [(lpattern, localVar name)]
482 C.Def facts (pvar name) (A.A patternRegion extract) Nothing
486-- CONSTRAIN DEFINITIONS
491 { iSchemes :: [Scheme]
492 , iRigid :: [Variable]
493 , iFlex :: [Variable]
494 , iHeaders :: Map.Map Text (A.Located Type)
500constrainDef :: Env.Env -> Info -> C.Def -> IO Info
501constrainDef env info (C.Def defRegion (A.A patternRegion pattern) expr maybeTipe) =
502 case (pattern, maybeTipe) of
503 (P.Var name, Nothing) ->
504 constrainUnannotatedDef env patternRegion name expr info
506 (P.Var name, Just (A.A _ tipe)) ->
507 constrainAnnotatedDef env defRegion patternRegion name expr tipe info
510 error "canonical definitions must not have complex patterns as names in the contstraint generation phase"
513constrainUnannotatedDef
520constrainUnannotatedDef env patternRegion name expr info =
521 do v <- mkVar Nothing
523 defCon <- constrain env expr tipe
525 { iFlex = v : iFlex info
526 , iHeaders = Map.insert name (A.A patternRegion tipe) (iHeaders info)
527 , iC2 = defCon /\ iC2 info
540constrainAnnotatedDef env defRegion region name expr tipe info =
541 do (flexType, flexVars) <- Env.instantiateType Flex env tipe
545 { _rigidQuantifiers = []
546 , _flexibleQuantifiers = Map.elems flexVars
547 , _constraint = CTrue
548 , _header = Map.singleton name (A.A region flexType)
551 defCon <- constrainAnnDefHelp expr tipe (ArgInfo name defRegion env [] [])
554 { iSchemes = scheme : iSchemes info
555 , iC1 = iC1 info /\ defCon
564 , _args :: [(P.Canonical, Type)]
565 , _vars :: [Variable]
569constrainAnnDefHelp :: C.Expr -> ST.Canonical -> ArgInfo -> IO Constraint
570constrainAnnDefHelp expr tipe (ArgInfo name defRegion env args vars) =
572 (A.A _ (C.Lambda arg result), ST.Lambda argType resultType) ->
573 do (rigidArgType, newVars) <- Env.instantiateType Rigid env argType
575 constrainAnnDefHelp result resultType $
579 , _env = Env.addValues newVars env
580 , _args = (arg, rigidArgType) : args
581 , _vars = Map.elems newVars ++ vars
585 do (rigidType, newVars) <- Env.instantiateType Rigid env tipe
587 let finalEnv = Env.addValues newVars env
588 let finalArgs = reverse args
589 let rigidVars = Map.elems newVars ++ vars
591 (Pattern.Info headers argVars argCons) <-
592 Pattern.joinInfos <$> mapM (uncurry (Pattern.constrain finalEnv)) finalArgs
594 resultVar <- mkVar Nothing
595 let resultType = VarN resultVar
596 defCon <- constrain finalEnv expr resultType
598 let sharedArity = length args
599 let typeArity = sharedArity + length (ST.collectLambdas tipe) - 1
600 let argsArity = sharedArity + length (fst (C.collectLambdas expr))
601 let hint = Error.ReturnType name typeArity argsArity region
603 CEqual hint defRegion rigidType resultType
605 return $ forall rigidVars $ ex (resultVar : argVars) $ CLet [monoscheme headers] $
606 CAnd [ argCons, defCon, resultCon ]
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