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

Newtype over fully applied Levity Polymorphic Type family gives Levity Polymorphism error
## Summary If an UnliftedNewtype wraps a (kind-polymorphic) fully reducable type family it still gives a levity-polymorphism error when used. However the concrete type is known at the callsite and not actually polymorphic. ## Steps to reproduce Here is some example code: ``` {-# LANGUAGE DataKinds #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE StandaloneKindSignatures #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UnboxedTuples #-} {-# LANGUAGE UnliftedNewtypes #-} module Scratch where import GHC.Exts -- I'm not sure how to give this type with explicit arguments type ListTyp :: forall (n::ANat) (k::RuntimeRep) (a :: TYPE k). TYPE (ListRep n k) type family ListTyp where ListTyp @ANil = (# #) ListTyp @(ASuc n) @k @a = (# a, ListTyp @n @k @a #) type family ListRep (n :: ANat) (a::RuntimeRep) where ListRep ANil _ = (TupleRep '[]) ListRep (ASuc s) a = (TupleRep '[a, ListRep s a]) data ANat = ANil | ASuc ANat newtype UnpackedVec (n :: ANat) (k :: RuntimeRep) (a :: TYPE k) = UV (ListTyp @n @k @a) ``` These work (unsurprisingly): ````` rawTup :: (# #) -> Int rawTup (# #) = 0 typeFamTup :: ListTyp @'ANil @LiftedRep @Int -> Int typeFamTup (# #) = 0 ````` This breaks: ````` newtypeFam :: UnpackedVec 'ANil LiftedRep Int -> Int newtypeFam (UV (# #)) = 0 -- [typecheck] [E] A levity-polymorphic type is not allowed here: -- Type: ListTyp -- Kind: TYPE (ListRep 'ANil 'LiftedRep) -- In a wildcard pattern ````` But an Identity newtype over the type family compiles: ````` newtype SIdentity (k :: TYPE a) = SIdentity k type UnpackedVecI (n :: ANat) (k :: RuntimeRep) (a :: TYPE k) = SIdentity (ListTyp @n @k @a) newtypeFamSyn :: UnpackedVecI 'ANil LiftedRep Int -> Int newtypeFamSyn (SIdentity (# #)) = 0 ````` ## Expected behavior Expected Behavior: If the code typechecks without newtype then my intuition was that adding a newtype with -XUnliftedNewtypes should keep working. ## Motivation I think the code is weird enough that it needs some motivation. I am currently trying to compare how various data representations - under IORef, strict, unpacked, unlifted, etc - affect performance for mutable data structures. I mostly use an identical implementation and switch behavior via type aliases to pick operations. Because the call sites are all concrete I wondered whether typefamily-build type representations were usable if type family reduces. That part works! But a newtype over the type family breaks. Fixing this very well might not be worth the implementation cost since it isn't possible to write polymorphic functions either way. Long term I could see some usefulness via something like Kotlin's (macro-like) approach to inline functions. If the unoptimized code is copy-pasted to every callsite then levity polymorphism should be fine because it won't be polymorphic at the callsite, right? ## Environment * GHC version used: 8.10.4 and 9.2.1-alpha2
issue