+%************************************************************************
+%* *
+\subsection{tcBindWithSigs}
+%* *
+%************************************************************************
+
+@tcBindWithSigs@ deals with a single binding group. It does generalisation,
+so all the clever stuff is in here.
+
+* binder_names and mbind must define the same set of Names
+
+* The Names in tc_ty_sigs must be a subset of binder_names
+
+* The Ids in tc_ty_sigs don't necessarily have to have the same name
+ as the Name in the tc_ty_sig
+
+\begin{code}
+tcBindWithSigs :: TopLevelFlag
+ -> LHsBinds Name
+ -> [LSig Name]
+ -> RecFlag
+ -> TcM (LHsBinds TcId, [TcId])
+ -- The returned TcIds are guaranteed zonked
+
+tcBindWithSigs top_lvl mbind sigs is_rec = do
+ { -- TYPECHECK THE SIGNATURES
+ tc_ty_sigs <- recoverM (returnM []) $
+ tcTySigs (filter isVanillaLSig sigs)
+ ; let lookup_sig = lookupSig tc_ty_sigs
+
+ -- SET UP THE MAIN RECOVERY; take advantage of any type sigs
+ ; recoverM (recoveryCode mbind lookup_sig) $ do
+
+ { traceTc (ptext SLIT("--------------------------------------------------------"))
+ ; traceTc (ptext SLIT("Bindings for") <+> ppr (collectHsBindBinders mbind))
+
+ -- TYPECHECK THE BINDINGS
+ ; ((mbind', mono_bind_infos), lie_req)
+ <- getLIE (tcMonoBinds mbind lookup_sig is_rec)
+
+ -- CHECK FOR UNLIFTED BINDINGS
+ -- These must be non-recursive etc, and are not generalised
+ -- They desugar to a case expression in the end
+ ; zonked_mono_tys <- zonkTcTypes (map getMonoType mono_bind_infos)
+ ; if any isUnLiftedType zonked_mono_tys then
+ do { -- Unlifted bindings
+ checkUnliftedBinds top_lvl is_rec mbind
+ ; extendLIEs lie_req
+ ; let exports = zipWith mk_export mono_bind_infos zonked_mono_tys
+ mk_export (name, Nothing, mono_id) mono_ty = ([], mkLocalId name mono_ty, mono_id)
+ mk_export (name, Just sig, mono_id) mono_ty = ([], sig_id sig, mono_id)
+
+ ; return ( unitBag $ noLoc $ AbsBinds [] [] exports emptyNameSet mbind',
+ [poly_id | (_, poly_id, _) <- exports]) } -- Guaranteed zonked
+
+ else do -- The normal lifted case: GENERALISE
+ { is_unres <- isUnRestrictedGroup mbind tc_ty_sigs
+ ; (tyvars_to_gen, dict_binds, dict_ids)
+ <- setSrcSpan (getLoc (head (bagToList mbind))) $
+ -- TODO: location a bit awkward, but the mbinds have been
+ -- dependency analysed and may no longer be adjacent
+ addErrCtxt (genCtxt (bndrNames mono_bind_infos)) $
+ generalise top_lvl is_unres mono_bind_infos tc_ty_sigs lie_req
+
+ -- FINALISE THE QUANTIFIED TYPE VARIABLES
+ -- The quantified type variables often include meta type variables
+ -- we want to freeze them into ordinary type variables, and
+ -- default their kind (e.g. from OpenTypeKind to TypeKind)
+ ; tyvars_to_gen' <- mappM zonkQuantifiedTyVar tyvars_to_gen
+
+ -- BUILD THE POLYMORPHIC RESULT IDs
+ ; let
+ exports = map mk_export mono_bind_infos
+ poly_ids = [poly_id | (_, poly_id, _) <- exports]
+ dict_tys = map idType dict_ids
+
+ inlines = mkNameSet [ name
+ | L _ (InlineSig True (L _ name) _) <- sigs]
+ -- Any INLINE sig (regardless of phase control)
+ -- makes the RHS look small
+ inline_phases = listToFM [ (name, phase)
+ | L _ (InlineSig _ (L _ name) phase) <- sigs,
+ not (isAlwaysActive phase)]
+ -- Set the IdInfo field to control the inline phase
+ -- AlwaysActive is the default, so don't bother with them
+ add_inlines id = attachInlinePhase inline_phases id
+
+ mk_export (binder_name, mb_sig, mono_id)
+ = case mb_sig of
+ Just sig -> (sig_tvs sig, add_inlines (sig_id sig), mono_id)
+ Nothing -> (tyvars_to_gen', add_inlines new_poly_id, mono_id)
+ where
+ new_poly_id = mkLocalId binder_name poly_ty
+ poly_ty = mkForAllTys tyvars_to_gen'
+ $ mkFunTys dict_tys
+ $ idType mono_id
+
+ -- ZONK THE poly_ids, because they are used to extend the type
+ -- environment; see the invariant on TcEnv.tcExtendIdEnv
+ ; zonked_poly_ids <- mappM zonkId poly_ids
+
+ ; traceTc (text "binding:" <+> ppr ((dict_ids, dict_binds),
+ exports, map idType zonked_poly_ids))
+
+ ; return (
+ unitBag $ noLoc $
+ AbsBinds tyvars_to_gen'
+ dict_ids
+ exports
+ inlines
+ (dict_binds `unionBags` mbind'),
+ zonked_poly_ids
+ )
+ } } }
+
+-- If typechecking the binds fails, then return with each
+-- signature-less binder given type (forall a.a), to minimise
+-- subsequent error messages
+recoveryCode mbind lookup_sig
+ = do { traceTc (text "tcBindsWithSigs: error recovery" <+> ppr binder_names)
+ ; return (emptyLHsBinds, poly_ids) }
+ where
+ forall_a_a = mkForAllTy alphaTyVar (mkTyVarTy alphaTyVar)
+ binder_names = collectHsBindBinders mbind
+ poly_ids = map mk_dummy binder_names
+ mk_dummy name = case lookup_sig name of
+ Just sig -> sig_id sig -- Signature
+ Nothing -> mkLocalId name forall_a_a -- No signature
+
+attachInlinePhase inline_phases bndr
+ = case lookupFM inline_phases (idName bndr) of
+ Just prag -> bndr `setInlinePragma` prag
+ Nothing -> bndr
+
+-- Check that non-overloaded unlifted bindings are
+-- a) non-recursive,
+-- b) not top level,
+-- c) not a multiple-binding group (more or less implied by (a))
+
+checkUnliftedBinds top_lvl is_rec mbind
+ = checkTc (isNotTopLevel top_lvl)
+ (unliftedBindErr "Top-level" mbind) `thenM_`
+ checkTc (isNonRec is_rec)
+ (unliftedBindErr "Recursive" mbind) `thenM_`
+ checkTc (isSingletonBag mbind)
+ (unliftedBindErr "Multiple" mbind)
+\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