2 % (c) The GRASP/AQUA Project, Glasgow University, 1993-1998
4 \section[SpecEnv]{Specialisation info about an @Id@}
9 emptySpecEnv, isEmptySpecEnv,
10 specEnvValues, specEnvToList, specEnvFromList,
11 addToSpecEnv, lookupSpecEnv, substSpecEnv
14 #include "HsVersions.h"
19 import Type ( Type, GenType, fullSubstTy, substTyVar )
20 import Unify ( unifyTyListsX, matchTys )
23 import Util ( assertPanic )
28 %************************************************************************
32 %************************************************************************
37 | SpecEnv [([TyVar], -- Really a set, but invariably small,
42 specEnvValues :: SpecEnv value -> [value]
43 specEnvValues EmptySE = []
44 specEnvValues (SpecEnv alist) = [val | (_,_,val) <- alist]
46 specEnvToList :: SpecEnv value -> [([TyVar], [Type], value)]
47 specEnvToList EmptySE = []
48 specEnvToList (SpecEnv alist) = alist
50 specEnvFromList :: [([TyVar], [Type], value)] -> SpecEnv value
51 -- Assumes the list is in appropriate order
52 specEnvFromList [] = EmptySE
53 specEnvFromList alist = SpecEnv alist
56 In some SpecEnvs overlap is prohibited; that is, no pair of templates unify.
58 In others, overlap is permitted, but only in such a way that one can make
59 a unique choice when looking up. That is, overlap is only permitted if
60 one template matches the other, or vice versa. So this is ok:
68 If overlap is permitted, the list is kept most specific first, so that
69 the first lookup is the right choice.
72 For now we just use association lists.
75 emptySpecEnv :: SpecEnv a
76 emptySpecEnv = EmptySE
78 isEmptySpecEnv EmptySE = True
79 isEmptySpecEnv _ = False
82 @lookupSpecEnv@ looks up in a @SpecEnv@, using a one-way match. Since the env is kept
83 ordered, the first match must be the only one.
84 The thing we are looking up can have an
85 arbitrary "flexi" part.
88 lookupSpecEnv :: SDoc -- For error report
89 -> SpecEnv value -- The envt
90 -> [GenType flexi] -- Key
91 -> Maybe (TyVarEnv (GenType flexi), value)
93 lookupSpecEnv doc EmptySE key = Nothing
94 lookupSpecEnv doc (SpecEnv alist) key
98 find ((tpl_tyvars, tpl, val) : rest)
99 = case matchTys tpl_tyvars tpl key of
101 Just (subst, leftovers) -> ASSERT( null leftovers )
105 @addToSpecEnv@ extends a @SpecEnv@, checking for overlaps.
107 A boolean flag controls overlap reporting.
109 True => overlap is permitted, but only if one template matches the other;
110 not if they unify but neither is
113 addToSpecEnv :: Bool -- True <=> overlap permitted
114 -> SpecEnv value -- Envt
115 -> [TyVar] -> [Type] -> value -- New item
116 -> MaybeErr (SpecEnv value) -- Success...
117 ([Type], value) -- Failure: Offending overlap
119 addToSpecEnv overlap_ok spec_env ins_tvs ins_tys value
121 EmptySE -> returnMaB (SpecEnv [ins_item])
122 SpecEnv alist -> insert alist `thenMaB` \ alist' ->
123 returnMaB (SpecEnv alist')
125 ins_item = (ins_tvs, ins_tys, value)
127 insert [] = returnMaB [ins_item]
128 insert alist@(cur_item@(tpl_tvs, tpl_tys, val) : rest)
131 -- (a) they are the same, or
132 -- (b) they unify, and any sort of overlap is prohibited,
133 -- (c) they unify but neither is more specific than t'other
135 || (unifiable && not overlap_ok)
136 || (unifiable && not (ins_item_more_specific || cur_item_more_specific))
137 = failMaB (tpl_tys, val)
139 -- New item is an instance of current item, so drop it here
140 | ins_item_more_specific = returnMaB (ins_item : alist)
142 -- Otherwise carry on
143 | otherwise = insert rest `thenMaB` \ rest' ->
144 returnMaB (cur_item : rest')
146 unifiable = maybeToBool (unifyTyListsX (ins_tvs ++ tpl_tvs) tpl_tys ins_tys)
147 ins_item_more_specific = maybeToBool (matchTys tpl_tvs tpl_tys ins_tys)
148 cur_item_more_specific = maybeToBool (matchTys ins_tvs ins_tys tpl_tys)
149 identical = ins_item_more_specific && cur_item_more_specific
152 Finally, during simplification we must apply the current substitution to
156 substSpecEnv :: TyVarEnv Type -> IdOrTyVarSet
157 -> (TyVarEnv Type -> IdOrTyVarSet -> val -> val)
158 -> SpecEnv val -> SpecEnv val
159 substSpecEnv ty_subst in_scope val_fn EmptySE = EmptySE
160 substSpecEnv ty_subst in_scope val_fn (SpecEnv alist)
161 = SpecEnv (map subst alist)
163 subst (tpl_tyvars, tpl_tys, val)
165 map (fullSubstTy ty_subst' in_scope') tpl_tys,
166 val_fn ty_subst' in_scope' val)
168 (ty_subst', in_scope', tpl_tyvars') = go ty_subst in_scope [] tpl_tyvars
170 go s i acc [] = (s, i, reverse acc)
171 go s i acc (tv:tvs) = case substTyVar s i tv of
172 (s', i', tv') -> go s' i' (tv' : acc) tvs