summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorSimon Peyton Jones <simon.peytonjones@gmail.com>2022-05-09 22:56:22 +0100
committerSimon Peyton Jones <simonpj@microsoft.com>2022-05-16 08:51:17 +0100
commitc7d24cfdb02505e5f91d66d8cc052cac2d7108bf (patch)
tree4be288869397242e8f139e89b983327ba3f67a43 /compiler
parentaed356e1b68b2201fa6e3c5bf14079f3f3366b44 (diff)
downloadhaskell-c7d24cfdb02505e5f91d66d8cc052cac2d7108bf.tar.gz
Add arity to the INLINE pragmas for pattern synonymswip/T21531
The lack of INLNE arity was exposed by #21531. The fix is simple enough, if a bit clumsy.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/GHC/Tc/Gen/Sig.hs56
-rw-r--r--compiler/GHC/Tc/TyCl/PatSyn.hs55
2 files changed, 77 insertions, 34 deletions
diff --git a/compiler/GHC/Tc/Gen/Sig.hs b/compiler/GHC/Tc/Gen/Sig.hs
index 971a47bb99..874870765f 100644
--- a/compiler/GHC/Tc/Gen/Sig.hs
+++ b/compiler/GHC/Tc/Gen/Sig.hs
@@ -21,7 +21,8 @@ module GHC.Tc.Gen.Sig(
tcInstSig,
TcPragEnv, emptyPragEnv, lookupPragEnv, extendPragEnv,
- mkPragEnv, tcSpecPrags, tcSpecWrapper, tcImpPrags, addInlinePrags
+ mkPragEnv, tcSpecPrags, tcSpecWrapper, tcImpPrags,
+ addInlinePrags, addInlinePragArity
) where
import GHC.Prelude
@@ -66,7 +67,6 @@ import GHC.Unit.Module( getModule )
import GHC.Utils.Misc as Utils ( singleton )
import GHC.Utils.Outputable
import GHC.Utils.Panic
-import GHC.Utils.Trace
import GHC.Data.Maybe( orElse )
@@ -577,29 +577,32 @@ mkPragEnv sigs binds
prs = mapMaybe get_sig sigs
get_sig :: LSig GhcRn -> Maybe (Name, LSig GhcRn)
- get_sig (L l (SpecSig x lnm@(L _ nm) ty inl))
- = Just (nm, L l $ SpecSig x lnm ty (add_arity nm inl))
- get_sig (L l (InlineSig x lnm@(L _ nm) inl))
- = Just (nm, L l $ InlineSig x lnm (add_arity nm inl))
- get_sig (L l (SCCFunSig x st lnm@(L _ nm) str))
- = Just (nm, L l $ SCCFunSig x st lnm str)
+ get_sig sig@(L _ (SpecSig _ (L _ nm) _ _)) = Just (nm, add_arity nm sig)
+ get_sig sig@(L _ (InlineSig _ (L _ nm) _)) = Just (nm, add_arity nm sig)
+ get_sig sig@(L _ (SCCFunSig _ _ (L _ nm) _)) = Just (nm, sig)
get_sig _ = Nothing
- add_arity n inl_prag -- Adjust inl_sat field to match visible arity of function
- | isInlinePragma inl_prag
- -- add arity only for real INLINE pragmas, not INLINABLE
+ add_arity n sig -- Adjust inl_sat field to match visible arity of function
= case lookupNameEnv ar_env n of
- Just ar -> inl_prag { inl_sat = Just ar }
- Nothing -> warnPprTrace True "mkPragEnv no arity" (ppr n) $
- -- There really should be a binding for every INLINE pragma
- inl_prag
- | otherwise
- = inl_prag
+ Just ar -> addInlinePragArity ar sig
+ Nothing -> sig -- See Note [Pattern synonym inline arity]
-- ar_env maps a local to the arity of its definition
ar_env :: NameEnv Arity
ar_env = foldr lhsBindArity emptyNameEnv binds
+addInlinePragArity :: Arity -> LSig GhcRn -> LSig GhcRn
+addInlinePragArity ar (L l (InlineSig x nm inl)) = L l (InlineSig x nm (add_inl_arity ar inl))
+addInlinePragArity ar (L l (SpecSig x nm ty inl)) = L l (SpecSig x nm ty (add_inl_arity ar inl))
+addInlinePragArity _ sig = sig
+
+add_inl_arity :: Arity -> InlinePragma -> InlinePragma
+add_inl_arity ar prag@(InlinePragma { inl_inline = inl_spec })
+ | Inline {} <- inl_spec -- Add arity only for real INLINE pragmas, not INLINABLE
+ = prag { inl_sat = Just ar }
+ | otherwise
+ = prag
+
lhsBindArity :: LHsBind GhcRn -> NameEnv Arity -> NameEnv Arity
lhsBindArity (L _ (FunBind { fun_id = id, fun_matches = ms })) env
= extendNameEnv env (unLoc id) (matchGroupArity ms)
@@ -638,6 +641,25 @@ addInlinePrags poly_id prags_for_me
pp_inl (L loc prag) = ppr prag <+> parens (ppr loc)
+{- Note [Pattern synonym inline arity]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Consider
+ {-# INLINE P #-}
+ pattern P x = (x, True)
+
+The INLINE pragma attaches to both the /matcher/ and the /builder/ for
+the pattern synonym; see Note [Pragmas for pattern synonyms] in
+GHC.Tc.TyCl.PatSyn. But they have different inline arities (i.e. number
+of binders to which we apply the function before inlining), and we don't
+know what those arities are yet. So for pattern synonyms we don't set
+the inl_sat field yet; instead we do so (via addInlinePragArity) in
+GHC.Tc.TyCl.PatSyn.tcPatSynMatcher and tcPatSynBuilderBind.
+
+It's a bit messy that we set the arities in different ways. Perhaps we
+should add the arity later for all binders. But it works fine like this.
+-}
+
+
{- *********************************************************************
* *
SPECIALISE pragmas
diff --git a/compiler/GHC/Tc/TyCl/PatSyn.hs b/compiler/GHC/Tc/TyCl/PatSyn.hs
index 45810f5d9f..a306a3967e 100644
--- a/compiler/GHC/Tc/TyCl/PatSyn.hs
+++ b/compiler/GHC/Tc/TyCl/PatSyn.hs
@@ -27,7 +27,8 @@ import GHC.Core.Type ( tidyTyCoVarBinders, tidyTypes, tidyType, isManyDataConTy
import GHC.Core.TyCo.Subst( extendTvSubstWithClone )
import GHC.Tc.Errors.Types
import GHC.Tc.Utils.Monad
-import GHC.Tc.Gen.Sig ( TcPragEnv, emptyPragEnv, completeSigFromId, lookupPragEnv, addInlinePrags )
+import GHC.Tc.Gen.Sig ( TcPragEnv, emptyPragEnv, completeSigFromId, lookupPragEnv
+ , addInlinePrags, addInlinePragArity )
import GHC.Tc.Utils.Env
import GHC.Tc.Utils.TcMType
import GHC.Tc.Utils.Zonk
@@ -782,7 +783,7 @@ tcPatSynMatcher :: LocatedN Name
-> TcType
-> TcM (PatSynMatcher, LHsBinds GhcTc)
-- See Note [Matchers and builders for pattern synonyms] in GHC.Core.PatSyn
-tcPatSynMatcher (L loc name) lpat prag_fn
+tcPatSynMatcher (L loc ps_name) lpat prag_fn
(univ_tvs, req_theta, req_ev_binds, req_dicts)
(ex_tvs, ex_tys, prov_theta, prov_dicts)
(args, arg_tys) pat_ty
@@ -802,7 +803,7 @@ tcPatSynMatcher (L loc name) lpat prag_fn
fail_ty = mkVisFunTyMany unboxedUnitTy res_ty
- ; matcher_name <- newImplicitBinder name mkMatcherOcc
+ ; matcher_name <- newImplicitBinder ps_name mkMatcherOcc
; scrutinee <- newSysLocalId (fsLit "scrut") Many pat_ty
; cont <- newSysLocalId (fsLit "cont") Many cont_ty
; fail <- newSysLocalId (fsLit "fail") Many fail_ty
@@ -811,7 +812,7 @@ tcPatSynMatcher (L loc name) lpat prag_fn
; let matcher_tau = mkVisFunTysMany [pat_ty, cont_ty, fail_ty] res_ty
matcher_sigma = mkInfSigmaTy (rr_tv:res_tv:univ_tvs) req_theta matcher_tau
matcher_id = mkExportedVanillaId matcher_name matcher_sigma
- patsyn_id = mkExportedVanillaId name matcher_sigma
+ patsyn_id = mkExportedVanillaId ps_name matcher_sigma
-- See Note [Exported LocalIds] in GHC.Types.Id
inst_wrap = mkWpEvApps prov_dicts <.> mkWpTyApps ex_tys
@@ -848,16 +849,21 @@ tcPatSynMatcher (L loc name) lpat prag_fn
, mg_ext = MatchGroupTc [] res_ty
, mg_origin = Generated
}
- prags = lookupPragEnv prag_fn name
+ matcher_arity = length req_theta + 3
-- See Note [Pragmas for pattern synonyms]
- ; matcher_prag_id <- addInlinePrags matcher_id prags
+ -- Add INLINE pragmas; see Note [Pragmas for pattern synonyms]
+ -- NB: prag_fn is keyed by the PatSyn Name, not the (internal) matcher name
+ ; matcher_prag_id <- addInlinePrags matcher_id $
+ map (addInlinePragArity matcher_arity) $
+ lookupPragEnv prag_fn ps_name
+
; let bind = FunBind{ fun_id = L loc matcher_prag_id
, fun_matches = mg
, fun_ext = idHsWrapper
, fun_tick = [] }
matcher_bind = unitBag (noLocA bind)
- ; traceTc "tcPatSynMatcher" (ppr name $$ ppr (idType matcher_id))
+ ; traceTc "tcPatSynMatcher" (ppr ps_name $$ ppr (idType matcher_id))
; traceTc "tcPatSynMatcher" (ppr matcher_bind)
; return ((matcher_name, matcher_sigma, is_unlifted), matcher_bind) }
@@ -905,6 +911,7 @@ mkPatSynBuilder dir (L _ name)
mkPhiTy theta $
mkVisFunTysMany arg_tys $
pat_ty
+
; return (Just (builder_name, builder_sigma, need_dummy_arg)) }
tcPatSynBuilderBind :: TcPragEnv
@@ -937,11 +944,17 @@ tcPatSynBuilderBind prag_fn (PSB { psb_id = ps_lname@(L loc ps_name)
do { -- Bidirectional, so patSynBuilder returns Just
let builder_id = mkExportedVanillaId builder_name builder_ty
-- See Note [Exported LocalIds] in GHC.Types.Id
- prags = lookupPragEnv prag_fn ps_name
- -- See Note [Pragmas for pattern synonyms]
- -- Keyed by the PatSyn Name, not the (internal) builder name
- ; builder_id <- addInlinePrags builder_id prags
+ (_, req_theta, _, prov_theta, arg_tys, _) = patSynSigBndr patsyn
+ builder_arity = length req_theta + length prov_theta
+ + length arg_tys
+ + (if need_dummy_arg then 1 else 0)
+
+ -- Add INLINE pragmas; see Note [Pragmas for pattern synonyms]
+ -- NB: prag_fn is keyed by the PatSyn Name, not the (internal) builder name
+ ; builder_id <- addInlinePrags builder_id $
+ map (addInlinePragArity builder_arity) $
+ lookupPragEnv prag_fn ps_name
; let match_group' | need_dummy_arg = add_dummy_arg match_group
| otherwise = match_group
@@ -955,8 +968,7 @@ tcPatSynBuilderBind prag_fn (PSB { psb_id = ps_lname@(L loc ps_name)
; traceTc "tcPatSynBuilderBind {" $
vcat [ ppr patsyn
- , ppr builder_id <+> dcolon <+> ppr (idType builder_id)
- , ppr prags ]
+ , ppr builder_id <+> dcolon <+> ppr (idType builder_id) ]
; (builder_binds, _) <- tcPolyCheck emptyPragEnv sig (noLocA bind)
; traceTc "tcPatSynBuilderBind }" $ ppr builder_binds
; return builder_binds } } }
@@ -1216,18 +1228,19 @@ want to avoid difficult to decipher core lint errors!
Note [Pragmas for pattern synonyms]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-INLINE and NOINLINE pragmas are supported for pattern synonyms. They affect both
-the matcher and the builder.
+INLINE and NOINLINE pragmas are supported for pattern synonyms.
+They affect both the matcher and the builder.
(See Note [Matchers and builders for pattern synonyms] in PatSyn)
For example:
pattern InlinedPattern x = [x]
{-# INLINE InlinedPattern #-}
+
pattern NonInlinedPattern x = [x]
{-# NOINLINE NonInlinedPattern #-}
-For pattern synonyms with explicit builders, only pragma for the entire pattern
-synonym is supported. For example:
+For pattern synonyms with explicit builders, only a pragma for the
+entire pattern synonym is supported. For example:
pattern HeadC x <- x:xs where
HeadC x = [x]
-- This wouldn't compile: {-# INLINE HeadC #-}
@@ -1235,6 +1248,14 @@ synonym is supported. For example:
When no pragma is provided for a pattern, the inlining decision might change
between different versions of GHC.
+
+Implementation notes. The prag_fn passed in to tcPatSynDecl will have a binding
+for the /pattern synonym/ Name, thus
+ InlinedPattern :-> INLINE
+From this we cook up an INLINE pragma for the matcher (in tcPatSynMatcher)
+and builder (in tcPatSynBuilderBind), by looking up the /pattern synonym/
+Name in the prag_fn, and then using addInlinePragArity to add the right
+inl_sat field to that INLINE pragma for the matcher or builder respectively.
-}