[commit: ghc] master: Make FunPtr's role be phantom; add comments. (9e6c6b4)

git at git.haskell.org git at git.haskell.org
Wed Jun 11 13:32:10 UTC 2014


Repository : ssh://git@git.haskell.org/ghc

On branch  : master
Link       : http://ghc.haskell.org/trac/ghc/changeset/9e6c6b4206cd893434e49cd893eb67081eeffe99/ghc

>---------------------------------------------------------------

commit 9e6c6b4206cd893434e49cd893eb67081eeffe99
Author: Richard Eisenberg <eir at cis.upenn.edu>
Date:   Tue Jun 10 13:38:06 2014 -0400

    Make FunPtr's role be phantom; add comments.
    
    This change also updates castFunPtr to make it free at runtime.
    This fixes #9163.


>---------------------------------------------------------------

9e6c6b4206cd893434e49cd893eb67081eeffe99
 compiler/typecheck/TcForeign.lhs                   | 23 ++++++++++++++++++++--
 libraries/base/GHC/Ptr.lhs                         | 20 ++++++++++---------
 libraries/ghc-prim/GHC/Types.hs                    | 11 +++++++++--
 testsuite/tests/roles/should_compile/Roles2.stderr |  1 +
 4 files changed, 42 insertions(+), 13 deletions(-)

diff --git a/compiler/typecheck/TcForeign.lhs b/compiler/typecheck/TcForeign.lhs
index c2f812b..8370e0a 100644
--- a/compiler/typecheck/TcForeign.lhs
+++ b/compiler/typecheck/TcForeign.lhs
@@ -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
@@ -146,7 +161,11 @@ normaliseFfiType' env ty0 = go initRecTc ty0
           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
diff --git a/libraries/base/GHC/Ptr.lhs b/libraries/base/GHC/Ptr.lhs
index 341512b..a55f01e 100644
--- a/libraries/base/GHC/Ptr.lhs
+++ b/libraries/base/GHC/Ptr.lhs
@@ -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 at .
 
--- 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'.
 --
diff --git a/libraries/ghc-prim/GHC/Types.hs b/libraries/ghc-prim/GHC/Types.hs
index 44351d8..f6f4233 100644
--- a/libraries/ghc-prim/GHC/Types.hs
+++ b/libraries/ghc-prim/GHC/Types.hs
@@ -1,4 +1,5 @@
-{-# 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 at .
 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]
diff --git a/testsuite/tests/roles/should_compile/Roles2.stderr b/testsuite/tests/roles/should_compile/Roles2.stderr
index e6f9bcd..2c7ab6c 100644
--- a/testsuite/tests/roles/should_compile/Roles2.stderr
+++ b/testsuite/tests/roles/should_compile/Roles2.stderr
@@ -1,6 +1,7 @@
 TYPE SIGNATURES
 TYPE CONSTRUCTORS
   data T1 a = K1 (IO a)
+  type role T2 phantom
   data T2 a = K2 (FunPtr a)
 COERCION AXIOMS
 Dependent modules: []



More information about the ghc-commits mailing list