2 % (c) The GRASP/AQUA Project, Glasgow University, 1993-1995
4 \section[Specialise]{Stamping out overloading, and (optionally) polymorphism}
7 #include "HsVersions.h"
14 isUnboxedSpecialisation,
19 argTysMatchSpecTys_error,
23 Maybe(..), Pretty(..), UniType
27 import Bag ( Bag, isEmptyBag, bagToList )
28 import FiniteMap ( FiniteMap, emptyFM, addListToFM_C,
29 plusFM_C, keysFM, lookupWithDefaultFM
31 import Id ( mkSameSpecCon, getIdUniType,
32 isDictFunId, isConstMethodId_maybe,
33 isDefaultMethodId_maybe,
41 @specialiseCallTys@ works out which type args don't need to be specialised on,
42 based on flags, the overloading constraint vector, and the types.
45 specialiseCallTys :: Bool -- Specialise on all type args
46 -> Bool -- Specialise on unboxed type args
47 -> Bool -- Specialise on overloaded type args
48 -> ConstraintVector -- Tells which type args are overloaded
49 -> [UniType] -- Type args
50 -> [Maybe UniType] -- Nothings replace non-specialised type args
52 specialiseCallTys True _ _ cvec tys
54 specialiseCallTys False spec_unboxed spec_overloading cvec tys
55 = zipWith spec_ty_other cvec tys
57 spec_ty_other c ty | (spec_unboxed && isUnboxedDataType ty)
58 || (spec_overloading && c)
64 @getIdOverloading@ grabs the type of an Id, and returns a
65 list of its polymorphic variables, and the initial segment of
66 its ThetaType, in which the classes constrain only type variables.
67 For example, if the Id's type is
69 forall a,b,c. Eq a -> Ord [a] -> tau
75 This seems curious at first. For a start, the type above looks odd,
76 because we usually only have dictionary args whose types are of
77 the form (C a) where a is a type variable. But this doesn't hold for
78 the functions arising from instance decls, which sometimes get
79 arguements with types of form (C (T a)) for some type constructor T.
81 Should we specialise wrt this compound-type dictionary? This is
82 a heuristic judgement, as indeed is the fact that we specialise wrt
83 only dictionaries. We choose *not* to specialise wrt compound dictionaries
84 because at the moment the only place they show up is in instance decls,
85 where they are simply plugged into a returned dictionary. So nothing is
86 gained by specialising wrt them.
89 getIdOverloading :: Id
90 -> ([TyVarTemplate], [(Class,TyVarTemplate)])
92 = (tyvars, tyvar_part_of theta)
94 (tyvars, theta, _) = splitType (getIdUniType id)
97 tyvar_part_of ((clas,ty) : theta) = case getTyVarTemplateMaybe ty of
99 Just tyvar -> (clas, tyvar) : tyvar_part_of theta
103 type ConstraintVector = [Bool] -- True for constrained tyvar, false otherwise
105 mkConstraintVector :: Id
108 mkConstraintVector id
109 = [tyvar `elem` constrained_tyvars | tyvar <- tyvars]
111 (tyvars, class_tyvar_pairs) = getIdOverloading id
112 constrained_tyvars = map snd class_tyvar_pairs -- May contain dups
116 isUnboxedSpecialisation :: [Maybe UniType] -> Bool
117 isUnboxedSpecialisation tys
120 is_unboxed (Just ty) = isUnboxedDataType ty
121 is_unboxed Nothing = False
124 @specialiseConstrTys@ works out which type args don't need to be
125 specialised on. We only speciailise on unboxed types.
128 specialiseConstrTys :: [UniType]
131 specialiseConstrTys tys
132 = map maybe_unboxed_ty tys
134 maybe_unboxed_ty ty = case isUnboxedDataType ty of
140 mkSpecialisedCon :: Id -> [UniType] -> Id
141 mkSpecialisedCon con tys
143 then mkSameSpecCon spec_tys con
146 spec_tys = specialiseConstrTys tys
147 spec_reqd = maybeToBool (firstJust spec_tys)
150 @argTysMatchSpecTys@ checks if a list of argument types is consistent
151 with a list of specialising types. An error message is returned if not.
153 argTysMatchSpecTys_error :: [Maybe UniType]
156 argTysMatchSpecTys_error spec_tys arg_tys
157 = if match spec_tys arg_tys
159 else Just (ppSep [ppStr "Spec and Arg Types Inconsistent:",
160 ppStr "spectys=", ppSep [pprMaybeTy PprDebug ty | ty <- spec_tys],
161 ppStr "argtys=", ppSep [pprParendUniType PprDebug ty | ty <- arg_tys]])
163 match (Nothing:spec_tys) (arg:arg_tys)
164 = not (isUnboxedDataType arg) &&
165 match spec_tys arg_tys
166 match (Just spec:spec_tys) (arg:arg_tys)
167 = case (cmpUniType True{-properly-} spec arg) of
168 EQ_ -> match spec_tys arg_tys
174 @pprSpecErrs@ prints error and warning information
175 about imported specialisations which do not exist.
178 pprSpecErrs :: FAST_STRING -- module name
179 -> (Bag (Id,[Maybe UniType])) -- errors
180 -> (Bag (Id,[Maybe UniType])) -- warnings
181 -> (Bag (TyCon,[Maybe UniType])) -- errors
184 pprSpecErrs this_mod spec_errs spec_warn spec_tyerrs
185 | not any_errs && not any_warn
190 ppStr "SPECIALISATION MESSAGES:",
191 ppAboves (map pp_module_specs use_modules)
194 any_errs = not (isEmptyBag spec_errs && isEmptyBag spec_tyerrs)
195 any_warn = not (isEmptyBag spec_warn)
197 mk_module_fm get_mod_data errs_bag
198 = addListToFM_C (++) emptyFM errs_list
200 errs_list = map get_mod_data (bagToList errs_bag)
202 tyspecs_fm = mk_module_fm get_ty_data spec_tyerrs
204 iderrs_fm = mk_module_fm (get_id_data True) spec_errs
205 idwarn_fm = mk_module_fm (get_id_data False) spec_warn
206 idspecs_fm = plusFM_C (++) idwarn_fm iderrs_fm
208 get_id_data is_err (id, tys)
209 = (mod_name, [(id_name, id, tys, is_err)])
211 (mod_name, id_name) = get_id_name id
214 | maybeToBool (isDefaultMethodId_maybe id)
217 | isDictFunId id || maybeToBool (isConstMethodId_maybe id)
218 = let get_mod = getInstIdModule id
219 use_mod = if from_prelude get_mod
227 get_ty_data (ty, tys)
228 = (mod_name, [(ty_name, ty, tys)])
230 (mod_name,ty_name) = getOrigName ty
233 = SLIT("Prelude") == (_SUBSTR_ mod 0 6)
235 module_names = concat [keysFM idspecs_fm, keysFM tyspecs_fm]
236 mods = map head (equivClasses _CMP_STRING_ module_names)
238 (unks, known) = if null mods
240 else case _CMP_STRING_ (head mods) _NIL_ of
241 EQ_ -> ([_NIL_], tail mods)
244 (prels, others) = partition from_prelude known
245 use_modules = unks ++ prels ++ others
247 pp_module_specs :: FAST_STRING -> Pretty
250 = ASSERT (null mod_tyspecs)
251 ppAboves (map (pp_idspec ty_sty (ppStr "UNKNOWN:")) mod_idspecs)
255 ppAboves (map (pp_tyspec ty_sty (pp_module mod)) mod_tyspecs),
256 ppAboves (map (pp_idspec ty_sty (pp_module mod)) mod_idspecs)
263 mod_tyspecs = lookupWithDefaultFM tyspecs_fm [] mod
264 mod_idspecs = lookupWithDefaultFM idspecs_fm [] mod
265 have_specs = not (null mod_tyspecs && null mod_idspecs)
266 ty_sty = PprInterface (error "SpecTyFuns:PprInterface:sw_chkr")
269 = ppBesides [ppPStr mod, ppStr ":"]
271 pp_tyspec :: PprStyle -> Pretty -> (FAST_STRING, TyCon, [Maybe UniType]) -> Pretty
273 pp_tyspec sty pp_mod (_, tycon, tys)
275 ppStr "{-# SPECIALIZE", ppStr "data",
276 pprNonOp PprForUser tycon, ppCat (map (pprParendUniType sty) spec_tys),
277 ppStr "#-}", ppStr "{- Essential -}"
280 tvs = getTyConTyVarTemplates tycon
281 (spec_args, tv_maybes) = unzip (map choose_ty (tvs `zip` tys))
282 spec_tys = map (mkForallTy (catMaybes tv_maybes)) spec_args
284 choose_ty (tv, Nothing) = (mkTyVarTemplateTy tv, Just tv)
285 choose_ty (tv, Just ty) = (ty, Nothing)
287 pp_idspec :: PprStyle -> Pretty -> (FAST_STRING, Id, [Maybe UniType], Bool) -> Pretty
289 pp_idspec sty pp_mod (_, id, tys, is_err)
292 ppStr "{-# SPECIALIZE",
294 pprUniType sty spec_ty,
295 ppStr "#-}", pp_essential ]
299 Just (cls, clsty, clsop) = const_method_maybe
300 (_, cls_str) = getOrigName cls
301 clsop_str = getClassOpString clsop
304 ppStr "{-# SPECIALIZE",
305 pp_clsop clsop_str, ppStr "::",
306 pprUniType sty spec_ty,
307 ppStr "#-} {- IN instance",
308 ppPStr cls_str, pprParendUniType sty clsty,
309 ppStr "-}", pp_essential ]
311 | is_default_method_id
313 Just (cls, clsop, _) = default_method_maybe
314 (_, cls_str) = getOrigName cls
315 clsop_str = getClassOpString clsop
320 ppStr "EXPLICIT METHOD REQUIRED",
321 pp_clsop clsop_str, ppStr "::",
322 pprUniType sty spec_ty,
323 ppStr "-}", pp_essential ]
327 ppStr "{-# SPECIALIZE",
328 pprNonOp PprForUser id, ppStr "::",
329 pprUniType sty spec_ty,
330 ppStr "#-}", pp_essential ]
332 spec_ty = specialiseTy (getIdUniType id) tys 100 -- HACK to drop all dicts!!!
333 pp_essential = if is_err then ppStr "{- Essential -}" else ppNil
335 const_method_maybe = isConstMethodId_maybe id
336 is_const_method_id = maybeToBool const_method_maybe
338 default_method_maybe = isDefaultMethodId_maybe id
339 is_default_method_id = maybeToBool default_method_maybe
341 pp_clsop str | isAvarop str
342 = ppBesides [ppLparen, ppPStr str, ppRparen]