Skip to content

Demand: Nested strict product demands (#18885)

Sebastian Graf requested to merge wip/T18885 into master

Controversial follow-up of !4371 (closed).

Fixing #18903 (closed) gives us enough expressiveness to tackle #18885 (closed), where we have

f :: Int -> Int
f y =
  let x
       | expensive y == 1 = (expensive (y+1), expensive (y+2))
       | otherwise        = (expensive (y+3), expensive (y+4))
  in case () of
       _ | expensive (y+5) == 42 -> fst x
       _ | expensive (y+6) == 41 -> fst x + snd x
       _ | otherwise             -> 0

Here, we used to give x demand 1P(1P(U),1P(U)). The outer 1 is because x is used lazily and the inner 1s are redundant with that fact. That leaves some expressiveness on the table. After this change, we infer 1P(SP(U),1P(U)), meaning that whenever we evaluate x, we evaluate its first component strictly, effectively making strictness product demands apply relatively. Usage product demands still apply absolutely, though.

More details on how we could exploit the new language in Note [Absent sub-demands].

Fixes #18885 (closed).

There's a single remaining regression in T9630, which increases +16% in residency but decreases slightly in total allocations. I checked the heap profile, which doesn't suggest any obvious regressions. Ticky doesn't point to the reason either, because total allocations actually improved. I think it's OK to just accept it.

Metric Increase: T9630

Merge request reports