\begin{code}
module TcBinds ( tcLocalBinds, tcTopBinds,
tcHsBootSigs, tcMonoBinds, tcPolyBinds,
- TcPragFun, tcSpecPrag, tcPrags, mkPragFun,
+ TcPragFun, tcPrags, mkPragFun,
TcSigInfo(..), TcSigFun, mkTcSigFun,
badBootDeclErr ) where
import TcPat
import TcMType
import TcType
-import {- Kind parts of -} Type
import Coercion
import VarEnv
import TysPrim
import ErrUtils
import Digraph
import Maybes
-import List
import Util
import BasicTypes
import Outputable
import FastString
+import Data.List( partition )
import Control.Monad
\end{code}
tcValBinds top_lvl (ValBindsOut binds sigs) thing_inside
= do { -- Typecheck the signature
- ; let { prag_fn = mkPragFun sigs
+ ; let { prag_fn = mkPragFun sigs (foldr (unionBags . snd) emptyBag binds)
; ty_sigs = filter isTypeLSig sigs
; sig_fn = mkTcSigFun ty_sigs }
; if is_strict then
do { 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 (_, Just sig, mono_id) _ = ([], sig_id sig, mono_id, [])
- -- ToDo: prags for unlifted bindings
+ mk_export (name, mb_sig, mono_id) mono_ty
+ = ([], the_id, mono_id, noSpecPrags)
+ -- ToDo: prags for unlifted bindings
+ where
+ the_id = case mb_sig of
+ Just sig -> sig_id sig
+ Nothing -> mkLocalId name mono_ty
; return ( unitBag $ L loc $ AbsBinds [] [] exports binds',
[poly_id | (_, poly_id, _, _) <- exports]) } -- Guaranteed zonked
-- BUILD THE POLYMORPHIC RESULT IDs
; let dict_vars = map instToVar dicts -- May include equality constraints
- ; exports <- mapM (mkExport top_lvl prag_fn tyvars_to_gen (map varType dict_vars))
+ ; exports <- mapM (mkExport top_lvl rec_group (length mono_bind_infos > 1)
+ prag_fn tyvars_to_gen (map varType dict_vars))
mono_bind_infos
; let poly_ids = [poly_id | (_, poly_id, _, _) <- exports]
--------------
-mkExport :: TopLevelFlag -> TcPragFun -> [TyVar] -> [TcType]
+mkExport :: TopLevelFlag -> RecFlag
+ -> Bool -- More than one variable is bound, so we'll desugar to
+ -- a tuple, so INLINE pragmas won't work
+ -> TcPragFun -> [TyVar] -> [TcType]
-> MonoBindInfo
- -> TcM ([TyVar], Id, Id, [LPrag])
+ -> TcM ([TyVar], Id, Id, TcSpecPrags)
-- mkExport generates exports with
-- zonked type variables,
-- zonked poly_ids
-- Pre-condition: the inferred_tvs are already zonked
-mkExport top_lvl prag_fn inferred_tvs dict_tys (poly_name, mb_sig, mono_id)
+mkExport top_lvl rec_group multi_bind prag_fn inferred_tvs dict_tys
+ (poly_name, mb_sig, mono_id)
= do { warn_missing_sigs <- doptM Opt_WarnMissingSigs
; let warn = isTopLevel top_lvl && warn_missing_sigs
; (tvs, poly_id) <- mk_poly_id warn mb_sig
-- poly_id has a zonked type
- ; prags <- tcPrags poly_id (prag_fn poly_name)
+ ; (poly_id', spec_prags) <- tcPrags rec_group multi_bind (notNull dict_tys)
+ poly_id (prag_fn poly_name)
-- tcPrags requires a zonked poly_id
- ; return (tvs, poly_id, mono_id, prags) }
+ ; return (tvs, poly_id', mono_id, SpecPrags spec_prags) }
where
poly_ty = mkForAllTys inferred_tvs (mkFunTys dict_tys (idType mono_id))
------------------------
type TcPragFun = Name -> [LSig Name]
-mkPragFun :: [LSig Name] -> TcPragFun
-mkPragFun sigs = \n -> lookupNameEnv env n `orElse` []
- where
- prs = [(expectJust "mkPragFun" (sigName sig), sig)
- | sig <- sigs, isPragLSig sig]
- env = foldl add emptyNameEnv prs
- add env (n,p) = extendNameEnv_Acc (:) singleton env n p
-
-tcPrags :: Id -> [LSig Name] -> TcM [LPrag]
-tcPrags poly_id prags = mapM (wrapLocM tc_prag) prags
+mkPragFun :: [LSig Name] -> LHsBinds Name -> TcPragFun
+mkPragFun sigs binds = \n -> lookupNameEnv prag_env n `orElse` []
where
- tc_prag prag = addErrCtxt (pragSigCtxt prag) $
- tcPrag poly_id prag
-
-pragSigCtxt :: Sig Name -> SDoc
-pragSigCtxt prag = hang (ptext (sLit "In the pragma")) 2 (ppr prag)
-
-tcPrag :: TcId -> Sig Name -> TcM Prag
+ prs = mapCatMaybes get_sig sigs
+
+ get_sig :: LSig Name -> Maybe (Located Name, LSig Name)
+ get_sig (L l (SpecSig nm ty inl)) = Just (nm, L l $ SpecSig nm ty (add_arity nm inl))
+ get_sig (L l (InlineSig nm inl)) = Just (nm, L l $ InlineSig nm (add_arity nm inl))
+ get_sig _ = Nothing
+
+ add_arity (L _ n) inl_prag -- Adjust inl_sat field to match visible arity of function
+ | Just ar <- lookupNameEnv ar_env n = inl_prag { inl_sat = Just ar }
+ | otherwise = inl_prag
+
+ prag_env :: NameEnv [LSig Name]
+ prag_env = foldl add emptyNameEnv prs
+ add env (L _ n,p) = extendNameEnv_Acc (:) singleton env n p
+
+ -- ar_env maps a local to the arity of its definition
+ ar_env :: NameEnv Arity
+ ar_env = foldrBag lhsBindArity emptyNameEnv binds
+
+lhsBindArity :: LHsBind Name -> NameEnv Arity -> NameEnv Arity
+lhsBindArity (L _ (FunBind { fun_id = id, fun_matches = ms })) env
+ = extendNameEnv env (unLoc id) (matchGroupArity ms)
+lhsBindArity _ env = env -- PatBind/VarBind
+
+tcPrags :: RecFlag
+ -> Bool -- True <=> AbsBinds binds more than one variable
+ -> Bool -- True <=> function is overloaded
+ -> Id -> [LSig Name]
+ -> TcM (Id, [Located TcSpecPrag])
+-- Add INLINE and SPECLIASE pragmas
+-- INLINE prags are added to the (polymorphic) Id directly
+-- SPECIALISE prags are passed to the desugarer via TcSpecPrags
-- Pre-condition: the poly_id is zonked
-- Reason: required by tcSubExp
-tcPrag poly_id (SpecSig _ hs_ty inl) = tcSpecPrag poly_id hs_ty inl
-tcPrag poly_id (SpecInstSig hs_ty) = tcSpecPrag poly_id hs_ty defaultInlineSpec
-tcPrag _ (InlineSig _ inl) = return (InlinePrag inl)
-tcPrag _ sig = pprPanic "tcPrag" (ppr sig)
+tcPrags _rec_group _multi_bind _is_overloaded_id poly_id prag_sigs
+ = do { poly_id' <- tc_inl inl_sigs
+
+ ; spec_prags <- mapM (wrapLocM (tcSpecPrag poly_id')) spec_sigs
+-- Commented out until bytestring library removes redundant pragmas
+-- for packWith and unpackWith
+-- ; unless (null spec_sigs || is_overloaded_id) warn_discarded_spec
+
+ ; unless (null bad_sigs) warn_discarded_sigs
+
+ ; return (poly_id', spec_prags) }
+ where
+ (inl_sigs, other_sigs) = partition isInlineLSig prag_sigs
+ (spec_sigs, bad_sigs) = partition isSpecLSig other_sigs
+
+-- warn_discarded_spec = warnPrags poly_id spec_sigs $
+-- ptext (sLit "SPECIALISE pragmas for non-overloaded function")
+ warn_dup_inline = warnPrags poly_id inl_sigs $
+ ptext (sLit "Duplicate INLINE pragmas for")
+ warn_discarded_sigs = warnPrags poly_id bad_sigs $
+ ptext (sLit "Discarding unexpected pragmas for")
+
+ -----------
+ tc_inl [] = return poly_id
+ tc_inl (L loc (InlineSig _ prag) : other_inls)
+ = do { unless (null other_inls) (setSrcSpan loc warn_dup_inline)
+ ; return (poly_id `setInlinePragma` prag) }
+ tc_inl _ = panic "tc_inl"
+
+{- Earlier we tried to warn about
+ (a) INLINE for recursive function
+ (b) INLINE for function that is part of a multi-binder group
+ Code fragments below. But we want to allow
+ {-# INLINE f #-}
+ f x = x : g y
+ g y = ....f...f....
+ even though they are mutually recursive.
+ So I'm just omitting the warnings for now
+
+ | multi_bind && isInlinePragma prag
+ = do { setSrcSpan loc $ addWarnTc multi_bind_warn
+ ; return poly_id }
+ | otherwise
+ ; when (isInlinePragma prag && isRec rec_group)
+ (setSrcSpan loc (addWarnTc rec_inline_warn))
+
+ rec_inline_warn = ptext (sLit "INLINE pragma for recursive binder")
+ <+> quotes (ppr poly_id) <+> ptext (sLit "may be discarded")
+
+ multi_bind_warn = hang (ptext (sLit "Discarding INLINE pragma for") <+> quotes (ppr poly_id))
+ 2 (ptext (sLit "because it is bound by a pattern, or mutual recursion") )
+-}
+
+
+warnPrags :: Id -> [LSig Name] -> SDoc -> TcM ()
+warnPrags id bad_sigs herald
+ = addWarnTc (hang (herald <+> quotes (ppr id))
+ 2 (ppr_sigs bad_sigs))
+ where
+ ppr_sigs sigs = vcat (map (ppr . getLoc) sigs)
-tcSpecPrag :: TcId -> LHsType Name -> InlineSpec -> TcM Prag
-tcSpecPrag poly_id hs_ty inl
- = do { let name = idName poly_id
+--------------
+tcSpecPrag :: TcId -> Sig Name -> TcM TcSpecPrag
+tcSpecPrag poly_id prag@(SpecSig _ hs_ty inl)
+ = addErrCtxt (spec_ctxt prag) $
+ do { let name = idName poly_id
; spec_ty <- tcHsSigType (FunSigCtxt name) hs_ty
; co_fn <- tcSubExp (SpecPragOrigin name) (idType poly_id) spec_ty
- ; return (SpecPrag (mkHsWrap co_fn (HsVar poly_id)) spec_ty inl) }
- -- Most of the work of specialisation is done by
- -- the desugarer, guided by the SpecPrag
-
+ ; return (SpecPrag co_fn inl) }
+ where
+ spec_ctxt prag = hang (ptext (sLit "In the SPECIALISE pragma")) 2 (ppr prag)
+tcSpecPrag _ sig = pprPanic "tcSpecPrag" (ppr sig)
+
+
--------------
-- If typechecking the binds fails, then return with each
-- signature-less binder given type (forall a.a), to minimise
(strictBindErr "Recursive" unlifted mbind)
; checkTc (isSingletonBag mbind)
(strictBindErr "Multiple" unlifted mbind)
+ -- This should be a checkTc, not a warnTc, but as of GHC 6.11
+ -- the versions of alex and happy available have non-conforming
+ -- templates, so the GHC build fails if it's an error:
+ ; warnUnlifted <- doptM Opt_WarnLazyUnliftedBindings
+ ; warnTc (warnUnlifted && not bang_pat)
+ (unliftedMustBeBang mbind)
; mapM_ check_sig infos
; return True }
| otherwise
(badStrictSig unlifted sig)
check_sig _ = return ()
+unliftedMustBeBang :: LHsBindsLR Var Var -> SDoc
+unliftedMustBeBang mbind
+ = hang (text "Bindings containing unlifted types must use an outermost bang pattern:")
+ 4 (pprLHsBinds mbind)
+ $$ text "*** This will be an error in GHC 6.14! Fix your code now!"
+
strictBindErr :: String -> Bool -> LHsBindsLR Var Var -> SDoc
strictBindErr flavour unlifted mbind
= hang (text flavour <+> msg <+> ptext (sLit "aren't allowed:"))
-- The returned [TyVar] are all ready to quantify
generalise dflags top_lvl bind_list sig_fn mono_infos lie_req
- | isMonoGroup dflags bind_list
+ | isMonoGroup dflags top_lvl bind_list sigs
= do { extendLIEs lie_req
; return ([], [], emptyBag) }
-- Post-condition: the returned Insts are full zonked
unifyCtxts [] = panic "unifyCtxts []"
unifyCtxts (sig1 : sigs) -- Argument is always non-empty
- = do { mapM unify_ctxt sigs
+ = do { traceTc $ text "unifyCtxts" <+> ppr (sig1 : sigs)
+ ; mapM_ unify_ctxt sigs
; theta <- zonkTcThetaType (sig_theta sig1)
; newDictBndrs (sig_loc sig1) theta }
where
checkDistinctTyVars sig_tvs
= do { zonked_tvs <- mapM zonkSigTyVar sig_tvs
- ; foldlM check_dup emptyVarEnv (sig_tvs `zip` zonked_tvs)
+ ; foldlM_ check_dup emptyVarEnv (sig_tvs `zip` zonked_tvs)
; return zonked_tvs }
where
check_dup :: TyVarEnv TcTyVar -> (TcTyVar, TcTyVar) -> TcM (TyVarEnv TcTyVar)
sig_loc = loc }) }
-------------------
-isMonoGroup :: DynFlags -> [LHsBind Name] -> Bool
+isMonoGroup :: DynFlags -> TopLevelFlag -> [LHsBind Name]
+ -> [TcSigInfo] -> Bool
-- No generalisation at all
-isMonoGroup dflags binds
- = dopt Opt_MonoPatBinds dflags && any is_pat_bind binds
+isMonoGroup dflags top_lvl binds sigs
+ = (dopt Opt_MonoPatBinds dflags && any is_pat_bind binds)
+ || (dopt Opt_MonoLocalBinds dflags && null sigs && not (isTopLevel top_lvl))
where
is_pat_bind (L _ (PatBind {})) = True
is_pat_bind _ = False