2 % (c) The GRASP/AQUA Project, Glasgow University, 1993-1996
4 \section[Specialise]{Stamping out overloading, and (optionally) polymorphism}
7 #include "HsVersions.h"
11 SYN_IE(ConstraintVector),
13 isUnboxedSpecialisation,
18 argTysMatchSpecTys_error,
25 import CmdLineOpts ( opt_SpecialiseOverloaded, opt_SpecialiseUnboxed,
26 opt_SpecialiseAll, opt_PprUserLength
28 import Bag ( isEmptyBag, bagToList, Bag )
29 import Class ( GenClass{-instance NamedThing-}, SYN_IE(Class) )
30 import FiniteMap ( emptyFM, addListToFM_C, plusFM_C, keysFM,
33 import Id ( idType, isDictFunId,
34 isDefaultMethodId_maybe, mkSameSpecCon,
35 GenId {-instance NamedThing -}, SYN_IE(Id)
37 import Maybes ( maybeToBool, catMaybes, firstJust )
38 import Name ( OccName, pprOccName, modAndOcc, NamedThing(..) )
39 import Outputable ( PprStyle(..), Outputable(..) )
40 import PprType ( pprGenType, pprParendGenType, pprMaybeTy,
41 TyCon{-ditto-}, GenType{-ditto-}, GenTyVar
43 import Pretty -- plenty of it
44 import TyCon ( tyConTyVars, TyCon{-instance NamedThing-} )
45 import Type ( splitSigmaTy, mkTyVarTy, mkForAllTys,
46 getTyVar_maybe, isUnboxedType, SYN_IE(Type)
48 import TyVar ( GenTyVar{-instance Eq-}, SYN_IE(TyVar) )
49 import Unique ( Unique{-instance Eq-} )
50 import Util ( equivClasses, zipWithEqual, cmpPString,
51 assertPanic, panic{-ToDo:rm-}
55 cmpType = panic "SpecUtils.cmpType (ToDo: get rid of)"
56 getInstIdModule = panic "SpecUtils.getInstIdModule (ToDo)"
59 @specialiseCallTys@ works out which type args don't need to be specialised on,
60 based on flags, the overloading constraint vector, and the types.
63 specialiseCallTys :: ConstraintVector -- Tells which type args are overloaded
64 -> [Type] -- Type args
65 -> [Maybe Type] -- Nothings replace non-specialised type args
67 specialiseCallTys cvec tys
68 | opt_SpecialiseAll = map Just tys
69 | otherwise = zipWithEqual "specialiseCallTys" spec_ty_other cvec tys
71 spec_ty_other c ty | (opt_SpecialiseUnboxed && isUnboxedType ty) ||
72 (opt_SpecialiseOverloaded && c)
78 @getIdOverloading@ grabs the type of an Id, and returns a
79 list of its polymorphic variables, and the initial segment of
80 its ThetaType, in which the classes constrain only type variables.
81 For example, if the Id's type is
83 forall a,b,c. Eq a -> Ord [a] -> tau
89 This seems curious at first. For a start, the type above looks odd,
90 because we usually only have dictionary args whose types are of
91 the form (C a) where a is a type variable. But this doesn't hold for
92 the functions arising from instance decls, which sometimes get
93 arguements with types of form (C (T a)) for some type constructor T.
95 Should we specialise wrt this compound-type dictionary? This is
96 a heuristic judgement, as indeed is the fact that we specialise wrt
97 only dictionaries. We choose *not* to specialise wrt compound dictionaries
98 because at the moment the only place they show up is in instance decls,
99 where they are simply plugged into a returned dictionary. So nothing is
100 gained by specialising wrt them.
103 getIdOverloading :: Id
104 -> ([TyVar], [(Class,TyVar)])
106 = (tyvars, tyvar_part_of theta)
108 (tyvars, theta, _) = splitSigmaTy (idType id)
110 tyvar_part_of [] = []
111 tyvar_part_of ((c,ty):theta) = case (getTyVar_maybe ty) of
113 Just tv -> (c, tv) : tyvar_part_of theta
117 type ConstraintVector = [Bool] -- True for constrained tyvar, false otherwise
121 isUnboxedSpecialisation :: [Maybe Type] -> Bool
122 isUnboxedSpecialisation tys
125 is_unboxed (Just ty) = isUnboxedType ty
126 is_unboxed Nothing = False
129 @specialiseConstrTys@ works out which type args don't need to be
130 specialised on. We only speciailise on unboxed types.
133 specialiseConstrTys :: [Type]
136 specialiseConstrTys tys
137 = map maybe_unboxed_ty tys
139 maybe_unboxed_ty ty = case isUnboxedType ty of
145 mkSpecialisedCon :: Id -> [Type] -> Id
146 mkSpecialisedCon con tys
148 then mkSameSpecCon spec_tys con
151 spec_tys = specialiseConstrTys tys
152 spec_reqd = maybeToBool (firstJust spec_tys)
155 @argTysMatchSpecTys@ checks if a list of argument types is consistent
156 with a list of specialising types. An error message is returned if not.
158 argTysMatchSpecTys_error :: [Maybe Type]
161 argTysMatchSpecTys_error spec_tys arg_tys
162 = if match spec_tys arg_tys
164 else Just (sep [ptext SLIT("Spec and Arg Types Inconsistent:"),
165 ptext SLIT("spectys="), sep [pprMaybeTy PprDebug ty | ty <- spec_tys],
166 ptext SLIT("argtys="), sep [pprParendGenType PprDebug ty | ty <- arg_tys]])
168 match (Nothing:spec_tys) (arg:arg_tys)
169 = not (isUnboxedType arg) &&
170 match spec_tys arg_tys
171 match (Just spec:spec_tys) (arg:arg_tys)
172 = case (cmpType True{-properly-} spec arg) of
173 EQ_ -> match spec_tys arg_tys
179 @pprSpecErrs@ prints error and warning information
180 about imported specialisations which do not exist.
183 pprSpecErrs :: FAST_STRING -- module name
184 -> (Bag (Id,[Maybe Type])) -- errors
185 -> (Bag (Id,[Maybe Type])) -- warnings
186 -> (Bag (TyCon,[Maybe Type])) -- errors
189 pprSpecErrs this_mod spec_errs spec_warn spec_tyerrs
190 | not any_errs && not any_warn
195 ptext SLIT("SPECIALISATION MESSAGES:"),
196 vcat (map pp_module_specs use_modules)
199 any_errs = not (isEmptyBag spec_errs && isEmptyBag spec_tyerrs)
200 any_warn = not (isEmptyBag spec_warn)
202 mk_module_fm get_mod_data errs_bag
203 = addListToFM_C (++) emptyFM errs_list
205 errs_list = map get_mod_data (bagToList errs_bag)
207 tyspecs_fm = mk_module_fm get_ty_data spec_tyerrs
209 iderrs_fm = mk_module_fm (get_id_data True) spec_errs
210 idwarn_fm = mk_module_fm (get_id_data False) spec_warn
211 idspecs_fm = plusFM_C (++) idwarn_fm iderrs_fm
213 get_id_data is_err (id, tys)
214 = (mod_name, [(id_name, id, tys, is_err)])
216 (mod_name, id_name) = get_id_name id
221 {- Don't understand this -- and looks TURGID. SLPJ 4 Nov 96
222 | maybeToBool (isDefaultMethodId_maybe id)
225 | isDictFunId id || maybeToBool (isConstMethodId_maybe id)
226 = let get_mod = getInstIdModule id
234 get_ty_data (ty, tys)
235 = (mod_name, [(ty_name, ty, tys)])
237 (mod_name, ty_name) = modAndOcc ty
239 module_names = concat [keysFM idspecs_fm, keysFM tyspecs_fm]
240 mods = map head (equivClasses _CMP_STRING_ module_names)
242 (unks, known) = if null mods
244 else case _CMP_STRING_ (head mods) _NIL_ of
245 EQ_ -> ([_NIL_], tail mods)
248 use_modules = unks ++ known
250 pp_module_specs :: FAST_STRING -> Doc
253 = ASSERT (null mod_tyspecs)
254 vcat (map (pp_idspec ty_sty (ptext SLIT("UNKNOWN:"))) mod_idspecs)
258 vcat (map (pp_tyspec ty_sty (pp_module mod)) mod_tyspecs),
259 vcat (map (pp_idspec ty_sty (pp_module mod)) mod_idspecs)
266 mod_tyspecs = lookupWithDefaultFM tyspecs_fm [] mod
267 mod_idspecs = lookupWithDefaultFM idspecs_fm [] mod
268 have_specs = not (null mod_tyspecs && null mod_idspecs)
269 ty_sty = PprInterface
272 = hcat [ptext mod, char ':']
274 pp_tyspec :: PprStyle -> Doc -> (OccName, TyCon, [Maybe Type]) -> Doc
276 pp_tyspec sty pp_mod (_, tycon, tys)
278 text "{-# SPECIALIZE data",
279 ppr (PprForUser opt_PprUserLength) tycon, hsep (map (pprParendGenType sty) spec_tys),
280 text "-} {- Essential -}"
283 tvs = tyConTyVars tycon
284 (spec_args, tv_maybes) = unzip (map choose_ty (tvs `zip` tys))
285 spec_tys = map (mkForAllTys (catMaybes tv_maybes)) spec_args
287 choose_ty (tv, Nothing) = (mkTyVarTy tv, Just tv)
288 choose_ty (tv, Just ty) = (ty, Nothing)
290 pp_idspec :: PprStyle -> Doc -> (OccName, Id, [Maybe Type], Bool) -> Doc
291 pp_idspec = error "pp_idspec"
295 pp_idspec sty pp_mod (_, id, tys, is_err)
298 text "{-# SPECIALIZE instance",
299 pprGenType sty spec_ty,
300 text "#-}", pp_essential ]
304 Just (cls, clsty, clsop) = const_method_maybe
307 text "{-# SPECIALIZE",
308 ppr sty clsop, text "::",
309 pprGenType sty spec_ty,
310 text "#-} {- IN instance",
311 pprOccName sty (getOccName cls), pprParendGenType sty clsty,
312 text "-}", pp_essential ]
314 | is_default_method_id
316 Just (cls, clsop, _) = default_method_maybe
320 pprOccName sty (getOccName cls),
321 ptext SLIT("EXPLICIT METHOD REQUIRED"),
322 ppr sty clsop, text "::",
323 pprGenType sty spec_ty,
324 text "-}", pp_essential ]
328 text "{-# SPECIALIZE",
329 ppr (PprForUser opt_PprUserLength) id, ptext SLIT("::"),
330 pprGenType sty spec_ty,
331 text "#-}", pp_essential ]
333 spec_ty = specialiseTy (idType id) tys 100 -- HACK to drop all dicts!!!
334 pp_essential = if is_err then text "{- Essential -}" else empty
336 const_method_maybe = isConstMethodId_maybe id
337 is_const_method_id = maybeToBool const_method_maybe
339 default_method_maybe = isDefaultMethodId_maybe id
340 is_default_method_id = maybeToBool default_method_maybe