Commit 9e6c6b42 authored by eir@cis.upenn.edu's avatar eir@cis.upenn.edu
Browse files

Make FunPtr's role be phantom; add comments.

This change also updates castFunPtr to make it free at runtime.
This fixes #9163.
parent 0e6bc84c
......@@ -94,6 +94,20 @@ parameters.
Similarly, we don't need to look in AppTy's, because nothing headed by
an AppTy will be marshalable.
Note [FFI type roles]
~~~~~~~~~~~~~~~~~~~~~
The 'go' helper function within normaliseFfiType' always produces
representational coercions. But, in the "children_only" case, we need to
use these coercions in a TyConAppCo. Accordingly, the roles on the coercions
must be twiddled to match the expectation of the enclosing TyCon. However,
we cannot easily go from an R coercion to an N one, so we forbid N roles
on FFI type constructors. Currently, only two such type constructors exist:
IO and FunPtr. Thus, this is not an onerous burden.
If we ever want to lift this restriction, we would need to make 'go' take
the target role as a parameter. This wouldn't be hard, but it's a complication
not yet necessary and so is not yet implemented.
\begin{code}
-- normaliseFfiType takes the type from an FFI declaration, and
-- evaluates any type synonyms, type functions, and newtypes. However,
......@@ -116,7 +130,8 @@ normaliseFfiType' env ty0 = go initRecTc ty0
-- We don't want to look through the IO newtype, even if it is
-- in scope, so we have a special case for it:
| tc_key `elem` [ioTyConKey, funPtrTyConKey]
-- Those *must* have R roles on their parameters!
-- These *must not* have nominal roles on their parameters!
-- See Note [FFI type roles]
= children_only
| isNewTyCon tc -- Expand newtypes
......@@ -143,10 +158,14 @@ normaliseFfiType' env ty0 = go initRecTc ty0
= nothing -- see Note [Don't recur in normaliseFfiType']
where
tc_key = getUnique tc
children_only
children_only
= do xs <- mapM (go rec_nts) tys
let (cos, tys', gres) = unzip3 xs
return ( mkTyConAppCo Representational tc cos
-- the (repeat Representational) is because 'go' always
-- returns R coercions
cos' = zipWith3 downgradeRole (tyConRoles tc)
(repeat Representational) cos
return ( mkTyConAppCo Representational tc cos'
, mkTyConApp tc tys', unionManyBags gres)
nt_co = mkUnbranchedAxInstCo Representational (newTyConCo tc) tys
nt_rhs = newTyConInstRhs tc tys
......
......@@ -31,13 +31,18 @@ import GHC.Show
import GHC.Num
import GHC.List ( length, replicate )
import Numeric ( showHex )
import Data.Coerce
#include "MachDeps.h"
------------------------------------------------------------------------
-- Data pointers.
-- The role of Ptr's parameter is phantom, as there is no relation between
-- the Haskell representation and whathever the user puts at the end of the
-- pointer. And phantom is useful to implement castPtr (see #9163)
-- redundant role annotation checks that this doesn't change
type role Ptr phantom
data Ptr a = Ptr Addr# deriving (Eq, Ord)
-- ^ A value of type @'Ptr' a@ represents a pointer to an object, or an
-- array of objects, which may be marshalled to or from Haskell values
......@@ -49,10 +54,6 @@ data Ptr a = Ptr Addr# deriving (Eq, Ord)
-- to access the pointer. For example you might write small foreign
-- functions to get or set the fields of a C @struct@.
-- The role of Ptr's parameter is phantom, as there is relation between
-- the Haskell representation and whathever the user puts at the end of the
-- pointer. And phantom is useful to implement castPtr (see #9163)
-- |The constant 'nullPtr' contains a distinguished value of 'Ptr'
-- that is not associated with a valid memory location.
nullPtr :: Ptr a
......@@ -86,7 +87,10 @@ minusPtr (Ptr a1) (Ptr a2) = I# (minusAddr# a1 a2)
------------------------------------------------------------------------
-- Function pointers for the default calling convention.
type role FunPtr representational
-- 'FunPtr' has a phantom role for similar reasons to 'Ptr'. Note
-- that 'FunPtr's role cannot become nominal without changes elsewhere
-- in GHC. See Note [FFI type roles] in TcForeign.
type role FunPtr phantom
data FunPtr a = FunPtr Addr# deriving (Eq, Ord)
-- ^ A value of type @'FunPtr' a@ is a pointer to a function callable
-- from foreign code. The type @a@ will normally be a /foreign type/,
......@@ -128,8 +132,6 @@ data FunPtr a = FunPtr Addr# deriving (Eq, Ord)
-- > foreign import ccall "dynamic"
-- > mkFun :: FunPtr IntFunction -> IntFunction
-- The role of FunPtr is representational, to be on the safe side (see #9163)
-- |The constant 'nullFunPtr' contains a
-- distinguished value of 'FunPtr' that is not
-- associated with a valid memory location.
......@@ -138,7 +140,7 @@ nullFunPtr = FunPtr nullAddr#
-- |Casts a 'FunPtr' to a 'FunPtr' of a different type.
castFunPtr :: FunPtr a -> FunPtr b
castFunPtr (FunPtr addr) = FunPtr addr
castFunPtr = coerce
-- |Casts a 'FunPtr' to a 'Ptr'.
--
......
{-# LANGUAGE MagicHash, NoImplicitPrelude, TypeFamilies, UnboxedTuples #-}
{-# LANGUAGE MagicHash, NoImplicitPrelude, TypeFamilies, UnboxedTuples,
RoleAnnotations #-}
-----------------------------------------------------------------------------
-- |
-- Module : GHC.Types
......@@ -80,7 +81,13 @@ at some point, directly or indirectly, from @Main.main@.
or the '>>' and '>>=' operations from the 'Monad' class.
-}
newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))
type role IO representational
{-
The above role annotation is redundant but is included because this role
is significant in the normalisation of FFI types. Specifically, if this
role were to become nominal (which would be very strange, indeed!), changes
elsewhere in GHC would be necessary. See [FFI type roles] in TcForeign.
-}
{-
Note [Kind-changing of (~) and Coercible]
......
TYPE SIGNATURES
TYPE CONSTRUCTORS
data T1 a = K1 (IO a)
type role T2 phantom
data T2 a = K2 (FunPtr a)
COERCION AXIOMS
Dependent modules: []
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment