Skip to content

map/coerce does not fire with all newtypes

Consider a slightly modified version of T2110, compiled with -O:

{-# LANGUAGE GADTs #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE RankNTypes #-}

import GHC.Exts
import Unsafe.Coerce

newtype Age a b where
  Age :: forall a b. Int -> Age a b

foo :: [Int] -> [Int]
foo = map id
fooAge :: [Int] -> [Age a b]
fooAge = map Age
fooCoerce :: [Int] -> [Age a b]
fooCoerce = map coerce
fooUnsafeCoerce :: [Int] -> [Age a b]
fooUnsafeCoerce = map unsafeCoerce

same :: a -> b -> IO ()
same x y = case reallyUnsafePtrEquality# (unsafeCoerce x) y of
    1# -> putStrLn "yes"
    _  -> putStrLn "no"

main = do
    let l = [1,2,3]
    same (foo l) l
    same (fooAge l) l
    same (fooCoerce l) l
    same (fooUnsafeCoerce l) l

This code correctly prints "yes" four times, as required by #2110 (closed). However, changing the order of type arguments in the definition of Age to:

  Age :: forall b a. Int -> Age a b

causes the test to fail in one case: map Age is no longer simplified to Age. The reason is that this change causes the newtype Age to have a wrapper, and the map/coerce rule is not detecting it (see Note [Getting the map/coerce RULE to work] and Note [Data con wrappers and GADT syntax])

This ticket is a prerequisite to linear types (since in linear types, all newtypes have wrappers).

Trac metadata
Trac field Value
Version 8.6.3
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information