Skip to content

tagToEnum# leads to some silly closures

I don't know how important this is in practice, but it looks unfortunate.

Suppose I write

foo :: (Bool -> a) -> Int# -> a
foo f x = f (tagToEnum# x)

Since tagToEnum# can fail, GHC compiles this to

foo
  = \ (@ a_a10v)
      (f_s1by [Occ=Once!] :: GHC.Types.Bool -> a_a10v)
      (x_s1bz [Occ=Once] :: GHC.Prim.Int#) ->
      let {
        sat_s1bA [Occ=Once] :: GHC.Types.Bool
        [LclId]
        sat_s1bA = GHC.Prim.tagToEnum# @ GHC.Types.Bool x_s1bz } in
      f_s1by sat_s1bA

That seems pretty bad! We know that tagToEnum# is applied to Bool, so we can transform this to something like

foo f x = case leWord# (intToWord# x) 1## of
            1# -> f $! tagToEnum# x
            _ -> f (error "tagToEnum# was used at Bool with tag ...")

which avoids an extra closure at the cost of a single Word# comparison. The same goes for arbitrary known enumeration types. I suspect the right place to fix this up is in CorePrep.

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