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,
28 import Bag ( isEmptyBag, bagToList, Bag )
29 import Class ( GenClass{-instance NamedThing-}, SYN_IE(Class),
30 GenClassOp {- instance NamedThing -} )
31 import FiniteMap ( emptyFM, addListToFM_C, plusFM_C, keysFM,
34 import Id ( idType, isDictFunId, isConstMethodId_maybe,
35 isDefaultMethodId_maybe,
36 GenId {-instance NamedThing -}, SYN_IE(Id)
38 import Maybes ( maybeToBool, catMaybes, firstJust )
39 import Name ( OccName, pprOccName, modAndOcc, NamedThing(..) )
40 import PprStyle ( PprStyle(..) )
41 import PprType ( pprGenType, pprParendGenType, pprMaybeTy,
42 TyCon{-ditto-}, GenType{-ditto-}, GenTyVar, GenClassOp
44 import Pretty -- plenty of it
45 import TyCon ( tyConTyVars, TyCon{-instance NamedThing-} )
46 import Type ( splitSigmaTy, mkTyVarTy, mkForAllTys,
47 getTyVar_maybe, isUnboxedType, SYN_IE(Type)
49 import TyVar ( GenTyVar{-instance Eq-}, SYN_IE(TyVar) )
50 import Unique ( Unique{-instance Eq-} )
51 import Util ( equivClasses, zipWithEqual, cmpPString,
52 assertPanic, panic{-ToDo:rm-}
55 #if __GLASGOW_HASKELL__ >= 202
56 import Outputable ( Outputable(..) )
59 cmpType = panic "SpecUtils.cmpType (ToDo: get rid of)"
60 mkSameSpecCon = panic "SpecUtils.mkSameSpecCon (ToDo)"
61 getInstIdModule = panic "SpecUtils.getInstIdModule (ToDo)"
62 specialiseTy :: Type -> [Maybe Type] -> Int -> Type
63 specialiseTy = panic "SpecUtils.specialiseTy (ToDo)"
66 @specialiseCallTys@ works out which type args don't need to be specialised on,
67 based on flags, the overloading constraint vector, and the types.
70 specialiseCallTys :: ConstraintVector -- Tells which type args are overloaded
71 -> [Type] -- Type args
72 -> [Maybe Type] -- Nothings replace non-specialised type args
74 specialiseCallTys cvec tys
75 | opt_SpecialiseAll = map Just tys
76 | otherwise = zipWithEqual "specialiseCallTys" spec_ty_other cvec tys
78 spec_ty_other c ty | (opt_SpecialiseUnboxed && isUnboxedType ty) ||
79 (opt_SpecialiseOverloaded && c)
85 @getIdOverloading@ grabs the type of an Id, and returns a
86 list of its polymorphic variables, and the initial segment of
87 its ThetaType, in which the classes constrain only type variables.
88 For example, if the Id's type is
90 forall a,b,c. Eq a -> Ord [a] -> tau
96 This seems curious at first. For a start, the type above looks odd,
97 because we usually only have dictionary args whose types are of
98 the form (C a) where a is a type variable. But this doesn't hold for
99 the functions arising from instance decls, which sometimes get
100 arguements with types of form (C (T a)) for some type constructor T.
102 Should we specialise wrt this compound-type dictionary? This is
103 a heuristic judgement, as indeed is the fact that we specialise wrt
104 only dictionaries. We choose *not* to specialise wrt compound dictionaries
105 because at the moment the only place they show up is in instance decls,
106 where they are simply plugged into a returned dictionary. So nothing is
107 gained by specialising wrt them.
110 getIdOverloading :: Id
111 -> ([TyVar], [(Class,TyVar)])
113 = (tyvars, tyvar_part_of theta)
115 (tyvars, theta, _) = splitSigmaTy (idType id)
117 tyvar_part_of [] = []
118 tyvar_part_of ((c,ty):theta) = case (getTyVar_maybe ty) of
120 Just tv -> (c, tv) : tyvar_part_of theta
124 type ConstraintVector = [Bool] -- True for constrained tyvar, false otherwise
128 isUnboxedSpecialisation :: [Maybe Type] -> Bool
129 isUnboxedSpecialisation tys
132 is_unboxed (Just ty) = isUnboxedType ty
133 is_unboxed Nothing = False
136 @specialiseConstrTys@ works out which type args don't need to be
137 specialised on. We only speciailise on unboxed types.
140 specialiseConstrTys :: [Type]
143 specialiseConstrTys tys
144 = map maybe_unboxed_ty tys
146 maybe_unboxed_ty ty = case isUnboxedType ty of
152 mkSpecialisedCon :: Id -> [Type] -> Id
153 mkSpecialisedCon con tys
155 then mkSameSpecCon spec_tys con
158 spec_tys = specialiseConstrTys tys
159 spec_reqd = maybeToBool (firstJust spec_tys)
162 @argTysMatchSpecTys@ checks if a list of argument types is consistent
163 with a list of specialising types. An error message is returned if not.
165 argTysMatchSpecTys_error :: [Maybe Type]
168 argTysMatchSpecTys_error spec_tys arg_tys
169 = if match spec_tys arg_tys
171 else Just (sep [ptext SLIT("Spec and Arg Types Inconsistent:"),
172 ptext SLIT("spectys="), sep [pprMaybeTy PprDebug ty | ty <- spec_tys],
173 ptext SLIT("argtys="), sep [pprParendGenType PprDebug ty | ty <- arg_tys]])
175 match (Nothing:spec_tys) (arg:arg_tys)
176 = not (isUnboxedType arg) &&
177 match spec_tys arg_tys
178 match (Just spec:spec_tys) (arg:arg_tys)
179 = case (cmpType True{-properly-} spec arg) of
180 EQ_ -> match spec_tys arg_tys
186 @pprSpecErrs@ prints error and warning information
187 about imported specialisations which do not exist.
190 pprSpecErrs :: FAST_STRING -- module name
191 -> (Bag (Id,[Maybe Type])) -- errors
192 -> (Bag (Id,[Maybe Type])) -- warnings
193 -> (Bag (TyCon,[Maybe Type])) -- errors
196 pprSpecErrs this_mod spec_errs spec_warn spec_tyerrs
197 | not any_errs && not any_warn
202 ptext SLIT("SPECIALISATION MESSAGES:"),
203 vcat (map pp_module_specs use_modules)
206 any_errs = not (isEmptyBag spec_errs && isEmptyBag spec_tyerrs)
207 any_warn = not (isEmptyBag spec_warn)
209 mk_module_fm get_mod_data errs_bag
210 = addListToFM_C (++) emptyFM errs_list
212 errs_list = map get_mod_data (bagToList errs_bag)
214 tyspecs_fm = mk_module_fm get_ty_data spec_tyerrs
216 iderrs_fm = mk_module_fm (get_id_data True) spec_errs
217 idwarn_fm = mk_module_fm (get_id_data False) spec_warn
218 idspecs_fm = plusFM_C (++) idwarn_fm iderrs_fm
220 get_id_data is_err (id, tys)
221 = (mod_name, [(id_name, id, tys, is_err)])
223 (mod_name, id_name) = get_id_name id
228 {- Don't understand this -- and looks TURGID. SLPJ 4 Nov 96
229 | maybeToBool (isDefaultMethodId_maybe id)
232 | isDictFunId id || maybeToBool (isConstMethodId_maybe id)
233 = let get_mod = getInstIdModule id
241 get_ty_data (ty, tys)
242 = (mod_name, [(ty_name, ty, tys)])
244 (mod_name, ty_name) = modAndOcc ty
246 module_names = concat [keysFM idspecs_fm, keysFM tyspecs_fm]
247 mods = map head (equivClasses _CMP_STRING_ module_names)
249 (unks, known) = if null mods
251 else case _CMP_STRING_ (head mods) _NIL_ of
252 EQ_ -> ([_NIL_], tail mods)
255 use_modules = unks ++ known
257 pp_module_specs :: FAST_STRING -> Doc
260 = ASSERT (null mod_tyspecs)
261 vcat (map (pp_idspec ty_sty (ptext SLIT("UNKNOWN:"))) mod_idspecs)
265 vcat (map (pp_tyspec ty_sty (pp_module mod)) mod_tyspecs),
266 vcat (map (pp_idspec ty_sty (pp_module mod)) mod_idspecs)
273 mod_tyspecs = lookupWithDefaultFM tyspecs_fm [] mod
274 mod_idspecs = lookupWithDefaultFM idspecs_fm [] mod
275 have_specs = not (null mod_tyspecs && null mod_idspecs)
276 ty_sty = PprInterface
279 = hcat [ptext mod, char ':']
281 pp_tyspec :: PprStyle -> Doc -> (OccName, TyCon, [Maybe Type]) -> Doc
283 pp_tyspec sty pp_mod (_, tycon, tys)
285 text "{-# SPECIALIZE data",
286 ppr PprForUser tycon, hsep (map (pprParendGenType sty) spec_tys),
287 text "-} {- Essential -}"
290 tvs = tyConTyVars tycon
291 (spec_args, tv_maybes) = unzip (map choose_ty (tvs `zip` tys))
292 spec_tys = map (mkForAllTys (catMaybes tv_maybes)) spec_args
294 choose_ty (tv, Nothing) = (mkTyVarTy tv, Just tv)
295 choose_ty (tv, Just ty) = (ty, Nothing)
297 pp_idspec :: PprStyle -> Doc -> (OccName, Id, [Maybe Type], Bool) -> Doc
299 pp_idspec sty pp_mod (_, id, tys, is_err)
302 text "{-# SPECIALIZE instance",
303 pprGenType sty spec_ty,
304 text "#-}", pp_essential ]
308 Just (cls, clsty, clsop) = const_method_maybe
311 text "{-# SPECIALIZE",
312 ppr sty clsop, text "::",
313 pprGenType sty spec_ty,
314 text "#-} {- IN instance",
315 pprOccName sty (getOccName cls), pprParendGenType sty clsty,
316 text "-}", pp_essential ]
318 | is_default_method_id
320 Just (cls, clsop, _) = default_method_maybe
324 pprOccName sty (getOccName cls),
325 ptext SLIT("EXPLICIT METHOD REQUIRED"),
326 ppr sty clsop, text "::",
327 pprGenType sty spec_ty,
328 text "-}", pp_essential ]
332 text "{-# SPECIALIZE",
333 ppr PprForUser id, ptext SLIT("::"),
334 pprGenType sty spec_ty,
335 text "#-}", pp_essential ]
337 spec_ty = specialiseTy (idType id) tys 100 -- HACK to drop all dicts!!!
338 pp_essential = if is_err then text "{- Essential -}" else empty
340 const_method_maybe = isConstMethodId_maybe id
341 is_const_method_id = maybeToBool const_method_maybe
343 default_method_maybe = isDefaultMethodId_maybe id
344 is_default_method_id = maybeToBool default_method_maybe