Admin message

Due to a large amount of spam we do not allow new users to create repositories, they are "external" users. If you are a new user and want to create a repository, for example for forking GHC, open a new issue on ghc/ghc using the "get-verified" issue template

Nullary Data Con Wrappers are not tagged
This ticket is concerned with the tagging logic of nullary data con *wrappers*. Concretely, it seems we are not tagging nullary data con wrappers at their usage site. The immediate consequences of not tagging these wrappers must be considered in at least two distinct scenarios: The data type is lifted: * If we pass the datacon wrapper as an argument to a function untagged (tag=0), despite knowing exactly what the constructor is, in the function body we will treat the argument as a thunk (which means calling at least an extra function -- the data con _con_entry() -- which will in turn return a tagged pointer) The data type is unlifted: * When we pass the unlifted datacon wrapper untagged (tag=0) to a function (that must be expecting an unlifted argument), we will get a segmentation fault as in #23146. The reason is functions expect their unlifted arguments to be evaluated and tagged, and therefore do not handle the case in which the unlifted argument has tag=0. This ticket is closely related to #23146 and I intend to fix both simultaneously. This one discusses the tagging issue in its full generality as opposed to the segfault particular to the unlifted case. ---- # Examples I've got a good example of this for each case. There are two subtleties about them. Nonetheless, they showcase the bug well and we must handle this correctly regardless: (1) Why do we even have a wrapper for a nullary data con? Answer: because of the unlifted equality coercion the worker takes as an argument (despite this argument not being runtime relevant) (2) The wrapper *doesn't* inline. (Why not?). ### Unlifted case This example will segfault when run, and it's the reproducer from #23146. ```haskell -- A.hs {-# LANGUAGE GADTs, UnliftedDatatypes #-} -- Unlifted, Nil worker has 1 Zero-Width argument import GHC.Exts import Data.Kind import R2 fieldsSam :: NP xs -> NP xs -> Bool fieldsSam (x' ::* xs) (y' ::* ys) = fieldsSam xs ys fieldsSam UNil UNil = True main :: IO () main = print (fieldsSam UNil UNil) -- B.hs {-# LANGUAGE UnliftedDatatypes #-} module R2 where import GHC.Exts type NP :: [UnliftedType] -> UnliftedType data NP xs where UNil :: NP '[] (::*) :: x -> NP xs -> NP (x ': xs) ``` ### Lifted case This example will not segfault, but inspecting the cmm will show the wrappers being passed untagged and the logic to handle untagged arguments (tag == 0) ```haskell -- A.hs {-# LANGUAGE GADTs, UnliftedDatatypes #-} -- Lifted, 1 Zero-Width argument import GHC.Exts import Data.Kind import S2 fieldsSam :: NP xs -> NP xs -> Bool fieldsSam (x' ::* xs) (y' ::* ys) = fieldsSam xs ys fieldsSam UNil UNil = True main :: IO () main = print (fieldsSam UNil UNil) -- B.hs {-# LANGUAGE UnliftedDatatypes #-} module S2 where import Data.Kind import GHC.Exts type NP :: [Type] -> Type data NP xs where UNil :: NP '[] (::*) :: x -> NP xs -> NP (x ': xs) ``` CC @simonpj @bgamari @AndreasK
issue