[Git][ghc/ghc][wip/T17910] Try not doing floatConsts
Simon Peyton Jones (@simonpj)
gitlab at gitlab.haskell.org
Thu Aug 31 15:25:25 UTC 2023
Simon Peyton Jones pushed to branch wip/T17910 at Glasgow Haskell Compiler / GHC
Commits:
9bedd485 by Simon Peyton Jones at 2023-08-31T16:23:58+01:00
Try not doing floatConsts
This avoid flattening, and generating lots of top level
bindings. Instead do it in late-lambda-lift.
I moved late-lambda-lift to run with -O because it is cheap
and valuable. That's a somewhat orthogonal change, probably
should test separately.
- - - - -
8 changed files:
- compiler/GHC/Core/Opt/Pipeline.hs
- compiler/GHC/Core/Opt/SetLevels.hs
- compiler/GHC/Driver/DynFlags.hs
- compiler/GHC/Stg/Lift.hs
- compiler/GHC/Stg/Lift/Analysis.hs
- compiler/GHC/Stg/Lift/Monad.hs
- compiler/GHC/Stg/Syntax.hs
- testsuite/tests/perf/compiler/LargeRecord.hs
Changes:
=====================================
compiler/GHC/Core/Opt/Pipeline.hs
=====================================
@@ -215,8 +215,8 @@ getCoreToDo dflags hpt_rule_base extra_vars
if full_laziness then
CoreDoFloatOutwards FloatOutSwitches {
- floatOutLambdas = Just 0,
- floatOutConstants = False,
+ floatOutLambdas = Just 0,
+ floatOutConstants = False,
floatOutOverSatApps = False,
floatToTopLevelOnly = False }
-- Was: gentleFloatOutSwitches
@@ -279,7 +279,7 @@ getCoreToDo dflags hpt_rule_base extra_vars
runWhen full_laziness $
CoreDoFloatOutwards FloatOutSwitches {
floatOutLambdas = floatLamArgs dflags,
- floatOutConstants = True,
+ floatOutConstants = False,
floatOutOverSatApps = True,
floatToTopLevelOnly = False },
-- nofib/spectral/hartel/wang doubles in speed if you
=====================================
compiler/GHC/Core/Opt/SetLevels.hs
=====================================
@@ -739,10 +739,10 @@ lvlMFE env strict_ctxt ann_expr
-- See Note [Floating to the top]
saves_alloc = isTopLvl dest_lvl
&& (floatConsts env || is_function || is_bot_lam)
- -- Always float constant lambdas
- -- T5237 is a good example
+ -- Always float constant lambdas
+ -- T5237 is a good example
&& ( not strict_ctxt -- (a)
- || exprIsHNF expr -- (b)
+ || exprIsExpandable expr -- (b)
|| (is_bot_lam && escapes_value_lam)) -- (c)
hasFreeJoin :: LevelEnv -> DVarSet -> Bool
=====================================
compiler/GHC/Driver/DynFlags.hs
=====================================
@@ -1249,7 +1249,7 @@ optLevelFlags -- see Note [Documenting optimisation flags]
, ([1,2], Opt_CmmStaticPred)
, ([1,2], Opt_CSE)
, ([1,2], Opt_StgCSE)
- , ([2], Opt_StgLiftLams)
+ , ([1,2], Opt_StgLiftLams)
, ([1,2], Opt_CmmControlFlow)
, ([1,2], Opt_EnableRewriteRules)
=====================================
compiler/GHC/Stg/Lift.hs
=====================================
@@ -31,7 +31,6 @@ import GHC.Utils.Outputable
import GHC.Utils.Panic
import GHC.Types.Var.Set
import Control.Monad ( when )
-import Data.Maybe ( isNothing )
-- Note [Late lambda lifting in STG]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -199,9 +198,12 @@ liftRhs
-> LlStgRhs
-> LiftM OutStgRhs
liftRhs mb_former_fvs rhs@(StgRhsCon ccs con mn ts args typ)
- = assertPpr (isNothing mb_former_fvs)
+ = assertPpr (case mb_former_fvs of
+ Nothing -> True
+ Just fvs -> isEmptyDVarSet fvs)
(text "Should never lift a constructor"
$$ pprStgRhs panicStgPprOpts rhs) $
+ -- We should never float a constructor, unless it's a constant
StgRhsCon ccs con mn ts <$> traverse liftArgs args <*> pure typ
liftRhs Nothing (StgRhsClosure _ ccs upd infos body typ) =
-- This RHS wasn't lifted.
@@ -215,17 +217,16 @@ liftRhs (Just former_fvs) (StgRhsClosure _ ccs upd infos body typ) =
liftArgs :: InStgArg -> LiftM OutStgArg
liftArgs a@(StgLitArg _) = pure a
-liftArgs (StgVarArg occ) = do
- assertPprM (not <$> isLifted occ) (text "StgArgs should never be lifted" $$ ppr occ)
- StgVarArg <$> substOcc occ
+liftArgs (StgVarArg x) = do { (x', fvs') <- substOcc x
+ ; assertPpr (null fvs') (ppr x <+> ppr x' $$ ppr fvs') $
+ pure (StgVarArg x') }
liftExpr :: LlStgExpr -> LiftM OutStgExpr
liftExpr (StgLit lit) = pure (StgLit lit)
liftExpr (StgTick t e) = StgTick t <$> liftExpr e
liftExpr (StgApp f args) = do
- f' <- substOcc f
+ (f',fvs') <- substOcc f
args' <- traverse liftArgs args
- fvs' <- formerFreeVars f
let top_lvl_args = map StgVarArg fvs' ++ args'
pure (StgApp f' top_lvl_args)
liftExpr (StgConApp con mn args tys) = StgConApp con mn <$> traverse liftArgs args <*> pure tys
=====================================
compiler/GHC/Stg/Lift/Analysis.hs
=====================================
@@ -43,72 +43,87 @@ import GHC.Types.Var.Set
import Data.Maybe ( mapMaybe )
--- Note [When to lift]
--- ~~~~~~~~~~~~~~~~~~~
--- $when
--- The analysis proceeds in two steps:
---
--- 1. It tags the syntax tree with analysis information in the form of
--- 'BinderInfo' at each binder and 'Skeleton's at each let-binding
--- by 'tagSkeletonTopBind' and friends.
--- 2. The resulting syntax tree is treated by the "GHC.Stg.Lift"
--- module, calling out to 'goodToLift' to decide if a binding is worthwhile
--- to lift.
--- 'goodToLift' consults argument occurrence information in 'BinderInfo'
--- and estimates 'closureGrowth', for which it needs the 'Skeleton'.
---
--- So the annotations from 'tagSkeletonTopBind' ultimately fuel 'goodToLift',
--- which employs a number of heuristics to identify and exclude lambda lifting
--- opportunities deemed non-beneficial:
---
--- [Top-level bindings] can't be lifted.
--- [Thunks] and data constructors shouldn't be lifted in order not to destroy
--- sharing.
--- [Argument occurrences] #arg_occs# of binders prohibit them to be lifted.
--- Doing the lift would re-introduce the very allocation at call sites that
--- we tried to get rid off in the first place. We capture analysis
--- information in 'BinderInfo'. Note that we also consider a nullary
--- application as argument occurrence, because it would turn into an n-ary
--- partial application created by a generic apply function. This occurs in
--- CPS-heavy code like the CS benchmark.
--- [Join points] should not be lifted, simply because there's no reduction in
--- allocation to be had.
--- [Abstracting over join points] destroys join points, because they end up as
--- arguments to the lifted function.
--- [Abstracting over known local functions] turns a known call into an unknown
--- call (e.g. some @stg_ap_*@), which is generally slower. Can be turned off
--- with @-fstg-lift-lams-known at .
--- [Calling convention] Don't lift when the resulting function would have a
--- higher arity than available argument registers for the calling convention.
--- Can be influenced with @-fstg-lift-(non)rec-args(-any)@.
--- [Closure growth] introduced when former free variables have to be available
--- at call sites may actually lead to an increase in overall allocations
--- resulting from a lift. Estimating closure growth is described in
--- "GHC.Stg.Lift.Analysis#clogro" and is what most of this module is ultimately
--- concerned with.
---
--- There's a <https://gitlab.haskell.org/ghc/ghc/wikis/late-lam-lift wiki page> with
--- some more background and history.
-
--- Note [Estimating closure growth]
--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--- $clogro
--- We estimate closure growth by abstracting the syntax tree into a 'Skeleton',
--- capturing only syntactic details relevant to 'closureGrowth', such as
---
--- * 'ClosureSk', representing closure allocation.
--- * 'RhsSk', representing a RHS of a binding and how many times it's called
--- by an appropriate 'Card'.
--- * 'AltSk', 'BothSk' and 'NilSk' for choice, sequence and empty element.
---
--- This abstraction is mostly so that the main analysis function 'closureGrowth'
--- can stay simple and focused. Also, skeletons tend to be much smaller than
--- the syntax tree they abstract, so it makes sense to construct them once and
--- and operate on them instead of the actual syntax tree.
---
--- A more detailed treatment of computing closure growth, including examples,
--- can be found in the paper referenced from the
--- <https://gitlab.haskell.org/ghc/ghc/wikis/late-lam-lift wiki page>.
+{- Note [When to lift]
+~~~~~~~~~~~~~~~~~~~~~~
+$when
+The analysis proceeds in two steps:
+
+ 1. It tags the syntax tree with analysis information in the form of
+ 'BinderInfo' at each binder and 'Skeleton's at each let-binding
+ by 'tagSkeletonTopBind' and friends.
+ 2. The resulting syntax tree is treated by the "GHC.Stg.Lift"
+ module, calling out to 'goodToLift' to decide if a binding is worthwhile
+ to lift.
+ 'goodToLift' consults argument occurrence information in 'BinderInfo'
+ and estimates 'closureGrowth', for which it needs the 'Skeleton'.
+
+So the annotations from 'tagSkeletonTopBind' ultimately fuel 'goodToLift',
+which employs a number of heuristics to identify and exclude lambda lifting
+opportunities deemed non-beneficial:
+
+* [WL1: Top-level bindings] can't be lifted.
+
+* [WL2: Thunks] and data constructors shouldn't be lifted in order not to destroy
+ sharing.
+
+* [WL3: Argument occurrences] #arg_occs# of binders prohibit them to be lifted.
+ Doing the lift would re-introduce the very allocation at call sites that
+ we tried to get rid of in the first place. Example
+ g y = let f x = ...x..y...
+ in map f xs
+ No point in lambda-lifting f:
+ f' y x = ...x..y...
+ g y = let f = f' y in map f xs
+ because we still have a closure allocation for f!
+
+ We capture analysis information in 'BinderInfo'. Note that we also consider a
+ nullary application as argument occurrence, because it would turn into an
+ n-ary partial application created by a generic apply function. This occurs in
+ CPS-heavy code like the CS benchmark.
+
+* [WL4: Join points] should not be lifted, simply because there's no reduction in
+ allocation to be had.
+
+* [WL5: Abstracting over join points] destroys join points, because they end up as
+ arguments to the lifted function.
+
+* [WL6: Abstracting over known local functions] turns a known call into an unknown
+ call (e.g. some @stg_ap_*@), which is generally slower. Can be turned off
+ with @-fstg-lift-lams-known at .
+
+* [WL7: Calling convention] Don't lift when the resulting function would have a
+ higher arity than available argument registers for the calling convention.
+ Can be influenced with @-fstg-lift-(non)rec-args(-any)@.
+
+* [WL8: Closure growth] introduced when former free variables have to be available
+ at call sites may actually lead to an increase in overall allocations
+ resulting from a lift. Estimating closure growth is described in
+ "GHC.Stg.Lift.Analysis#clogro" and is what most of this module is ultimately
+ concerned with.
+
+There's a <https://gitlab.haskell.org/ghc/ghc/wikis/late-lam-lift wiki page> with
+some more background and history.
+
+Note [Estimating closure growth]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+$clogro
+We estimate closure growth by abstracting the syntax tree into a 'Skeleton',
+capturing only syntactic details relevant to 'closureGrowth', such as
+
+ * 'ClosureSk', representing closure allocation.
+ * 'RhsSk', representing a RHS of a binding and how many times it's called
+ by an appropriate 'Card'.
+ * 'AltSk', 'BothSk' and 'NilSk' for choice, sequence and empty element.
+
+This abstraction is mostly so that the main analysis function 'closureGrowth'
+can stay simple and focused. Also, skeletons tend to be much smaller than
+the syntax tree they abstract, so it makes sense to construct them once and
+and operate on them instead of the actual syntax tree.
+
+A more detailed treatment of computing closure growth, including examples,
+can be found in the paper referenced from the
+<https://gitlab.haskell.org/ghc/ghc/wikis/late-lam-lift wiki page>.
+-}
llTrace :: String -> SDoc -> a -> a
llTrace _ _ c = c
@@ -282,30 +297,38 @@ goodToLift
-> Maybe DIdSet -- ^ @Just abs_ids@ <=> This binding is beneficial to
-- lift and @abs_ids@ are the variables it would
-- abstract over
-goodToLift cfg top_lvl rec_flag expander pairs scope = decide
- [ ("top-level", isTopLevel top_lvl) -- keep in sync with Note [When to lift]
- , ("memoized", any_memoized)
- , ("argument occurrences", arg_occs)
- , ("join point", is_join_point)
- , ("abstracts join points", abstracts_join_ids)
- , ("abstracts known local function", abstracts_known_local_fun)
- , ("args spill on stack", args_spill_on_stack)
- , ("increases allocation", inc_allocs)
- ] where
+goodToLift cfg top_lvl rec_flag expander pairs scope
+ | not (fancy_or deciders)
+ = llTrace "stgLiftLams:lifting" (ppr bndrs) $
+ Just expanded_abs_ids
+ | otherwise
+ = Nothing
+
+ where
+ deciders :: [(String,Bool)] -- True <=> do not lift
+ -- Keep in sync with Note [When to lift]
+ deciders
+ = [ ("top-level", isTopLevel top_lvl) -- [WL1: Top-level bindings]
+ , ("memoized", any_memoized) -- [WL2: Thunks]
+ , ("argument occurrences", arg_occs) -- [WL3: Argument occurrences]
+ , ("join point", is_join_point) -- [WL4: Join points]
+ , ("abstracts join points", abstracts_join_ids) -- [WL5: Abstracting over join points]
+ , ("abstracts known local function", abstracts_known_local_fun)
+ -- [WL6: Abstracting over known local functions]
+ , ("args spill on stack", args_spill_on_stack) -- [WL7: Calling convention]
+ , ("increases allocation", inc_allocs) -- [WL8: Closure growth]
+ ]
+
profile = c_targetProfile cfg
platform = profilePlatform profile
- decide deciders
- | not (fancy_or deciders)
- = llTrace "stgLiftLams:lifting"
- (ppr bndrs <+> ppr abs_ids $$
- ppr allocs $$
- ppr scope) $
- Just abs_ids
- | otherwise
- = Nothing
ppr_deciders = vcat . map (text . fst) . filter snd
fancy_or deciders
- = llTrace "stgLiftLams:goodToLift" (ppr bndrs $$ ppr_deciders deciders) $
+ = llTrace "stgLiftLams:goodToLift?"
+ (vcat [ text "bndrs:" <+> ppr bndrs
+ , text "fvs:" <+> ppr fvs
+ , text "abs_ids:" <+> ppr abs_ids
+ , text "expanded_abs_ids" <+> ppr expanded_abs_ids
+ , text "bad deciders:" <+> ppr_deciders deciders ]) $
any snd deciders
bndrs = map (binderInfoBndr . fst) pairs
@@ -316,33 +339,41 @@ goodToLift cfg top_lvl rec_flag expander pairs scope = decide
-- the lifted binding would abstract over. We have to merge the free
-- variables of all RHS to get the set of variables that will have to be
-- passed through parameters.
- fvs = unionDVarSets (map freeVarsOfRhs rhss)
- -- To lift the binding to top-level, we want to delete the lifted binders
+ --
+ -- delVarSetList: to lift the binding to top-level, we want to delete the lifted binders
-- themselves from the free var set. Local let bindings track recursive
-- occurrences in their free variable set. We neither want to apply our
-- cost model to them (see 'tagSkeletonRhs'), nor pass them as parameters
- -- when lifted, as these are known calls. We call the resulting set the
- -- identifiers we abstract over, thus @abs_ids at . These are all 'OutId's.
+ -- when lifted, as these are known calls.
+ --
+ -- expander: map to OutIds, expanding Ids that are themselves lifted
+ --
+ -- The resulting set is `expanded_abs_ids`; we will abstract over them.
-- We will save the set in 'LiftM.e_expansions' for each of the variables
-- if we perform the lift.
- abs_ids = expander (delDVarSetList fvs bndrs)
+ fvs = unionDVarSets (map freeVarsOfRhs rhss) -- InIds
+ abs_ids = delDVarSetList fvs bndrs -- InIds
+ expanded_abs_ids = expander abs_ids -- OutIds
+ no_expanded_abs_ids = isEmptyDVarSet expanded_abs_ids -- A constant expression
-- We don't lift updatable thunks or constructors
- any_memoized = any is_memoized_rhs rhss
- is_memoized_rhs StgRhsCon{} = True
- is_memoized_rhs (StgRhsClosure _ _ upd _ _ _) = isUpdatable upd
+ -- unless there are no Ids to abstract over, so it's a constant
+ any_memoized | no_expanded_abs_ids = False -- OK to lift
+ | otherwise = any is_memoized_rhs rhss
+ is_memoized_rhs (StgRhsCon{}) = True -- Never lift
+ is_memoized_rhs (StgRhsClosure _ _ upd _ _ _) = isUpdatable upd
-- Don't lift binders occurring as arguments. This would result in complex
-- argument expressions which would have to be given a name, reintroducing
-- the very allocation at each call site that we wanted to get rid off in
- -- the first place.
- arg_occs = or (mapMaybe (binderInfoOccursAsArg . fst) pairs)
+ -- the first place. Only matters if abstraction will take place
+ arg_occs = not no_expanded_abs_ids && or (mapMaybe (binderInfoOccursAsArg . fst) pairs)
-- These don't allocate anyway.
is_join_point = any isJoinId bndrs
-- Abstracting over join points/let-no-escapes spoils them.
- abstracts_join_ids = any isJoinId (dVarSetElems abs_ids)
+ abstracts_join_ids = anyDVarSet isJoinId abs_ids
-- Abstracting over known local functions that aren't floated themselves
-- turns a known, fast call into an unknown, slow call:
@@ -361,14 +392,17 @@ goodToLift cfg top_lvl rec_flag expander pairs scope = decide
-- idArity f > 0 ==> known
known_fun id = idArity id > 0
abstracts_known_local_fun
- = not (c_liftLamsKnown cfg) && any known_fun (dVarSetElems abs_ids)
+ = not (c_liftLamsKnown cfg) && anyDVarSet known_fun expanded_abs_ids
+ -- NB: expanded_abs_ids: if `f` is floated, the abs_ids for
+ -- `g` will mention `f`; but the /expanded/ abs_ids will
+ -- mention f's free vars, not f itself.
-- Number of arguments of a RHS in the current binding group if we decide
-- to lift it
n_args
= length
. StgToCmm.Closure.nonVoidIds -- void parameters don't appear in Cmm
- . (dVarSetElems abs_ids ++)
+ . (dVarSetElems expanded_abs_ids ++)
. rhsLambdaBndrs
max_n_args
| isRec rec_flag = c_liftLamsRecArgs cfg
@@ -395,7 +429,8 @@ goodToLift cfg top_lvl rec_flag expander pairs scope = decide
. expander
. flip dVarSetMinusVarSet bndrs_set
$ freeVarsOfRhs rhs
- clo_growth = closureGrowth expander (idClosureFootprint platform) bndrs_set abs_ids scope
+ clo_growth = closureGrowth expander (idClosureFootprint platform)
+ bndrs_set expanded_abs_ids scope
rhsLambdaBndrs :: LlStgRhs -> [Id]
rhsLambdaBndrs StgRhsCon{} = []
@@ -436,8 +471,8 @@ closureGrowth
-> IdSet
-- ^ Binding group for which lifting is to be decided
-> DIdSet
- -- ^ Free vars of the whole binding group prior to lifting it. These must be
- -- available at call sites if we decide to lift the binding group.
+ -- ^ Free vars (OutIds) of the whole binding group prior to lifting it. These
+ -- must be available at call sites if we decide to lift the binding group.
-> Skeleton
-- ^ Abstraction of the scope of the function
-> IntWithInf
=====================================
compiler/GHC/Stg/Lift/Monad.hs
=====================================
@@ -19,7 +19,7 @@ module GHC.Stg.Lift.Monad (
-- ** Substitution and binders
withSubstBndr, withSubstBndrs, withLiftedBndr, withLiftedBndrs,
-- ** Occurrences
- substOcc, isLifted, formerFreeVars, liftedIdsExpander
+ substOcc, isLifted, liftedIdsExpander
) where
import GHC.Prelude
@@ -65,6 +65,7 @@ data Env
= Env
{ e_config :: StgLiftConfig
-- ^ Read-only.
+
, e_subst :: !Subst
-- ^ We need to track the renamings of local 'InId's to their lifted 'OutId',
-- because shadowing might make a closure's free variables unavailable at its
@@ -74,6 +75,7 @@ data Env
-- @
-- Here, @f@ can't be lifted to top-level, because its free variable @x@ isn't
-- available at its call site.
+
, e_expansions :: !(IdEnv DIdSet)
-- ^ Lifted 'Id's don't occur as free variables in any closure anymore, because
-- they are bound at the top-level. Every occurrence must supply the formerly
@@ -295,23 +297,27 @@ withLiftedBndrs abs_ids = runContT . traverse (ContT . withLiftedBndr abs_ids)
-- | Substitutes a binder /occurrence/, which was brought in scope earlier by
-- 'withSubstBndr' \/ 'withLiftedBndr'.
-substOcc :: Id -> LiftM Id
-substOcc id = LiftM (RWS.asks (lookupIdSubst id . e_subst))
+-- Also returns an empty list for a binding that was not lifted and the list of all
+-- local variables the binding abstracts over (so, exactly the additional
+-- arguments at adjusted call sites) otherwise.
+--
+-- We are going to replace f with (f' fvs)
+substOcc :: InId -> LiftM (OutId, [OutId])
+substOcc f = LiftM (RWS.asks subst_occ)
+ where
+ subst_occ :: Env -> (OutId, [OutId])
+ subst_occ (Env { e_subst = subst, e_expansions = expansions })
+ = (lookupIdSubst f subst, get_expansions expansions)
+
+ get_expansions :: IdEnv DIdSet -> [OutId]
+ get_expansions expansions = case lookupVarEnv expansions f of
+ Nothing -> []
+ Just fvs -> dVarSetElems fvs
-- | Whether the given binding was decided to be lambda lifted.
isLifted :: InId -> LiftM Bool
isLifted bndr = LiftM (RWS.asks (elemVarEnv bndr . e_expansions))
--- | Returns an empty list for a binding that was not lifted and the list of all
--- local variables the binding abstracts over (so, exactly the additional
--- arguments at adjusted call sites) otherwise.
-formerFreeVars :: InId -> LiftM [OutId]
-formerFreeVars f = LiftM $ do
- expansions <- RWS.asks e_expansions
- pure $ case lookupVarEnv expansions f of
- Nothing -> []
- Just fvs -> dVarSetElems fvs
-
-- | Creates an /expander function/ for the current set of lifted binders.
-- This expander function will replace any 'InId' by their corresponding 'OutId'
-- and, in addition, will expand any lifted binders by the former free variables
=====================================
compiler/GHC/Stg/Syntax.hs
=====================================
@@ -492,7 +492,7 @@ stgRhsArity (StgRhsClosure _ _ _ bndrs _ _)
stgRhsArity (StgRhsCon {}) = 0
freeVarsOfRhs :: (XRhsClosure pass ~ DIdSet) => GenStgRhs pass -> DIdSet
-freeVarsOfRhs (StgRhsCon _ _ _ _ args _) = mkDVarSet [ id | StgVarArg id <- args ]
+freeVarsOfRhs (StgRhsCon _ _ _ _ args _) = mkDVarSet [ id | StgVarArg id <- args, isLocalId id ]
freeVarsOfRhs (StgRhsClosure fvs _ _ _ _ _) = fvs
{-
=====================================
testsuite/tests/perf/compiler/LargeRecord.hs
=====================================
@@ -60,6 +60,7 @@ type BigFieldList =
'[ "f1" := Int
, "f2" := Int
, "f3" := Int
+{-
, "f4" := Int
, "f5" := Int
, "f6" := Int
@@ -72,6 +73,7 @@ type BigFieldList =
, "f13" := Int
, "f14" := Int
, "f15" := Int
+-}
]
bigRec :: Record BigFieldList
@@ -79,6 +81,7 @@ bigRec =
#f1 := 1
& #f2 := 2
& #f3 := 3
+{-
& #f4 := 4
& #f5 := 5
& #f6 := 6
@@ -91,6 +94,7 @@ bigRec =
& #f13 := 13
& #f14 := 14
& #f15 := 15
+-}
& rnil
main :: IO ()
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9bedd485ba8e7b051570902fa95eb13e3d82bdfa
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9bedd485ba8e7b051570902fa95eb13e3d82bdfa
You're receiving this email because of your account on gitlab.haskell.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20230831/c87029c2/attachment-0001.html>
More information about the ghc-commits
mailing list