Note [Representation-polymorphic TyCons]
To check for representation-polymorphism directly in the typechecker, e.g. when using GHC.Tc.Utils.TcMType.checkTypeHasFixedRuntimeRep, we need to compute whether a type has a syntactically fixed RuntimeRep, as per Note [Fixed RuntimeRep] in GHC.Tc.Utils.Concrete. It's useful to have a quick way to check whether a saturated application of a type constructor has a fixed RuntimeRep. That is, we want to know, given a TyCon 'T' of arity 'n', does T a_1 ... a_n always have a fixed RuntimeRep? That is, is it always the case that this application has a kind of the form T a_1 ... a_n :: TYPE rep in which 'rep' is a concrete 'RuntimeRep'? ('Concrete' in the sense of Note [The Concrete mechanism] in GHC.Tc.Utils.Concrete: it contains no type-family applications or type variables.) To answer this question, we have 'tcHasFixedRuntimeRep'. If 'tcHasFixedRuntimeRep' returns 'True', it means we're sure that every saturated application of `T` has a fixed RuntimeRep. However, if it returns 'False', we don't know: perhaps some application might not have a fixed RuntimeRep. Examples: - For type families, we won't know in general whether an application will have a fixed RuntimeRep: type F :: k -> k type family F a where {..} `tcHasFixedRuntimeRep F = False' - For newtypes, we're usually OK: newtype N a b c = MkN Int No matter what arguments we apply `N` to, we always get something of kind `Type`, which has a fixed RuntimeRep. Thus `tcHasFixedRuntimeRep N = True`. However, with `-XUnliftedNewtypes`, we can have representation-polymorphic newtypes: type UN :: TYPE rep -> TYPE rep newtype UN a = MkUN a `tcHasFixedRuntimeRep UN = False` For example, `UN @Int8Rep Int8#` is represented by an 8-bit value, while `UN @LiftedRep Int` is represented by a heap pointer. To distinguish whether we are dealing with a representation-polymorphic newtype, we keep track of which situation we are in using the 'nt_fixed_rep' field of the 'NewTyCon' constructor of 'AlgTyConRhs', and read this field to compute 'tcHasFixedRuntimeRep'. - A similar story can be told for datatypes: we're usually OK, except with `-XUnliftedDatatypes` which allows for levity polymorphism, e.g.: type UC :: TYPE (BoxedRep l) -> TYPE (BoxedRep l) type UC a = MkUC a `tcHasFixedRuntimeRep UC = False` Here, we keep track of whether we are dealing with a levity-polymorphic unlifted datatype using the 'data_fixed_lev' field of the 'DataTyCon' constructor of 'AlgTyConRhs'. N.B.: technically, the representation of a datatype is fixed, as it is always a pointer. However, we currently require that we know the specific `RuntimeRep`: knowing that it's `BoxedRep l` for a type-variable `l` isn't enough. See #15532.
References 2
- Fixed RuntimeRep GHC.Tc.Utils.Concrete
- The Concrete mechanism GHC.Tc.Utils.Concrete
Referenced by 1
- GHC.Core.TyCon call site