-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathConstraint.hs
237 lines (177 loc) · 7.85 KB
/
Constraint.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE TypeSynonymInstances #-}
module Constraint where
import Text.Groom
import Debug.Trace
import qualified Data.Set as Set
import qualified Data.Map as Map
import Control.Monad.Writer
import Control.Monad.Except
import Control.Monad.Identity
import Data
import Environment
type TypeErrorM a = ExceptT TypeError Identity a
runTypeErrorM = runIdentity . runExceptT
type Solve a = TypeErrorM a
newtype Subst a b = Subst (Map.Map a b)
deriving (Show, Eq, Ord)
emptySubst = Subst Map.empty
(Subst s1) `compose` (Subst s2) =
Subst $ Map.map (apply (Subst s1)) s2 `Map.union` s1
v `bind` t | Set.singleton v == fv t = return $ emptySubst
| occurCheck v t = throwError $ InfinitType (show v) (show t)
| otherwise = return $ Subst $ Map.singleton v t
occurCheck v t = v `Set.member` fv t
class Substitutable var value contr | var -> value where
apply :: Subst var value -> contr -> contr
fv :: contr -> Set.Set var
-- Substitution for type variable
instance Substitutable TVar Type Type where
apply _ all@(TyCon _ _) = all
apply sub (TyArr t1 t2 fp) = TyArr (sub `apply` t1) (sub `apply` t2) fp
apply sub (TyApp t1 t2 fp) = TyApp (sub `apply` t1) (sub `apply` t2) fp
apply (Subst s) all@(TyVar var fp) = modifyFp (Map.findWithDefault all var s) fp
fv (TyCon _ _) = Set.empty
fv (TyArr t1 t2 _) = fv t1 `Set.union` fv t2
fv (TyApp t1 t2 _) = fv t1 `Set.union` fv t2
fv (TyVar var _) = Set.singleton var
instance Substitutable TVar Type TypeScm where
apply (Subst s) (TyForall as ty) = TyForall as $ apply s' ty
where s' = Subst $ foldr Map.delete s as
fv (TyForall as ty) = fv ty `Set.difference` Set.fromList as
instance Substitutable TVar Type FlppScm where
apply sub (FpForall as cs ty) = FpForall as (apply sub cs) (apply sub ty)
fv (FpForall as cs ty) = fv cs `Set.union` fv ty
instance Substitutable TVar Type FConstraint where
apply sub (t1, t2) = (sub `apply` t1, sub `apply` t2)
fv (t1, t2) = fv t1 `Set.union` fv t2
instance Substitutable TVar Type Env where
apply s (Env e) = Env $ Map.map (apply s) e
fv (Env e) = fv $ Map.elems e
instance Substitutable TVar Type a => Substitutable TVar Type [a] where
apply = map . apply
fv = foldr (Set.union . fv) Set.empty
-- Substitution for flow properties variable
instance Substitutable LVar FP Type where
apply sub (TyCon name fp) = TyCon name $ sub `apply` fp
apply sub (TyArr t1 t2 fp) = TyArr (sub `apply` t1) (sub `apply` t2) (sub `apply` fp)
apply sub (TyApp t1 t2 fp) = TyArr (sub `apply` t1) (sub `apply` t2) (sub `apply` fp)
apply sub (TyVar var fp) = TyVar var (sub `apply` fp)
fv (TyCon _ fp) = fv fp
fv (TyArr t1 t2 fp) = fv t1 `Set.union` fv t2 `Set.union` fv fp
fv (TyApp t1 t2 fp) = fv t1 `Set.union` fv t2 `Set.union` fv fp
fv (TyVar _ fp) = fv fp
instance Substitutable LVar FP TypeScm where
apply s (TyForall as ty) = TyForall as $ apply s ty
fv (TyForall as ty) = fv ty
instance Substitutable LVar FP FlppScm where
apply (Subst s) (FpForall as cs ty) = FpForall as (apply sub' cs) (apply sub' ty)
where sub' = Subst $ foldr Map.delete s as
fv (FpForall as cs ty) = fv cs `Set.union` fv ty `Set.difference` Set.fromList as
instance Substitutable LVar FP FP where
apply _ (FPSet lset) = FPSet lset
apply (Subst s) (FPVar var) = Map.findWithDefault (FPVar var) var s
fv (FPSet lset) = Set.empty
fv (FPVar var) = Set.singleton var
instance Substitutable LVar FP TConstraint where
apply s (f1, f2) = (s `apply` f1, s `apply` f2)
fv (f1, f2) = fv f1 `Set.union` fv f2
instance Substitutable LVar FP a => Substitutable LVar FP [a] where
apply = map . apply
fv = foldr (Set.union . fv) Set.empty
instance Substitutable LVar FP Env where
apply s (Env e) = Env $ Map.map (apply s) e
fv (Env e) = fv $ Map.elems e
instance Substitutable LVar FP TypedProgram where
apply s (loc, ty) = (loc, apply s ty)
fv (_, ty) = fv ty
instance Substitutable TVar Type TypedProgram where
apply s (loc, ty) = (loc, apply s ty)
fv (_, ty) = fv ty
-- Solve type constraints
unify :: Type -> Type -> Solve (Subst TVar Type)
unify t1 t2 | t1 `typeEq` t2 = return emptySubst
unify (TyVar v _) t = v `bind` t
unify t (TyVar v _) = v `bind` t
unify (TyArr t1 t2 _) (TyArr t3 t4 _) = unifyMany [t1, t2] [t3, t4]
unify (TyApp t1 t2 _) (TyApp t3 t4 _) = unifyMany [t1, t2] [t3, t4]
unify t1 t2 = throwError $ UnificationFail t1 t2
unifyMany :: [Type] -> [Type] -> Solve (Subst TVar Type)
unifyMany [] [] = return emptySubst
unifyMany (x:xs) (y:ys) = do
s1 <- unify x y
s2 <- unifyMany (s1 `apply` xs) (s1 `apply` ys)
return $ s2 `compose` s1
unifyMany _ _ = throwError $ UnificationMismatch
solver :: (Subst TVar Type, [TConstraint]) -> Solve (Subst TVar Type)
solver (su, cs) = case cs of
[] -> return su
(t1,t2):xs -> do
s <- unify t1 t2
solver (s `compose` su, apply s xs)
runSolve :: [TConstraint] -> Either TypeError (Subst TVar Type)
runSolve cs = runTypeErrorM $ solver st
where st = (emptySubst, cs)
-- Solve flow properties constraints
type Relation = Map.Map LVar (Set.Set LVar, Set.Set Label)
runGen :: [FConstraint] -> Either TypeError Relation
runGen = runTypeErrorM . genMany
(<.>) :: Relation -> Relation -> Relation
(<.>) = Map.unionWith (\(x1, y1) (x2, y2) -> (x1 `Set.union` x2, y1 `Set.union` y2))
emptyRelation = Map.empty
genMany :: [FConstraint] -> TypeErrorM Relation
genMany (x:xs) = do
m1 <- gen x
m2 <- genMany xs
return $ m1 <.> m2
genMany [] = return $ emptyRelation
gen :: FConstraint -> TypeErrorM Relation
gen (c1, c2) = do
case (c1, c2) of
(TyCon t1 f1, TyCon t2 f2) | t1 == t2 -> subset f1 f2
(TyArr t1 t2 f1, TyArr t3 t4 f2) -> do
r1 <- genMany [(t3, t1), (t2, t4)]
r2 <- subset f1 f2
return $ r1 <.> r2
(TyApp t1 t2 f1, TyApp t3 t4 f2) -> do
r1 <- genMany [(t1, t3), (t2, t4)]
r2 <- subset f1 f2
return $ r1 <.> r2
(TyVar _ f1, x) -> subset f1 (ty2fp x)
(x, TyVar _ f2) -> subset (ty2fp x) f2
_ -> throwError $ GenerateFPConstraintFail c1 c2
subset :: FP -> FP -> TypeErrorM Relation
subset f1 f2 = case (f1, f2) of
(FPVar v1, FPVar v2) ->
return $ Map.singleton v2 (Set.singleton v1, Set.empty)
(FPSet s1, FPVar v2) ->
return $ Map.singleton v2 (Set.empty, s1)
(FPSet s1, FPSet s2) | Set.isSubsetOf s1 s2 ->
return $ emptyRelation
_ -> throwError $ IncompatibleFPConstraints f1 f2
extendSubst :: Subst LVar FP -> LVar -> FP -> Subst LVar FP
extendSubst (Subst s) x (FPSet l) = Subst $
Map.insert x (FPSet $ l `Set.union` l') s
where (FPSet l') = Map.findWithDefault (FPSet Set.empty) x s
update :: Relation -> LVar -> (Set.Set LVar, Subst LVar FP) -> (Set.Set LVar, Subst LVar FP)
update relation x (visit, sub) =
case x `Set.member` visit of
True -> (visit, sub)
False -> case Map.lookup x relation of
Just (sons, fp) ->
let (visit', sub') = Set.foldr
(update relation)
(Set.insert x visit, extendSubst sub x (FPSet fp))
sons
in (visit', Set.foldr (\y all@(Subst sub) ->
case Map.lookup y sub of
Just lset -> extendSubst all x lset
Nothing -> all) sub' sons)
Nothing -> (visit, sub)
accumulate :: Relation -> Subst LVar FP
accumulate relation = foldr (\x y -> snd $
update relation x (Set.empty, y))
emptySubst $ Map.keys relation