1{-# OPTIONS_GHC -Wall #-}
2module Type.Constrain.Expression where
4import Control.Applicative ((<$>))
5import qualified Control.Monad as Monad
6import qualified Data.List as List
7import qualified Data.Map as Map
9import qualified AST.Expression.General as E
10import qualified AST.Expression.Canonical as Canonical
11import qualified AST.Literal as Lit
12import qualified AST.Pattern as P
13import qualified AST.Type as ST
14import qualified AST.Variable as V
15import qualified Reporting.Annotation as A
16import qualified Reporting.Error.Type as Error
17import qualified Reporting.Region as R
18import qualified Type.Constrain.Literal as Literal
19import qualified Type.Constrain.Pattern as Pattern
20import qualified Type.Environment as Env
21import qualified Type.Fragment as Fragment
22import Type.Type hiding (Descriptor(..))
30constrain env (A.A region expression) tipe =
31 let list t = Env.get env Env.types "List" <| t
32 (===) = CEqual Error.None region
33 (<?) = CInstance region
37 Literal.constrain env region lit tipe
39 E.GLShader _uid _src gltipe ->
44 Env.get env Env.types "WebGL.Shader" <| a <| u <| v
47 Env.get env Env.types . Lit.glTipeName
49 makeRec accessor baseRec =
50 let decls = accessor gltipe
52 if Map.size decls == 0
54 else record (Map.map (\t -> [glTipe t]) decls) baseRec
56 attribute = makeRec Lit.attribute attr
57 uniform = makeRec Lit.uniform unif
58 varying = makeRec Lit.varying (termN EmptyRecord1)
60 return (tipe === shaderTipe attribute uniform varying)
63 let name = V.toString var
65 return (if name == E.saveEnvName then CSaveEnv else name <? tipe)
67 E.Range lowExpr highExpr ->
69 do lowCon <- constrain env lowExpr n
70 highCon <- constrain env highExpr n
71 return $ CAnd [lowCon, highCon, list n === tipe]
73 E.ExplicitList exprs ->
74 constrainList env region exprs tipe
76 E.Binop op leftExpr rightExpr ->
77 constrainBinop env region op leftExpr rightExpr tipe
79 E.Lambda pattern body ->
82 do fragment <- Pattern.constrain env pattern argType
83 bodyCon <- constrain env body resType
85 ex (Fragment.vars fragment)
86 (CLet [monoscheme (Fragment.typeEnv fragment)]
87 (Fragment.typeConstraint fragment /\ bodyCon)
89 return $ con /\ tipe === (argType ==> resType)
91 E.App func@(A.A funcRegion _) arg@(A.A argRegion _) ->
92 do argVar <- variable Flexible
93 argCon <- constrain env arg (varN argVar)
95 funcVar <- variable Flexible
96 funcCon <- constrain env func (varN funcVar)
98 argVar' <- variable Flexible
99 resultVar <- variable Flexible
101 return $ ex [argVar,argVar',resultVar] $ CAnd $
104 , CEqual (Error.ExtraArgument funcRegion) region
106 (varN argVar' ==> varN resultVar)
107 , CEqual (Error.BadArgument argRegion) region (varN argVar') (varN argVar)
108 , tipe === varN resultVar
111 E.MultiIf branches ->
112 constrainIf env region branches tipe
114 E.Case expr branches ->
115 constrainCase env region expr branches tipe
118 do vars <- Monad.forM exprs $ \_ -> variable Flexible
119 let pairs = zip exprs (map varN vars)
120 (ctipe, cs) <- Monad.foldM step (tipe, CTrue) (reverse pairs)
121 return $ ex vars (cs /\ name <? ctipe)
124 do c' <- constrain env e x
125 return (x ==> t, c /\ c')
127 E.Access expr label ->
129 constrain env expr (record (Map.singleton label [tipe]) t)
131 E.Remove expr label ->
133 constrain env expr (record (Map.singleton label [t]) tipe)
135 E.Insert expr label value ->
136 exists $ \valueType ->
137 exists $ \recordType ->
138 do valueCon <- constrain env value valueType
139 recordCon <- constrain env expr recordType
141 record (Map.singleton label [valueType]) recordType
142 return (CAnd [valueCon, recordCon, tipe === newRecordType])
144 E.Modify expr fields ->
146 do oldVars <- Monad.forM fields $ \_ -> variable Flexible
147 let oldFields = ST.fieldMap (zip (map fst fields) (map varN oldVars))
148 cOld <- ex oldVars <$> constrain env expr (record oldFields t)
150 newVars <- Monad.forM fields $ \_ -> variable Flexible
151 let newFields = ST.fieldMap (zip (map fst fields) (map varN newVars))
152 let cNew = tipe === record newFields t
154 cs <- Monad.zipWithM (constrain env) (map snd fields) (map varN newVars)
156 return $ cOld /\ ex newVars (CAnd (cNew : cs))
159 do vars <- Monad.forM fields (\_ -> variable Flexible)
165 let fields' = ST.fieldMap (zip (map fst fields) (map varN vars))
166 let recordType = record fields' (termN EmptyRecord1)
167 return (ex vars (CAnd (fieldCons ++ [tipe === recordType])))
170 do bodyCon <- constrain env body tipe
172 (Info schemes rqs fqs headers c2 c1) <-
175 (Info [] [] [] Map.empty CTrue CTrue)
176 (concatMap expandPattern defs)
178 let letScheme = [ Scheme rqs fqs (CLet [monoscheme headers] c2) headers ]
180 return $ CLet schemes (CLet letScheme (c1 /\ bodyCon))
188 constrain env expr tipe
191 constrain env expr tipe
204constrainBinop env region op leftExpr@(A.A leftRegion _) rightExpr@(A.A rightRegion _) tipe =
205 do leftVar <- variable Flexible
206 rightVar <- variable Flexible
208 leftCon <- constrain env leftExpr (varN leftVar)
209 rightCon <- constrain env rightExpr (varN rightVar)
211 leftVar' <- variable Flexible
212 rightVar' <- variable Flexible
213 answerVar <- variable Flexible
215 let opType = varN leftVar' ==> varN rightVar' ==> varN answerVar
218 ex [leftVar,rightVar,leftVar',rightVar',answerVar] $ CAnd $
221 , CInstance region (V.toString op) opType
222 , CEqual (Error.BinopLeft op leftRegion) region (varN leftVar') (varN leftVar)
223 , CEqual (Error.BinopRight op rightRegion) region (varN rightVar') (varN rightVar)
224 , CEqual (Error.Binop op) region tipe (varN answerVar)
236constrainList env region exprs tipe =
237 do (exprInfo, exprCons) <-
238 unzip <$> mapM elementConstraint exprs
240 let pairwiseCons = pairwiseConstraints 2 exprInfo
243 ex (map fst exprInfo)
244 (CAnd (exprCons ++ pairwiseCons))
247 Env.get env Env.types "List" <| t
249 elementConstraint expr@(A.A region' _) =
250 do var <- variable Flexible
251 con <- constrain env expr (varN var)
252 return ( (var, region'), con )
254 pairwiseConstraints n exprInfo =
260 [ CEqual Error.List region tipe (list (varN var)) ]
262 (var,_) : (var',region') : rest ->
264 hint = Error.ListElement n region'
265 con = CEqual hint region (varN var) (varN var')
267 con : pairwiseConstraints (n+1) ((var', region') : rest)
270-- CONSTRAIN IF EXPRESSIONS
275 -> [(Canonical.Expr, Canonical.Expr)]
278constrainIf env region branches tipe =
279 do (branchInfo, branchExprCons) <-
280 unzip <$> mapM constrainBranch branches
283 ex (map fst branchInfo)
284 (CAnd (branchExprCons ++ branchCons branchInfo))
286 bool = Env.get env Env.types "Bool"
288 constrainBranch (cond, expr@(A.A branchRegion _)) =
289 do branchVar <- variable Flexible
290 condCon <- constrain env cond bool
291 exprCon <- constrain env expr (varN branchVar)
293 ( (branchVar, branchRegion)
297 branchCons branchInfo =
299 [(thenVar, _), (elseVar, _)] ->
300 [ CEqual Error.IfBranches region (varN thenVar) (varN elseVar)
301 , CEqual Error.If region tipe (varN thenVar)
305 buildBranchCons 2 branchInfo
307 buildBranchCons n branchInfo =
313 [ CEqual Error.If region tipe (varN var) ]
315 (var,_) : (var',region') : rest ->
317 hint = Error.MultiIfBranch n region'
318 con = CEqual hint region (varN var) (varN var')
320 con : buildBranchCons (n+1) ((var', region') : rest)
323-- CONSTRAIN CASE EXPRESSIONS
329 -> [(P.CanonicalPattern, Canonical.Expr)]
332constrainCase env region expr branches tipe =
333 do exprVar <- variable Flexible
335 exprCon <- constrain env expr (varN exprVar)
337 (branchInfo, branchExprCons) <-
338 unzip <$> mapM (branch (varN exprVar)) branches
341 ex (exprVar : map fst branchInfo)
342 (CAnd (exprCon : branchExprCons ++ branchCons 2 branchInfo))
344 branch patternType (pattern, branchExpr@(A.A branchRegion _)) =
345 do branchVar <- variable Flexible
346 fragment <- Pattern.constrain env pattern patternType
347 branchCon <- constrain env branchExpr (varN branchVar)
349 ( (branchVar, branchRegion)
350 , CLet [Fragment.toScheme fragment] branchCon
353 branchCons n branchInfo =
359 [ CEqual Error.Case region tipe (varN var) ]
361 (var,_) : (var',region') : rest ->
363 hint = Error.CaseBranch n region'
364 con = CEqual hint region (varN var) (varN var')
366 con : branchCons (n+1) ((var', region') : rest)
371expandPattern :: Canonical.Def -> [Canonical.Def]
372expandPattern def@(Canonical.Definition lpattern expr maybeType) =
373 let (A.A patternRegion pattern) = lpattern
380 mainDef : map toDef vars
382 vars = P.boundVarList lpattern
384 combinedName = "$" ++ concat vars
387 A.A patternRegion (P.Var name)
390 A.A patternRegion (E.localVar name)
392 mainDef = Canonical.Definition (pvar combinedName) expr maybeType
396 E.Case (localVar combinedName) [(lpattern, localVar name)]
398 Canonical.Definition (pvar name) (A.A patternRegion extract) Nothing
401-- CONSTRAIN DEFINITIONS
404 { iSchemes :: [TypeScheme]
405 , iRigid :: [Variable]
406 , iFlex :: [Variable]
407 , iHeaders :: Map.Map String Type
408 , iC2 :: TypeConstraint
409 , iC1 :: TypeConstraint
413constrainDef :: Env.Environment -> Info -> Canonical.Def -> IO Info
414constrainDef env info (Canonical.Definition (A.A _ pattern) expr maybeTipe) =
415 let qs = [] -- should come from the def, but I'm not sure what would live there...
417 case (pattern, maybeTipe) of
418 (P.Var name, Just tipe) ->
419 constrainAnnotatedDef env info qs name expr tipe
421 (P.Var name, Nothing) ->
422 constrainUnannotatedDef env info qs name expr
424 _ -> error ("problem in constrainDef with " ++ show pattern)
435constrainAnnotatedDef env info qs name expr tipe =
436 do -- Some mistake may be happening here. Currently, qs is always [].
437 rigidVars <- Monad.forM qs (\_ -> variable Rigid)
439 flexiVars <- Monad.forM qs (\_ -> variable Flexible)
441 let inserts = zipWith (\arg typ -> Map.insert arg (varN typ)) qs flexiVars
443 let env' = env { Env.value = List.foldl' (\x f -> f x) (Env.value env) inserts }
445 (vars, typ) <- Env.instantiateType env tipe Map.empty
449 { rigidQuantifiers = []
450 , flexibleQuantifiers = flexiVars ++ vars
452 , header = Map.singleton name typ
455 c <- constrain env' expr typ
458 { iSchemes = scheme : iSchemes info
459 , iC1 = fl rigidVars c /\ iC1 info
463constrainUnannotatedDef
470constrainUnannotatedDef env info qs name expr =
471 do -- Some mistake may be happening here. Currently, qs is always [].
472 rigidVars <- Monad.forM qs (\_ -> variable Rigid)
474 v <- variable Flexible
478 let inserts = zipWith (\arg typ -> Map.insert arg (varN typ)) qs rigidVars
480 let env' = env { Env.value = List.foldl' (\x f -> f x) (Env.value env) inserts }
482 c <- constrain env' expr tipe
485 { iRigid = rigidVars ++ iRigid info
486 , iFlex = v : iFlex info
487 , iHeaders = Map.insert name tipe (iHeaders info)
488 , iC2 = c /\ iC2 info
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