- mk_export binder_name mono_id zonked_mono_id_ty
- | maybeToBool maybe_sig = (sig_tyvars, TcId sig_poly_id, TcId mono_id)
- | otherwise = (tyvars_to_gen_list, TcId poly_id, TcId mono_id)
- where
- maybe_sig = maybeSig tc_ty_sigs binder_name
- Just (TySigInfo _ sig_poly_id sig_tyvars _ _ _) = maybe_sig
- poly_id = mkUserId binder_name poly_ty (prag_info_fn binder_name)
- poly_ty = mkForAllTys tyvars_to_gen_list $ mkFunTys dict_tys $ zonked_mono_id_ty
- -- It's important to build a fully-zonked poly_ty, because
- -- we'll slurp out its free type variables when extending the
- -- local environment (tcExtendLocalValEnv); if it's not zonked
- -- it appears to have free tyvars that aren't actually free at all.
- in
+ where
+ single_bind (PatMonoBind _ _ _) = True
+ single_bind (FunMonoBind _ _ _ _) = True
+ single_bind other = False
+\end{code}
+
+
+Polymorphic recursion
+~~~~~~~~~~~~~~~~~~~~~
+The game plan for polymorphic recursion in the code above is
+
+ * Bind any variable for which we have a type signature
+ to an Id with a polymorphic type. Then when type-checking
+ the RHSs we'll make a full polymorphic call.
+
+This fine, but if you aren't a bit careful you end up with a horrendous
+amount of partial application and (worse) a huge space leak. For example:
+
+ f :: Eq a => [a] -> [a]
+ f xs = ...f...
+
+If we don't take care, after typechecking we get
+
+ f = /\a -> \d::Eq a -> let f' = f a d
+ in
+ \ys:[a] -> ...f'...
+
+Notice the the stupid construction of (f a d), which is of course
+identical to the function we're executing. In this case, the
+polymorphic recursion isn't being used (but that's a very common case).
+We'd prefer
+
+ f = /\a -> \d::Eq a -> letrec
+ fm = \ys:[a] -> ...fm...
+ in
+ fm
+
+This can lead to a massive space leak, from the following top-level defn
+(post-typechecking)
+
+ ff :: [Int] -> [Int]
+ ff = f Int dEqInt
+
+Now (f dEqInt) evaluates to a lambda that has f' as a free variable; but
+f' is another thunk which evaluates to the same thing... and you end
+up with a chain of identical values all hung onto by the CAF ff.
+
+ ff = f Int dEqInt
+
+ = let f' = f Int dEqInt in \ys. ...f'...
+
+ = let f' = let f' = f Int dEqInt in \ys. ...f'...
+ in \ys. ...f'...
+
+Etc.
+Solution: when typechecking the RHSs we always have in hand the
+*monomorphic* Ids for each binding. So we just need to make sure that
+if (Method f a d) shows up in the constraints emerging from (...f...)
+we just use the monomorphic Id. We achieve this by adding monomorphic Ids
+to the "givens" when simplifying constraints. That's what the "lies_avail"
+is doing.
+
+
+%************************************************************************
+%* *
+\subsection{getTyVarsToGen}
+%* *
+%************************************************************************
+
+\begin{code}
+generalise binder_names mbind tau_tvs lie_req sigs =
+
+ -- check for -fno-monomorphism-restriction
+ doptM Opt_NoMonomorphismRestriction `thenM` \ no_MR ->
+ let is_unrestricted | no_MR = True
+ | otherwise = isUnRestrictedGroup tysig_names mbind
+ in
+
+ if not is_unrestricted then -- RESTRICTED CASE
+ -- Check signature contexts are empty
+ checkTc (all is_mono_sig sigs)
+ (restrictedBindCtxtErr binder_names) `thenM_`
+
+ -- Now simplify with exactly that set of tyvars
+ -- We have to squash those Methods
+ tcSimplifyRestricted doc tau_tvs lie_req `thenM` \ (qtvs, binds) ->
+
+ -- Check that signature type variables are OK
+ checkSigsTyVars qtvs sigs `thenM` \ final_qtvs ->
+
+ returnM (final_qtvs, binds, [])
+
+ else if null sigs then -- UNRESTRICTED CASE, NO TYPE SIGS
+ tcSimplifyInfer doc tau_tvs lie_req
+
+ else -- UNRESTRICTED CASE, WITH TYPE SIGS
+ -- CHECKING CASE: Unrestricted group, there are type signatures
+ -- Check signature contexts are identical
+ checkSigsCtxts sigs `thenM` \ (sig_avails, sig_dicts) ->
+
+ -- Check that the needed dicts can be
+ -- expressed in terms of the signature ones
+ tcSimplifyInferCheck doc tau_tvs sig_avails lie_req `thenM` \ (forall_tvs, dict_binds) ->
+
+ -- Check that signature type variables are OK
+ checkSigsTyVars forall_tvs sigs `thenM` \ final_qtvs ->
+
+ returnM (final_qtvs, dict_binds, sig_dicts)