Skip to content

Let-bound wildcards are not let-generalised

With -XBangPatterns, the act of declaring a let-binding without using it might have a side-effect. Consider this example:

{-# LANGUAGE BangPatterns #-}

f :: ()
f = let !x = undefined in ()

g :: ()
g = let !_ = undefined in ()

main = do
  print f
  print g

Both f and g declare a variable in a strict binding that is actually dead. Surprisingly, they lead to different code. Here's the Core (GHC 8.6.5) after optimisation:

main
  = >>
      (print
         @ ()
         GHC.Show.$fShow()
         (case \ (@ a_a2hW) ->
                 undefined
                   @ 'GHC.Types.LiftedRep
                   @ a_a2hW
                   (<snip>)
          of
          { __DEFAULT ->
          GHC.Tuple.()
          }))
      (print
         @ ()
         GHC.Show.$fShow()
         (case undefined
                 @ 'GHC.Types.LiftedRep
                 @ GHC.Types.Any
                 (<snip>)
          of
          { __DEFAULT ->
          GHC.Tuple.()
          }))

Note the /\a. undefined @LiftedRep @a in the first scrutinee. This is ultimately due to the fact that x is let-generalised, whereas _ is not. The first case is on a lambda, so I expect it to perform no forcing at all. The first case evaluates a complete application of undefined, so should crash. As a result, I'd expect this program to generate the following output:

()
test: Prelude.undefined
CallStack (from HasCallStack):
  error, called at libraries/base/GHC/Err.hs:78:14 in base:GHC.Err
  undefined, called at test.hs:4:15 in main:Main

Currently (tested on GHC 8.6.5), even the first print f will crash, so the behavior is actually consistent. I think this is actually a reasonable semantics, but I didn't expect it based on the difference in Core. My understanding of Core semantics might be off here.

So: Is let-generalisation of x but not of _ expected? If so, why does let !x = undefined in () crash?

CC @simonpj @rae since this is a continuation of the discussion in !1954 (comment 229057).

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information