Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
-
4a645683
by Simon Peyton Jones at 2026-05-27T21:41:59-04:00
6 changed files:
- + changelog.d/T27261
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
- compiler/GHC/Core/Opt/Simplify/Utils.hs
- + testsuite/tests/simplCore/should_compile/T27261.hs
- + testsuite/tests/simplCore/should_compile/T27261_aux.hs
- testsuite/tests/simplCore/should_compile/all.T
Changes:
| 1 | +section: compiler
|
|
| 2 | +issues: #27261
|
|
| 3 | +mrs: !16084
|
|
| 4 | +synopsis:
|
|
| 5 | + Avoid a crash in ``mkDupableContWithDmds`` when given empty demands
|
|
| 6 | +description:
|
|
| 7 | + The case of an empty list of remaining argument demands is now explicitly
|
|
| 8 | + handled by trimming the simplifier continuation, to avoid a compiler crash
|
|
| 9 | + of the form ``Non-exhaustive patterns in dmd : cont_dmds`` or ``expectNonEmpty``
|
|
| 10 | + in ``mkDupableContWithDmds``. |
| ... | ... | @@ -62,6 +62,7 @@ import GHC.Types.Var ( isTyCoVar ) |
| 62 | 62 | import GHC.Builtin.Types.Prim( realWorldStatePrimTy )
|
| 63 | 63 | import GHC.Builtin.Names( runRWKey, seqHashKey )
|
| 64 | 64 | |
| 65 | +import qualified GHC.Data.List.Infinite as Inf
|
|
| 65 | 66 | import GHC.Data.Maybe ( isNothing, orElse, mapMaybe )
|
| 66 | 67 | import GHC.Data.FastString
|
| 67 | 68 | import GHC.Unit.Module ( moduleName )
|
| ... | ... | @@ -2444,24 +2445,9 @@ rebuildCall env arg_info _cont |
| 2444 | 2445 | |
| 2445 | 2446 | ---------- Bottoming applications --------------
|
| 2446 | 2447 | rebuildCall env (ArgInfo { ai_fun = fun, ai_args = rev_args, ai_dmds = [] }) cont
|
| 2447 | - -- When we run out of strictness args, it means
|
|
| 2448 | - -- that the call is definitely bottom; see GHC.Core.Opt.Simplify.Utils.mkArgInfo
|
|
| 2449 | - -- Then we want to discard the entire strict continuation. E.g.
|
|
| 2450 | - -- * case (error "hello") of { ... }
|
|
| 2451 | - -- * (error "Hello") arg
|
|
| 2452 | - -- * f (error "Hello") where f is strict
|
|
| 2453 | - -- etc
|
|
| 2454 | - -- Then, especially in the first of these cases, we'd like to discard
|
|
| 2455 | - -- the continuation, leaving just the bottoming expression. But the
|
|
| 2456 | - -- type might not be right, so we may have to add a coerce.
|
|
| 2457 | - | not (contIsTrivial cont) -- Only do this if there is a non-trivial
|
|
| 2458 | - -- continuation to discard, else we do it
|
|
| 2459 | - -- again and again!
|
|
| 2460 | - = seqType cont_ty `seq` -- See Note [Avoiding space leaks in OutType]
|
|
| 2461 | - return (emptyFloats env, castBottomExpr res cont_ty)
|
|
| 2462 | - where
|
|
| 2463 | - res = argInfoExpr fun rev_args
|
|
| 2464 | - cont_ty = contResultType cont
|
|
| 2448 | + -- When we run out of demands, it means that the call is definitely bottom.
|
|
| 2449 | + -- See (TC2) in Note [Trimming the continuation for bottoming functions]
|
|
| 2450 | + = rebuild env (argInfoExpr fun rev_args) (mkBottomCont cont)
|
|
| 2465 | 2451 | |
| 2466 | 2452 | ---------- Simplify type applications --------------
|
| 2467 | 2453 | rebuildCall env info (ApplyToTy { sc_arg_ty = arg_ty, sc_hole_ty = hole_ty, sc_cont = cont })
|
| ... | ... | @@ -4045,6 +4031,41 @@ When we have |
| 4045 | 4031 | then we can just duplicate those alts because the A and C cases
|
| 4046 | 4032 | will disappear immediately. This is more direct than creating
|
| 4047 | 4033 | join points and inlining them away. See #4930.
|
| 4034 | + |
|
| 4035 | +Note [Trimming the continuation for bottoming functions]
|
|
| 4036 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 4037 | +Suppose
|
|
| 4038 | + f :: Int -> Int -> Int
|
|
| 4039 | + f x = error "urk"
|
|
| 4040 | + |
|
| 4041 | + foo = f 3 4
|
|
| 4042 | + |
|
| 4043 | +f's demand signature say "after one arg I return bottom". We can drop
|
|
| 4044 | +the remaining arguments, thus
|
|
| 4045 | + |
|
| 4046 | + foo = case f 3 of {}
|
|
| 4047 | + |
|
| 4048 | +This trimming can also be done with other continuations:
|
|
| 4049 | + * case (error "hello") of { ... }
|
|
| 4050 | + * f (error "Hello") where f is strict
|
|
| 4051 | + etc
|
|
| 4052 | + |
|
| 4053 | +We implement the trimming in three parts:
|
|
| 4054 | + |
|
| 4055 | +(TC1) In `mkArgInfo`, for a bottoming function, we make a list of `RemainingArgDmds`
|
|
| 4056 | + with a finite list of elements (in the example above, just one).
|
|
| 4057 | + |
|
| 4058 | + For comparison, note that, for non-bottoming functions, the `RemainingArgDmds`
|
|
| 4059 | + always finishes with an infinite list of `topDmd`.
|
|
| 4060 | + |
|
| 4061 | +(TC2) In `rebuildCall`, when we run out of `RemainingArgDmds` we discard the
|
|
| 4062 | + remaining continuation.
|
|
| 4063 | + |
|
| 4064 | + After discarding the continuation, the types might not match, in which case
|
|
| 4065 | + we leave behind a (case <hole> of {}) wrapper. See the call to `mkBottomCont`.
|
|
| 4066 | + |
|
| 4067 | +(TC3) In `mkDupableContWithDmds`, we similarly discard the continuation when
|
|
| 4068 | + we run out of `RemainingArgDmds`.
|
|
| 4048 | 4069 | -}
|
| 4049 | 4070 | |
| 4050 | 4071 | --------------------
|
| ... | ... | @@ -4079,10 +4100,10 @@ mkDupableCont env cont |
| 4079 | 4100 | = mkDupableContWithDmds (zapSubstEnv env) (repeat topDmd) cont
|
| 4080 | 4101 | |
| 4081 | 4102 | mkDupableContWithDmds
|
| 4082 | - :: SimplEnvIS -> [Demand] -- Demands on arguments; always infinite
|
|
| 4103 | + :: SimplEnvIS -> RemainingArgDmds
|
|
| 4083 | 4104 | -> SimplCont -> SimplM ( SimplFloats, SimplCont)
|
| 4084 | 4105 | |
| 4085 | -mkDupableContWithDmds env _ cont
|
|
| 4106 | +mkDupableContWithDmds env remaining_dmds cont
|
|
| 4086 | 4107 | -- Check the invariant
|
| 4087 | 4108 | | assertPpr (checkSimplEnvIS env) (pprBadSimplEnvIS env) False
|
| 4088 | 4109 | = pprPanic "mkDupableContWithDmds" empty
|
| ... | ... | @@ -4090,6 +4111,13 @@ mkDupableContWithDmds env _ cont |
| 4090 | 4111 | | contIsDupable cont
|
| 4091 | 4112 | = return (emptyFloats env, cont)
|
| 4092 | 4113 | |
| 4114 | + -- No more demands => function is definitely bottom
|
|
| 4115 | + -- => simply trim the continuation
|
|
| 4116 | + -- c.f. the null-demands case in `rebuildCall`
|
|
| 4117 | + -- See (TC3) in Note [Trimming the continuation for bottoming functions]
|
|
| 4118 | + | null remaining_dmds
|
|
| 4119 | + = return (emptyFloats env, mkBottomCont cont)
|
|
| 4120 | + |
|
| 4093 | 4121 | mkDupableContWithDmds _ _ (Stop {}) = panic "mkDupableCont" -- Handled by previous eqn
|
| 4094 | 4122 | |
| 4095 | 4123 | mkDupableContWithDmds env dmds (CastIt { sc_co = co, sc_opt = opt, sc_cont = cont })
|
| ... | ... | @@ -4134,7 +4162,8 @@ mkDupableContWithDmds env _ |
| 4134 | 4162 | , thumbsUpPlanA cont
|
| 4135 | 4163 | = -- Use Plan A of Note [Duplicating StrictArg]
|
| 4136 | 4164 | -- pprTrace "Using plan A" (ppr (ai_fun fun) $$ text "args" <+> ppr (ai_args fun) $$ text "cont" <+> ppr cont) $
|
| 4137 | - do { let _ :| dmds = expectNonEmpty $ ai_dmds fun
|
|
| 4165 | + do { let _ :| dmds = expectNonEmpty (ai_dmds fun) -- See Invariant of StrictArg;
|
|
| 4166 | + -- ai_dmds is never empty
|
|
| 4138 | 4167 | ; (floats1, cont') <- mkDupableContWithDmds env dmds cont
|
| 4139 | 4168 | -- Use the demands from the function to add the right
|
| 4140 | 4169 | -- demand info on any bindings we make for further args
|
| ... | ... | @@ -4180,7 +4209,10 @@ mkDupableContWithDmds env dmds |
| 4180 | 4209 | -- let a = ...arg...
|
| 4181 | 4210 | -- in [...hole...] a
|
| 4182 | 4211 | -- NB: sc_dup /= OkToDup; that is caught earlier by contIsDupable
|
| 4183 | - do { let dmd:|cont_dmds = expectNonEmpty dmds
|
|
| 4212 | + do { let dmd:|cont_dmds =
|
|
| 4213 | + -- We took care to handle an empty demand list at the start,
|
|
| 4214 | + -- ensuring this call to 'expectNonEmpty' does not panic (#27261).
|
|
| 4215 | + expectNonEmpty dmds
|
|
| 4184 | 4216 | ; (floats1, cont') <- mkDupableContWithDmds env cont_dmds cont
|
| 4185 | 4217 | ; let env' = env `setInScopeFromF` floats1
|
| 4186 | 4218 | ; arg' <- simplArg env' Nothing hole_ty se arg arg_mco
|
| ... | ... | @@ -4251,7 +4283,7 @@ mkDupableStrictBind env arg_bndr join_rhs res_ty |
| 4251 | 4283 | ; let arg_info = ArgInfo { ai_fun = join_bndr
|
| 4252 | 4284 | , ai_rules = [], ai_args = []
|
| 4253 | 4285 | , ai_encl = False, ai_dmds = repeat topDmd
|
| 4254 | - , ai_discs = repeat 0 }
|
|
| 4286 | + , ai_discs = Inf.repeat 0 }
|
|
| 4255 | 4287 | ; return ( addJoinFloats (emptyFloats env) $
|
| 4256 | 4288 | unitJoinFloat $
|
| 4257 | 4289 | NonRec join_bndr $
|
| ... | ... | @@ -25,13 +25,13 @@ module GHC.Core.Opt.Simplify.Utils ( |
| 25 | 25 | StaticEnv(..),
|
| 26 | 26 | isSimplified, contIsStop,
|
| 27 | 27 | contIsDupable, contResultType, contHoleType, contHoleScaling,
|
| 28 | - contIsTrivial, contArgs, contIsRhs,
|
|
| 28 | + contIsTrivial, contArgs, contIsRhs, mkBottomCont,
|
|
| 29 | 29 | hasArgs, countArgs, contOutArgs, dropContArgs,
|
| 30 | 30 | mkBoringStop, mkRhsStop, mkLazyArgStop,
|
| 31 | 31 | interestingCallContext,
|
| 32 | 32 | |
| 33 | 33 | -- ArgInfo
|
| 34 | - ArgInfo(..), ArgSpec(..), mkArgInfo,
|
|
| 34 | + ArgInfo(..), ArgSpec(..), RemainingArgDmds, mkArgInfo,
|
|
| 35 | 35 | addValArgTo, addTyArgTo,
|
| 36 | 36 | argInfoExpr, argSpecArg,
|
| 37 | 37 | pushOutArgs, pushArgSpecs,
|
| ... | ... | @@ -54,8 +54,10 @@ import GHC.Core.Opt.Stats ( Tick(..) ) |
| 54 | 54 | import qualified GHC.Core.Subst
|
| 55 | 55 | import GHC.Core.Ppr
|
| 56 | 56 | import GHC.Core.TyCo.Ppr ( pprParendType )
|
| 57 | +import GHC.Core.TyCo.Compare ( eqTypeIgnoringMultiplicity )
|
|
| 57 | 58 | import GHC.Core.FVs
|
| 58 | 59 | import GHC.Core.Utils
|
| 60 | +import GHC.Core.Make( mkWildValBinder )
|
|
| 59 | 61 | import GHC.Core.Opt.Arity
|
| 60 | 62 | import GHC.Core.Unfold
|
| 61 | 63 | import GHC.Core.Unfold.Make
|
| ... | ... | @@ -75,6 +77,8 @@ import GHC.Types.Var.Set |
| 75 | 77 | import GHC.Types.Basic
|
| 76 | 78 | import GHC.Types.Name.Env
|
| 77 | 79 | |
| 80 | +import GHC.Data.List.Infinite ( Infinite(..) )
|
|
| 81 | +import qualified GHC.Data.List.Infinite as Inf
|
|
| 78 | 82 | import GHC.Data.OrdList ( isNilOL )
|
| 79 | 83 | import GHC.Data.FastString ( fsLit )
|
| 80 | 84 | |
| ... | ... | @@ -205,10 +209,10 @@ data SimplCont |
| 205 | 209 | |
| 206 | 210 | | StrictArg -- (StrictArg (f e1 ..en) K)[e] = K[ f e1 .. en e ]
|
| 207 | 211 | { sc_dup :: DupFlag
|
| 208 | - , sc_fun :: ArgInfo -- Specifies f, e1..en, Whether f has rules, etc
|
|
| 212 | + , sc_fun :: ArgInfo -- Specifies f, e1..en, whether f has rules, etc
|
|
| 209 | 213 | -- plus demands and discount flags for *this* arg
|
| 210 | 214 | -- and further args
|
| 211 | - -- So ai_dmds and ai_discs are never empty
|
|
| 215 | + -- Invariant: ai_dmds and ai_discs are never empty
|
|
| 212 | 216 | , sc_fun_ty :: OutType -- Type of the function (f e1 .. en),
|
| 213 | 217 | -- presumably (arg_ty -> res_ty)
|
| 214 | 218 | -- where res_ty is expected by sc_cont
|
| ... | ... | @@ -348,32 +352,41 @@ doesn't matter because we'll never compute them all. |
| 348 | 352 | |
| 349 | 353 | data ArgInfo
|
| 350 | 354 | = ArgInfo {
|
| 351 | - ai_fun :: OutId, -- The function
|
|
| 352 | - ai_args :: [ArgSpec], -- ...applied to these args (which are in *reverse* order)
|
|
| 355 | + ai_fun :: OutId, -- ^ The function
|
|
| 356 | + ai_args :: [ArgSpec], -- ^ ...applied to these args (which are in *reverse* order)
|
|
| 353 | 357 | -- NB: all these argumennts are already simplified
|
| 354 | 358 | |
| 355 | - ai_rules :: [CoreRule], -- Rules for this function
|
|
| 356 | - ai_encl :: Bool, -- Flag saying whether this function
|
|
| 357 | - -- or an enclosing one has rules (recursively)
|
|
| 358 | - -- True => be keener to inline in all args
|
|
| 359 | + ai_rules :: [CoreRule], -- ^ Rules for this function
|
|
| 360 | + ai_encl :: Bool,
|
|
| 361 | + -- ^ Flag saying whether this function or an enclosing one has rules
|
|
| 362 | + -- (recursively)
|
|
| 363 | + --
|
|
| 364 | + -- @True@ means: be keener to inline in all args
|
|
| 359 | 365 | |
| 360 | - ai_dmds :: [Demand], -- Demands on remaining value arguments (beyond ai_args)
|
|
| 361 | - -- Usually infinite, but if it is finite it guarantees
|
|
| 362 | - -- that the function diverges after being given
|
|
| 363 | - -- that number of args
|
|
| 366 | + ai_dmds :: RemainingArgDmds,
|
|
| 367 | + -- ^ Demands on remaining value arguments (beyond 'ai_args')
|
|
| 364 | 368 | |
| 365 | - ai_discs :: [Int] -- Discounts for remaining value arguments (beyond ai_args)
|
|
| 366 | - -- non-zero => be keener to inline
|
|
| 367 | - -- Always infinite
|
|
| 369 | + ai_discs :: Infinite Int
|
|
| 370 | + -- ^ Discounts for remaining value arguments (beyond 'ai_args')
|
|
| 371 | + --
|
|
| 372 | + -- A non-zero value means: be keener to inline
|
|
| 368 | 373 | }
|
| 369 | 374 | |
| 370 | -data ArgSpec
|
|
| 371 | - = ValArg { as_dmd :: Demand -- Demand placed on this argument
|
|
| 372 | - , as_arg :: OutExpr -- Apply to this (coercion or value); c.f. ApplyToVal
|
|
| 373 | - , as_hole_ty :: OutType } -- Type of the function (presumably t1 -> t2)
|
|
| 375 | +-- | 'RemainingArgDmds' gives the demands on any remaining value arguments.
|
|
| 376 | +--
|
|
| 377 | +-- It is usually infinite (with 'topDmd's in the tail), but if it is finite it
|
|
| 378 | +-- guarantees that the function diverges after being applied to that number
|
|
| 379 | +-- of arguments.
|
|
| 380 | +type RemainingArgDmds = [Demand]
|
|
| 374 | 381 | |
| 375 | - | TyArg { as_arg_ty :: OutType -- Apply to this type; c.f. ApplyToTy
|
|
| 376 | - , as_hole_ty :: OutType } -- Type of the function (presumably forall a. blah)
|
|
| 382 | +data ArgSpec
|
|
| 383 | + -- | A value argument
|
|
| 384 | + = ValArg { as_dmd :: Demand -- ^ Demand placed on this argument
|
|
| 385 | + , as_arg :: OutExpr -- ^ Apply to this (coercion or value); c.f. 'ApplyToVal'
|
|
| 386 | + , as_hole_ty :: OutType } -- ^ Type of the function (presumably @t1 -> t2@ for 'ValArg' or @forall a. blah@ for 'TyArg')
|
|
| 387 | + -- | A type argument
|
|
| 388 | + | TyArg { as_arg_ty :: OutType -- ^ Apply to this type; c.f. 'ApplyToTy'
|
|
| 389 | + , as_hole_ty :: OutType } -- ^ Type of the function (presumably @t1 -> t2@ for 'ValArg' or @forall a. blah@ for 'TyArg')
|
|
| 377 | 390 | |
| 378 | 391 | instance Outputable ArgInfo where
|
| 379 | 392 | ppr (ArgInfo { ai_fun = fun, ai_args = args, ai_dmds = dmds, ai_rules = rules })
|
| ... | ... | @@ -389,7 +402,7 @@ instance Outputable ArgSpec where |
| 389 | 402 | |
| 390 | 403 | addValArgTo :: ArgInfo -> OutExpr -> OutType -> ArgInfo
|
| 391 | 404 | addValArgTo ai arg hole_ty
|
| 392 | - | ArgInfo { ai_dmds = dmd:dmds, ai_discs = _:discs } <- ai
|
|
| 405 | + | ArgInfo { ai_dmds = dmd:dmds, ai_discs = Inf _ discs } <- ai
|
|
| 393 | 406 | -- Pop the top demand and and discounts off
|
| 394 | 407 | , let arg_spec = ValArg { as_arg = arg, as_hole_ty = hole_ty, as_dmd = dmd }
|
| 395 | 408 | = ai { ai_args = arg_spec : ai_args ai
|
| ... | ... | @@ -492,12 +505,23 @@ contIsDupable (TickIt _ k) = contIsDupable k |
| 492 | 505 | contIsTrivial :: SimplCont -> Bool
|
| 493 | 506 | contIsTrivial (Stop {}) = True
|
| 494 | 507 | contIsTrivial (ApplyToTy { sc_cont = k }) = contIsTrivial k
|
| 495 | --- This one doesn't look right. A value application is not trivial
|
|
| 496 | --- contIsTrivial (ApplyToVal { sc_arg = Coercion _, sc_cont = k }) = contIsTrivial k
|
|
| 497 | 508 | contIsTrivial (CastIt { sc_cont = k }) = contIsTrivial k
|
| 498 | 509 | contIsTrivial _ = False
|
| 499 | 510 | |
| 500 | 511 | -------------------
|
| 512 | +contStop :: SimplCont -> SimplCont
|
|
| 513 | +-- ^ Get the 'Stop' at the tail of the continuation
|
|
| 514 | +--
|
|
| 515 | +-- Always returns a continuation of form @(Stop ...)@.
|
|
| 516 | +contStop stop@(Stop {}) = stop
|
|
| 517 | +contStop (CastIt { sc_cont = k }) = contStop k
|
|
| 518 | +contStop (StrictBind { sc_cont = k }) = contStop k
|
|
| 519 | +contStop (StrictArg { sc_cont = k }) = contStop k
|
|
| 520 | +contStop (Select { sc_cont = k }) = contStop k
|
|
| 521 | +contStop (ApplyToTy { sc_cont = k }) = contStop k
|
|
| 522 | +contStop (ApplyToVal { sc_cont = k }) = contStop k
|
|
| 523 | +contStop (TickIt _ k) = contStop k
|
|
| 524 | + |
|
| 501 | 525 | contResultType :: SimplCont -> OutType
|
| 502 | 526 | contResultType (Stop ty _ _) = ty
|
| 503 | 527 | contResultType (CastIt { sc_cont = k }) = contResultType k
|
| ... | ... | @@ -651,6 +675,35 @@ contEvalContext bndrs cont = go cont |
| 651 | 675 | -- Perhaps reconstruct the demand on the scrutinee by looking at field
|
| 652 | 676 | -- and case binder dmds, see addCaseBndrDmd. No priority right now.
|
| 653 | 677 | |
| 678 | +-------------------
|
|
| 679 | +mkBottomCont ::SimplCont -> SimplCont
|
|
| 680 | +-- ^ Given a continuation `cont`, return a `cont` /of the same type/,
|
|
| 681 | +-- looking like @(case \<hole\> of {})@.
|
|
| 682 | +--
|
|
| 683 | +-- This is used when we are going to fill in the @<hole>@ with bottom.
|
|
| 684 | +-- See (TC2,3) in Note [Trimming the continuation for bottoming functions]
|
|
| 685 | +--
|
|
| 686 | +-- Don't bother to trim, making a @case <hole> of {}@, if we have only
|
|
| 687 | +-- an essentially-trivial continuation; e.g. @(<hole> \@ty |> co)@.
|
|
| 688 | +mkBottomCont cont = go cont
|
|
| 689 | + where
|
|
| 690 | + go k@(Stop {}) = k
|
|
| 691 | + go (TickIt t k') = TickIt t (go k')
|
|
| 692 | + go k@(CastIt { sc_cont = k' }) = k { sc_cont = go k' }
|
|
| 693 | + go k@(ApplyToTy { sc_cont = k' }) = k { sc_cont = go k' }
|
|
| 694 | + go k@(Select { sc_alts = [], sc_cont = Stop {} }) = k -- Optimisation only
|
|
| 695 | + go k | Stop res_ty _ _ <- stop_cont
|
|
| 696 | + , hole_ty `eqTypeIgnoringMultiplicity` res_ty
|
|
| 697 | + = stop_cont
|
|
| 698 | + | otherwise
|
|
| 699 | + = Select { sc_alts = []
|
|
| 700 | + , sc_bndr = mkWildValBinder OneTy hole_ty
|
|
| 701 | + , sc_env = Simplified OkDup
|
|
| 702 | + , sc_cont = stop_cont }
|
|
| 703 | + where
|
|
| 704 | + hole_ty = contHoleType k
|
|
| 705 | + stop_cont = contStop k
|
|
| 706 | + |
|
| 654 | 707 | -------------------
|
| 655 | 708 | mkArgInfo :: SimplEnv -> Id -> [CoreRule] -> SimplCont -> ArgInfo
|
| 656 | 709 | mkArgInfo env fun rules_for_fun cont
|
| ... | ... | @@ -672,16 +725,17 @@ mkArgInfo env fun rules_for_fun cont |
| 672 | 725 | |
| 673 | 726 | fun_has_rules = not (null rules_for_fun)
|
| 674 | 727 | |
| 675 | - vanilla_discounts, arg_discounts :: [Int]
|
|
| 676 | - vanilla_discounts = repeat 0
|
|
| 728 | + vanilla_discounts, arg_discounts :: Infinite Int
|
|
| 729 | + vanilla_discounts = Inf.repeat 0
|
|
| 677 | 730 | arg_discounts = case idUnfolding fun of
|
| 678 | 731 | CoreUnfolding {uf_guidance = UnfIfGoodArgs {ug_args = discounts}}
|
| 679 | - -> discounts ++ vanilla_discounts
|
|
| 732 | + -> discounts Inf.++ vanilla_discounts
|
|
| 680 | 733 | _ -> vanilla_discounts
|
| 681 | 734 | |
| 682 | - vanilla_dmds, arg_dmds :: [Demand]
|
|
| 735 | + vanilla_dmds :: RemainingArgDmds
|
|
| 683 | 736 | vanilla_dmds = repeat topDmd
|
| 684 | 737 | |
| 738 | + arg_dmds :: RemainingArgDmds
|
|
| 685 | 739 | arg_dmds
|
| 686 | 740 | | not (seInline env)
|
| 687 | 741 | = vanilla_dmds -- See Note [Do not expose strictness if sm_inline=False]
|
| ... | ... | @@ -689,26 +743,22 @@ mkArgInfo env fun rules_for_fun cont |
| 689 | 743 | = -- add_type_str fun_ty $
|
| 690 | 744 | case splitDmdSig (idDmdSig fun) of
|
| 691 | 745 | (demands, result_info)
|
| 692 | - | not (demands `lengthExceeds` n_val_args)
|
|
| 693 | - -> -- Enough args, use the strictness given.
|
|
| 694 | - -- For bottoming functions we used to pretend that the arg
|
|
| 695 | - -- is lazy, so that we don't treat the arg as an
|
|
| 696 | - -- interesting context. This avoids substituting
|
|
| 697 | - -- top-level bindings for (say) strings into
|
|
| 698 | - -- calls to error. But now we are more careful about
|
|
| 699 | - -- inlining lone variables, so its ok
|
|
| 700 | - -- (see GHC.Core.Op.Simplify.Utils.analyseCont)
|
|
| 701 | - if isDeadEndDiv result_info then
|
|
| 702 | - demands -- Finite => result is bottom
|
|
| 703 | - else
|
|
| 704 | - demands ++ vanilla_dmds
|
|
| 746 | + | not (demands `lengthExceeds` n_val_args)
|
|
| 747 | + -> remaining_dmds -- Enough args, use the strictness given.
|
|
| 705 | 748 | | otherwise
|
| 706 | 749 | -> warnPprTrace True "More demands than arity" (ppr fun <+> ppr (idArity fun)
|
| 707 | 750 | <+> ppr n_val_args <+> ppr demands) $
|
| 708 | 751 | vanilla_dmds -- Not enough args, or no strictness
|
| 709 | 752 | |
| 710 | - add_type_strictness :: Type -> [Demand] -> [Demand]
|
|
| 711 | - -- If the function arg types are strict, record that in the 'strictness bits'
|
|
| 753 | + where
|
|
| 754 | + remaining_dmds :: RemainingArgDmds
|
|
| 755 | + -- isDeadEndDiv: if remaining_dmds is finite, result is bottom
|
|
| 756 | + -- See (TC1) in Note [Trimming the continuation for bottoming functions]
|
|
| 757 | + remaining_dmds | isDeadEndDiv result_info = demands
|
|
| 758 | + | otherwise = demands ++ vanilla_dmds
|
|
| 759 | + |
|
| 760 | + add_type_strictness :: Type -> RemainingArgDmds -> RemainingArgDmds
|
|
| 761 | + -- If the function arg /types/ are strict, record that in the RemainingArgDmds
|
|
| 712 | 762 | -- No need to instantiate because unboxed types (which dominate the strict
|
| 713 | 763 | -- types) can't instantiate type variables.
|
| 714 | 764 | -- add_type_strictness is done repeatedly (for each call);
|
| ... | ... | @@ -915,16 +965,16 @@ the incentive to disappear when we inline `f`! |
| 915 | 965 | lazyArgContext :: ArgInfo -> CallCtxt
|
| 916 | 966 | -- Use this for lazy arguments
|
| 917 | 967 | lazyArgContext (ArgInfo { ai_encl = encl_rules, ai_discs = discs })
|
| 918 | - | encl_rules = RuleArgCtxt
|
|
| 919 | - | disc:_ <- discs, disc > 0 = DiscArgCtxt -- Be keener here
|
|
| 920 | - | otherwise = BoringCtxt -- Nothing interesting
|
|
| 968 | + | encl_rules = RuleArgCtxt
|
|
| 969 | + | Inf disc _ <- discs, disc > 0 = DiscArgCtxt -- Be keener here
|
|
| 970 | + | otherwise = BoringCtxt -- Nothing interesting
|
|
| 921 | 971 | |
| 922 | 972 | strictArgContext :: ArgInfo -> CallCtxt
|
| 923 | 973 | strictArgContext (ArgInfo { ai_encl = encl_rules, ai_discs = discs })
|
| 924 | 974 | -- Use this for strict arguments
|
| 925 | - | encl_rules = RuleArgCtxt
|
|
| 926 | - | disc:_ <- discs, disc > 0 = DiscArgCtxt -- Be keener here
|
|
| 927 | - | otherwise = RhsCtxt NonRecursive
|
|
| 975 | + | encl_rules = RuleArgCtxt
|
|
| 976 | + | Inf disc _ <- discs, disc > 0 = DiscArgCtxt -- Be keener here
|
|
| 977 | + | otherwise = RhsCtxt NonRecursive
|
|
| 928 | 978 | -- Why RhsCtxt? if we see f (g x), and f is strict, we
|
| 929 | 979 | -- want to be a bit more eager to inline g, because it may
|
| 930 | 980 | -- expose an eval (on x perhaps) that can be eliminated or
|
| 1 | +{-# OPTIONS_GHC -fno-full-laziness #-}
|
|
| 2 | + |
|
| 3 | +module T27261 (foo) where
|
|
| 4 | + |
|
| 5 | +import T27261_aux (myError)
|
|
| 6 | + |
|
| 7 | +foo :: [String] -> (() -> Int) -> Int
|
|
| 8 | +foo cs =
|
|
| 9 | + \ k -> ( case bar of
|
|
| 10 | + Just str -> let cs2 = case cs of { [] -> cs; _ -> "stack entry" : cs }
|
|
| 11 | + in myError cs2 str
|
|
| 12 | + Nothing -> \ c -> c () )
|
|
| 13 | + ( \ _ -> k () )
|
|
| 14 | + |
|
| 15 | +bar :: Maybe String
|
|
| 16 | +bar = Nothing
|
|
| 17 | +{-# NOINLINE bar #-} |
| 1 | +{-# LANGUAGE BangPatterns #-}
|
|
| 2 | + |
|
| 3 | +module T27261_aux (myError) where
|
|
| 4 | + |
|
| 5 | +myError :: [String] -> String -> a
|
|
| 6 | +myError !_ _ = undefined
|
|
| 7 | +{-# NOINLINE myError #-} |
| ... | ... | @@ -601,3 +601,4 @@ test('T25718a', normal, compile, ['-O -ddump-simpl -dsuppress-uniques -dsuppress |
| 601 | 601 | test('T25718b', normal, compile, ['-O -ddump-simpl -dsuppress-uniques -dsuppress-all -dno-typeable-binds'])
|
| 602 | 602 | test('T25718c', normal, compile, ['-O -ddump-simpl -dsuppress-uniques -dsuppress-all -dno-typeable-binds'])
|
| 603 | 603 | test('T19166', normal, compile, ['-O -ddump-simpl -dsuppress-uniques -dsuppress-all -dno-typeable-binds'])
|
| 604 | +test('T27261', [extra_files(['T27261_aux.hs'])], multimod_compile, ['T27261', '-v0 -O']) |