summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Graf <sebastian.graf@kit.edu>2022-06-07 11:31:22 +0200
committerSebastian Graf <sebastian.graf@kit.edu>2022-06-20 09:43:32 +0200
commit49fb2f9b16ca987648d2ac57eecf1892d49852ec (patch)
tree5bad0a2814b084d1811ca89ce0e6d70ae837dcbf
parentb570da84b7aad5ca3f90f2d1c1a690c927e99fe9 (diff)
downloadhaskell-49fb2f9b16ca987648d2ac57eecf1892d49852ec.tar.gz
Simplify: Take care with eta reduction in recursive RHSs (#21652)
Similar to the fix to #20836 in CorePrep, we now track the set of enclosing recursive binders in the SimplEnv and SimpleOptEnv. See Note [Eta reduction in recursive RHSs] for details. I also updated Note [Arity robustness] with the insights Simon and I had in a call discussing the issue. Fixes #21652. Unfortunately, we get a 5% ghc/alloc regression in T16577. That is due to additional eta reduction in GHC.Read.choose1 and the resulting ANF-isation of a large list literal at the top-level that didn't happen before (presumably because it was too interesting to float to the top-level). There's not much we can do about that. Metric Increase: T16577
-rw-r--r--compiler/GHC/Core/Opt/Arity.hs87
-rw-r--r--compiler/GHC/Core/Opt/Simplify.hs8
-rw-r--r--compiler/GHC/Core/Opt/Simplify/Env.hs52
-rw-r--r--compiler/GHC/Core/Opt/Simplify/Utils.hs3
-rw-r--r--compiler/GHC/Core/SimpleOpt.hs34
-rw-r--r--testsuite/tests/arityanal/should_compile/Arity03.stderr7
-rw-r--r--testsuite/tests/arityanal/should_run/Makefile3
-rw-r--r--testsuite/tests/arityanal/should_run/T21652.hs10
-rw-r--r--testsuite/tests/arityanal/should_run/T21652.stdout1
-rw-r--r--testsuite/tests/arityanal/should_run/all.T2
-rw-r--r--testsuite/tests/deSugar/should_compile/T19969.stderr14
11 files changed, 154 insertions, 67 deletions
diff --git a/compiler/GHC/Core/Opt/Arity.hs b/compiler/GHC/Core/Opt/Arity.hs
index 5858ff91e0..5edc5e5bb0 100644
--- a/compiler/GHC/Core/Opt/Arity.hs
+++ b/compiler/GHC/Core/Opt/Arity.hs
@@ -73,6 +73,7 @@ import GHC.Builtin.Types.Prim
import GHC.Builtin.Uniques
import GHC.Data.FastString
+import GHC.Data.Graph.UnVar
import GHC.Data.Pair
import GHC.Utils.GlobalVars( unsafeHasNoStateHack )
@@ -2043,15 +2044,6 @@ This test is made by `ok_fun` in tryEtaReduce.
with both type and dictionary lambdas; hence the slightly
ad-hoc (all ok_lam bndrs)
-3. (See fun_arity in tryEtaReduce.) We have to hide `f`'s `idArity` in
- its own RHS, lest we suffer from the last point of Note [Arity
- robustness] in GHC.Core.Opt.Simplify.Env. There we have `f = \x. f x`
- and we should not eta-reduce to `f=f`. Which might change a
- terminating program (think @f `seq` e@) to a non-terminating one.
- So we check for being a loop breaker first. However for GlobalIds
- we can look at the arity; and for primops we must, since they have
- no unfolding. [SG: Perhaps this is rather a soundness subtlety?]
-
Of course, eta reduction is not always sound. See Note [Eta reduction soundness]
for when it is.
@@ -2133,6 +2125,12 @@ case where `e` is trivial):
See Note [Eta reduction based on evaluation context] for the implementation
details. This criterion is tested extensively in T21261.
+ R. Note [Eta reduction in recursive RHSs] tells us that we should not
+ eta-reduce `f` in its own RHS and describes our fix.
+ There we have `f = \x. f x` and we should not eta-reduce to `f=f`. Which
+ might change a terminating program (think @f `seq` e@) to a non-terminating
+ one.
+
E. (See fun_arity in tryEtaReduce.) As a perhaps special case on the
boundary of (A) and (S), when we know that a fun binder `f` is in
WHNF, we simply assume it has arity 1 and apply (A). Example:
@@ -2276,15 +2274,73 @@ Then this is how the pieces are put together:
sub-demands `Cn` and see whether all of the n's (here: `S=C_1N` and
`1=C_11`) were strict. And strict they are! Thus, it will eta-reduce
`\x y. e x y` to `e`.
+
+Note [Eta reduction in recursive RHSs]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Consider the following recursive function:
+ f = \x. ....g (\y. f y)....
+The recursive call of f in its own RHS seems like a fine opportunity for
+eta-reduction because f has arity 1. And often it is!
+
+Alas, that is unsound in general if the eta-reduction happens in a tail context.
+Making the arity visible in the RHS allows us to eta-reduce
+ f = \x -> f x
+to
+ f = f
+which means we optimise terminating programs like (f `seq` ()) into
+non-terminating ones. Nor is this problem just for tail calls. Consider
+ f = id (\x -> f x)
+where we have (for some reason) not yet inlined `id`. We must not eta-reduce to
+ f = id f
+because that will then simplify to `f = f` as before.
+
+An immediate idea might be to look at whether the called function is a local
+loopbreaker and refrain from eta-expanding. But that doesn't work for mutually
+recursive function like in #21652:
+ f = g
+ g* x = f x
+Here, g* is the loopbreaker but f isn't.
+
+What can we do?
+
+Fix 1: Zap `idArity` when analysing recursive RHSs and re-attach the info when
+ entering the let body.
+ Has the disadvantage that other transformations which make use of arity
+ (such as dropping of `seq`s when arity > 0) will no longer work in the RHS.
+ Plus it requires non-trivial refactorings to both the simple optimiser (in
+ the way `subst_opt_bndr` is used) as well as the Simplifier (in the way
+ `simplRecBndrs` and `simplRecJoinBndrs` is used), modifying the SimplEnv's
+ substitution twice in the process. A very complicated stop-gap.
+
+Fix 2: Pass the set of enclosing recursive binders to `tryEtaReduce`; these are
+ the ones we should not eta-reduce. All call-site must maintain this set.
+ Example:
+ rec { f1 = ....rec { g = ... (\x. g x)...(\y. f2 y)... }...
+ ; f2 = ...f1... }
+ when eta-reducing those inner lambdas, we need to know that we are in the
+ rec group for {f1, f2, g}.
+ This is very much like the solution in Note [Speculative evaluation] in
+ GHC.CoreToStg.Prep.
+ It is a bit tiresome to maintain this info, because it means another field
+ in SimplEnv and SimpleOptEnv.
+
+We implement Fix (2) because of it isn't as complicated to maintain as (1).
+Plus, it is the correct fix to begin with. After all, the arity is correct,
+but doing the transformation isn't. The moving parts are:
+ * A field `scRecIds` in `SimplEnv` tracks the enclosing recursive binders
+ * We extend the `scRecIds` set in `GHC.Core.Opt.Simplify.simplRecBind`
+ * We consult the set in `is_eta_reduction_sound` in `tryEtaReduce`
+The situation is very similar to Note [Speculative evaluation] which has the
+same fix.
-}
-- | `tryEtaReduce [x,y,z] e sd` returns `Just e'` if `\x y z -> e` is evaluated
-- according to `sd` and can soundly and gainfully be eta-reduced to `e'`.
-- See Note [Eta reduction soundness]
-- and Note [Eta reduction makes sense] when that is the case.
-tryEtaReduce :: [Var] -> CoreExpr -> SubDemand -> Maybe CoreExpr
+tryEtaReduce :: UnVarSet -> [Var] -> CoreExpr -> SubDemand -> Maybe CoreExpr
-- Return an expression equal to (\bndrs. body)
-tryEtaReduce bndrs body eval_sd
+tryEtaReduce rec_ids bndrs body eval_sd
= go (reverse bndrs) body (mkRepReflCo (exprType body))
where
incoming_arity = count isId bndrs -- See Note [Eta reduction makes sense], point (2)
@@ -2347,9 +2403,11 @@ tryEtaReduce bndrs body eval_sd
---------------
-- See Note [Eta reduction soundness], this is THE place to check soundness!
is_eta_reduction_sound fun =
+ -- Don't eta-reduce in fun in its own recursive RHSs
+ not (fun `elemUnVarSet` rec_ids) -- criterion (R)
-- Check that eta-reduction won't make the program stricter...
- (fun_arity fun >= incoming_arity -- criterion (A) and (E)
- || all_calls_with_arity incoming_arity) -- criterion (S)
+ && (fun_arity fun >= incoming_arity -- criterion (A) and (E)
+ || all_calls_with_arity incoming_arity) -- criterion (S)
-- ... and that the function can be eta reduced to arity 0
-- without violating invariants of Core and GHC
&& canEtaReduceToArity fun 0 0 -- criteria (L), (J), (W), (B)
@@ -2358,9 +2416,6 @@ tryEtaReduce bndrs body eval_sd
---------------
fun_arity fun
- | isLocalId fun
- , isStrongLoopBreaker (idOccInfo fun) = 0
- -- See Note [Eta reduction makes sense], point (3)
| arity > 0 = arity
| isEvaldUnfolding (idUnfolding fun) = 1
-- See Note [Eta reduction soundness], criterion (E)
diff --git a/compiler/GHC/Core/Opt/Simplify.hs b/compiler/GHC/Core/Opt/Simplify.hs
index c44fd1d62a..b5dac4d385 100644
--- a/compiler/GHC/Core/Opt/Simplify.hs
+++ b/compiler/GHC/Core/Opt/Simplify.hs
@@ -261,9 +261,11 @@ simplRecBind :: SimplEnv -> BindContext
-> [(InId, InExpr)]
-> SimplM (SimplFloats, SimplEnv)
simplRecBind env0 bind_cxt pairs0
- = do { (env_with_info, triples) <- mapAccumLM add_rules env0 pairs0
- ; (rec_floats, env1) <- go env_with_info triples
- ; return (mkRecFloats rec_floats, env1) }
+ = do { (env1, triples) <- mapAccumLM add_rules env0 pairs0
+ ; let new_bndrs = map sndOf3 triples
+ ; (rec_floats, env2) <- enterRecGroupRHSs env1 new_bndrs $ \env ->
+ go env triples
+ ; return (mkRecFloats rec_floats, env2) }
where
add_rules :: SimplEnv -> (InBndr,InExpr) -> SimplM (SimplEnv, (InBndr, OutBndr, InExpr))
-- Add the (substituted) rules to the binder
diff --git a/compiler/GHC/Core/Opt/Simplify/Env.hs b/compiler/GHC/Core/Opt/Simplify/Env.hs
index 5defa782e0..30afb9aac2 100644
--- a/compiler/GHC/Core/Opt/Simplify/Env.hs
+++ b/compiler/GHC/Core/Opt/Simplify/Env.hs
@@ -17,7 +17,7 @@ module GHC.Core.Opt.Simplify.Env (
zapSubstEnv, setSubstEnv, bumpCaseDepth,
getInScope, setInScopeFromE, setInScopeFromF,
setInScopeSet, modifyInScope, addNewInScopeIds,
- getSimplRules,
+ getSimplRules, enterRecGroupRHSs,
-- * Substitution results
SimplSR(..), mkContEx, substId, lookupRecBndr,
@@ -56,6 +56,7 @@ import GHC.Types.Var
import GHC.Types.Var.Env
import GHC.Types.Var.Set
import GHC.Data.OrdList
+import GHC.Data.Graph.UnVar
import GHC.Types.Id as Id
import GHC.Core.Make ( mkWildValBinder, mkCoreLet )
import GHC.Driver.Session ( DynFlags )
@@ -97,6 +98,10 @@ data SimplEnv
, seCvSubst :: CvSubstEnv -- InCoVar |--> OutCoercion
, seIdSubst :: SimplIdSubst -- InId |--> OutExpr
+ -- | Fast OutVarSet tracking which recursive RHSs we are analysing.
+ -- See Note [Eta reduction in recursive RHSs] in GHC.Core.Opt.Arity.
+ , seRecIds :: !UnVarSet
+
----------- Dynamic part of the environment -----------
-- Dynamic in the sense of describing the setup where
-- the expression finally ends up
@@ -287,6 +292,7 @@ mkSimplEnv mode
, seTvSubst = emptyVarEnv
, seCvSubst = emptyVarEnv
, seIdSubst = emptyVarEnv
+ , seRecIds = emptyUnVarSet
, seCaseDepth = 0 }
-- The top level "enclosing CC" is "SUBSUMED".
@@ -392,6 +398,13 @@ modifyInScope :: SimplEnv -> CoreBndr -> SimplEnv
modifyInScope env@(SimplEnv {seInScope = in_scope}) v
= env {seInScope = extendInScopeSet in_scope v}
+enterRecGroupRHSs :: SimplEnv -> [OutBndr] -> (SimplEnv -> SimplM (r, SimplEnv))
+ -> SimplM (r, SimplEnv)
+enterRecGroupRHSs env bndrs k = do
+ --pprTraceM "enterRecGroupRHSs" (ppr bndrs)
+ (r, env'') <- k env{seRecIds = extendUnVarSetList bndrs (seRecIds env)}
+ return (r, env''{seRecIds = seRecIds env})
+
{- Note [Setting the right in-scope set]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Consider
@@ -892,31 +905,18 @@ seqIds (id:ids) = seqId id `seq` seqIds ids
Note [Arity robustness]
~~~~~~~~~~~~~~~~~~~~~~~
We *do* transfer the arity from the in_id of a let binding to the
-out_id. This is important, so that the arity of an Id is visible in
-its own RHS. For example:
- f = \x. ....g (\y. f y)....
-We can eta-reduce the arg to g, because f is a value. But that
-needs to be visible.
-
-This interacts with the 'state hack' too:
- f :: Bool -> IO Int
- f = \x. case x of
- True -> f y
- False -> \s -> ...
-Can we eta-expand f? Only if we see that f has arity 1, and then we
-take advantage of the 'state hack' on the result of
-(f y) :: State# -> (State#, Int) to expand the arity one more.
-
-There is a disadvantage though. Making the arity visible in the RHS
-allows us to eta-reduce
- f = \x -> f x
-to
- f = f
-which technically is not sound. We take care of that in point (3) of
-Note [Eta reduction makes sense].
-Another idea is to ensure that f's arity never decreases; its arity started as
-1, and we should never eta-reduce below that.
-
+out_id so that its arity is visible in its RHS. Examples:
+
+ * f = \x y. let g = \p q. f (p+q) in Just (...g..g...)
+ Here we want to give `g` arity 3 and eta-expand. `findRhsArity` will have a
+ hard time figuring that out when `f` only has arity 0 in its own RHS.
+ * f = \x y. ....(f `seq` blah)....
+ We want to drop the seq.
+ * f = \x. g (\y. f y)
+ You'd think we could eta-reduce `\y. f y` to `f` here. And indeed, that is true.
+ Unfortunately, it is not sound in general to eta-reduce in f's RHS.
+ Example: `f = \x. f x`. See Note [Eta reduction in recursive RHSs] for how
+ we prevent that.
Note [Robust OccInfo]
~~~~~~~~~~~~~~~~~~~~~
diff --git a/compiler/GHC/Core/Opt/Simplify/Utils.hs b/compiler/GHC/Core/Opt/Simplify/Utils.hs
index d0a7abb84f..f209713de7 100644
--- a/compiler/GHC/Core/Opt/Simplify/Utils.hs
+++ b/compiler/GHC/Core/Opt/Simplify/Utils.hs
@@ -1662,6 +1662,7 @@ rebuildLam env bndrs body cont
; try_eta dflags bndrs body }
where
mode = getMode env
+ rec_ids = seRecIds env
in_scope = getInScope env -- Includes 'bndrs'
mb_rhs = contIsRhs cont
@@ -1678,7 +1679,7 @@ rebuildLam env bndrs body cont
try_eta dflags bndrs body
| -- Try eta reduction
gopt Opt_DoEtaReduction dflags
- , Just etad_lam <- tryEtaReduce bndrs body (eval_sd dflags)
+ , Just etad_lam <- tryEtaReduce rec_ids bndrs body (eval_sd dflags)
= do { tick (EtaReduction (head bndrs))
; return etad_lam }
diff --git a/compiler/GHC/Core/SimpleOpt.hs b/compiler/GHC/Core/SimpleOpt.hs
index 2db7ee3373..1d604120b9 100644
--- a/compiler/GHC/Core/SimpleOpt.hs
+++ b/compiler/GHC/Core/SimpleOpt.hs
@@ -52,6 +52,7 @@ import GHC.Utils.Panic
import GHC.Utils.Panic.Plain
import GHC.Utils.Misc
import GHC.Data.Maybe ( orElse )
+import GHC.Data.Graph.UnVar
import Data.List (mapAccumL)
import qualified Data.ByteString as BS
@@ -191,6 +192,10 @@ data SimpleOptEnv
, soe_subst :: Subst
-- ^ Deals with cloning; includes the InScopeSet
+
+ , soe_rec_ids :: !UnVarSet
+ -- ^ Fast OutVarSet tracking which recursive RHSs we are analysing.
+ -- See Note [Eta reduction in recursive RHSs]
}
instance Outputable SimpleOptEnv where
@@ -200,9 +205,10 @@ instance Outputable SimpleOptEnv where
<+> text "}"
emptyEnv :: SimpleOpts -> SimpleOptEnv
-emptyEnv opts = SOE { soe_inl = emptyVarEnv
- , soe_subst = emptySubst
- , soe_opts = opts }
+emptyEnv opts = SOE { soe_inl = emptyVarEnv
+ , soe_subst = emptySubst
+ , soe_rec_ids = emptyUnVarSet
+ , soe_opts = opts }
soeZapSubst :: SimpleOptEnv -> SimpleOptEnv
soeZapSubst env@(SOE { soe_subst = subst })
@@ -215,6 +221,13 @@ soeSetInScope :: InScopeSet -> SimpleOptEnv -> SimpleOptEnv
soeSetInScope in_scope env2@(SOE { soe_subst = subst2 })
= env2 { soe_subst = setInScope subst2 in_scope }
+enterRecGroupRHSs :: SimpleOptEnv -> [OutBndr] -> (SimpleOptEnv -> (SimpleOptEnv, r))
+ -> (SimpleOptEnv, r)
+enterRecGroupRHSs env bndrs k
+ = (env'{soe_rec_ids = soe_rec_ids env}, r)
+ where
+ (env', r) = k env{soe_rec_ids = extendUnVarSetList bndrs (soe_rec_ids env)}
+
---------------
simple_opt_clo :: InScopeSet
-> SimpleClo
@@ -226,6 +239,7 @@ simple_opt_expr :: HasCallStack => SimpleOptEnv -> InExpr -> OutExpr
simple_opt_expr env expr
= go expr
where
+ rec_ids = soe_rec_ids env
subst = soe_subst env
in_scope = substInScope subst
in_scope_env = (in_scope, simpleUnfoldingFun)
@@ -288,14 +302,17 @@ simple_opt_expr env expr
----------------------
-- go_lam tries eta reduction
+ -- It is quite important that it does so. I tried removing this code and
+ -- got a lot of regressions, e.g., +11% ghc/alloc in T18223 and many
+ -- run/alloc increases. Presumably RULEs are affected.
go_lam env bs' (Lam b e)
= go_lam env' (b':bs') e
where
(env', b') = subst_opt_bndr env b
go_lam env bs' e
| so_eta_red (soe_opts env)
- , Just etad_e <- tryEtaReduce bs e' topSubDmd = etad_e
- | otherwise = mkLams bs e'
+ , Just etad_e <- tryEtaReduce rec_ids bs e' topSubDmd = etad_e
+ | otherwise = mkLams bs e'
where
bs = reverse bs'
e' = simple_opt_expr env e
@@ -408,12 +425,13 @@ simple_opt_bind env (NonRec b r) top_level
(env', mb_pr) = simple_bind_pair env b' Nothing (env,r') top_level
simple_opt_bind env (Rec prs) top_level
- = (env'', res_bind)
+ = (env2, res_bind)
where
res_bind = Just (Rec (reverse rev_prs'))
prs' = joinPointBindings_maybe prs `orElse` prs
- (env', bndrs') = subst_opt_bndrs env (map fst prs')
- (env'', rev_prs') = foldl' do_pr (env', []) (prs' `zip` bndrs')
+ (env1, bndrs') = subst_opt_bndrs env (map fst prs')
+ (env2, rev_prs') = enterRecGroupRHSs env1 bndrs' $ \env ->
+ foldl' do_pr (env, []) (prs' `zip` bndrs')
do_pr (env, prs) ((b,r), b')
= (env', case mb_pr of
Just pr -> pr : prs
diff --git a/testsuite/tests/arityanal/should_compile/Arity03.stderr b/testsuite/tests/arityanal/should_compile/Arity03.stderr
index f41fc1552c..652fcde173 100644
--- a/testsuite/tests/arityanal/should_compile/Arity03.stderr
+++ b/testsuite/tests/arityanal/should_compile/Arity03.stderr
@@ -26,12 +26,7 @@ fac = \ (x :: Int) -> case x of { GHC.Types.I# ww -> case F3.$wfac ww of ww1 { _
-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
f3 :: Int -> Int
-[GblId,
- Arity=1,
- Str=<1!P(1L)>,
- Cpr=1,
- Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=ALWAYS_IF(arity=1,unsat_ok=True,boring_ok=True)
- Tmpl= fac}]
+[GblId, Arity=1, Str=<1!P(1L)>, Cpr=1, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=ALWAYS_IF(arity=0,unsat_ok=True,boring_ok=True)}]
f3 = fac
diff --git a/testsuite/tests/arityanal/should_run/Makefile b/testsuite/tests/arityanal/should_run/Makefile
new file mode 100644
index 0000000000..9101fbd40a
--- /dev/null
+++ b/testsuite/tests/arityanal/should_run/Makefile
@@ -0,0 +1,3 @@
+TOP=../../..
+include $(TOP)/mk/boilerplate.mk
+include $(TOP)/mk/test.mk
diff --git a/testsuite/tests/arityanal/should_run/T21652.hs b/testsuite/tests/arityanal/should_run/T21652.hs
new file mode 100644
index 0000000000..16fda0aeaa
--- /dev/null
+++ b/testsuite/tests/arityanal/should_run/T21652.hs
@@ -0,0 +1,10 @@
+import GHC.Exts
+
+f, g :: a -> a
+f = g
+g x = f x
+{-# NOINLINE f #-}
+{-# NOINLINE g #-}
+
+-- should print done, not <<loop>>
+main = lazy g `seq` putStrLn "done"
diff --git a/testsuite/tests/arityanal/should_run/T21652.stdout b/testsuite/tests/arityanal/should_run/T21652.stdout
new file mode 100644
index 0000000000..19f86f493a
--- /dev/null
+++ b/testsuite/tests/arityanal/should_run/T21652.stdout
@@ -0,0 +1 @@
+done
diff --git a/testsuite/tests/arityanal/should_run/all.T b/testsuite/tests/arityanal/should_run/all.T
new file mode 100644
index 0000000000..a6b06fbb15
--- /dev/null
+++ b/testsuite/tests/arityanal/should_run/all.T
@@ -0,0 +1,2 @@
+# Regression tests
+test('T21652', [ only_ways(['optasm']) ], compile_and_run, [''])
diff --git a/testsuite/tests/deSugar/should_compile/T19969.stderr b/testsuite/tests/deSugar/should_compile/T19969.stderr
index 5e23785472..3ded6f27a4 100644
--- a/testsuite/tests/deSugar/should_compile/T19969.stderr
+++ b/testsuite/tests/deSugar/should_compile/T19969.stderr
@@ -1,7 +1,7 @@
==================== Tidy Core ====================
Result size of Tidy Core
- = {terms: 12, types: 18, coercions: 0, joins: 0/0}
+ = {terms: 8, types: 14, coercions: 0, joins: 0/0}
Rec {
-- RHS size: {terms: 3, types: 2, coercions: 0, joins: 0/0}
@@ -10,7 +10,7 @@ f [Occ=LoopBreaker] :: [Int] -> [Int]
f = \ (x :: [Int]) -> f x
end Rec }
--- RHS size: {terms: 3, types: 2, coercions: 0, joins: 0/0}
+-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
g [InlPrag=INLINE (sat-args=1)] :: [Int] -> [Int]
[GblId,
Arity=1,
@@ -19,10 +19,10 @@ g [InlPrag=INLINE (sat-args=1)] :: [Int] -> [Int]
Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True,
Guidance=ALWAYS_IF(arity=1,unsat_ok=False,boring_ok=True)
- Tmpl= \ (x [Occ=Once1] :: [Int]) -> f x}]
-g = \ (x :: [Int]) -> f x
+ Tmpl= f}]
+g = f
--- RHS size: {terms: 3, types: 2, coercions: 0, joins: 0/0}
+-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
h [InlPrag=INLINE (sat-args=1)] :: [Int] -> [Int]
[GblId,
Arity=1,
@@ -31,8 +31,8 @@ h [InlPrag=INLINE (sat-args=1)] :: [Int] -> [Int]
Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True,
Guidance=ALWAYS_IF(arity=1,unsat_ok=False,boring_ok=True)
- Tmpl= \ (x [Occ=Once1] :: [Int]) -> f x}]
-h = \ (x :: [Int]) -> f x
+ Tmpl= f}]
+h = f