Skip to content

GitLab

  • Projects
  • Groups
  • Snippets
  • Help
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
GHC
GHC
  • Project overview
    • Project overview
    • Details
    • Activity
    • Releases
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 4,323
    • Issues 4,323
    • List
    • Boards
    • Labels
    • Service Desk
    • Milestones
    • Iterations
  • Merge Requests 363
    • Merge Requests 363
  • Requirements
    • Requirements
    • List
  • CI / CD
    • CI / CD
    • Pipelines
    • Jobs
    • Schedules
  • Security & Compliance
    • Security & Compliance
    • Dependency List
    • License Compliance
  • Operations
    • Operations
    • Incidents
    • Environments
  • Analytics
    • Analytics
    • CI / CD
    • Code Review
    • Insights
    • Issue
    • Repository
    • Value Stream
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Members
    • Members
  • Collapse sidebar
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
  • Glasgow Haskell Compiler
  • GHCGHC
  • Issues
  • #17367

Closed
Open
Opened Oct 16, 2019 by Sebastian Graf@sgraf812Developer

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).

Assignee
Assign to
None
Milestone
None
Assign milestone
Time tracking
None
Due date
None
Reference: ghc/ghc#17367