[Git][ghc/ghc][wip/amg/T22156] 2 commits: Representation-polymorphic HasField (fixes #22156)

Adam Gundry (@adamgundry) gitlab at gitlab.haskell.org
Thu Dec 28 15:14:51 UTC 2023



Adam Gundry pushed to branch wip/amg/T22156 at Glasgow Haskell Compiler / GHC


Commits:
c50987d6 by Adam Gundry at 2023-12-28T15:14:04+00:00
Representation-polymorphic HasField (fixes #22156)

This generalises the HasField class to support representation polymorphism,
so that instead of

    type HasField :: forall {k} . k -> Type -> Type -> Constraint

we have

    type HasField :: forall {k} {r_rep} {a_rep} . k -> TYPE r_rep -> TYPE a_rep -> Constraint

- - - - -
13c4df69 by Adam Gundry at 2023-12-28T15:14:04+00:00
Mark GHC.Records as Trustworthy

The previous patch added an import of GHC.Exts, which means GHC.Records
ceases to be Safe-Inferred. Rather than breaking any user code which
relied on GHC.Records being considered Safe, we declare it Trustworthy.

- - - - -


9 changed files:

- compiler/GHC/Tc/Instance/Class.hs
- compiler/GHC/Tc/Validity.hs
- docs/users_guide/9.10.1-notes.rst
- libraries/base/changelog.md
- libraries/base/src/GHC/Records.hs
- testsuite/tests/interface-stability/base-exports.stdout
- testsuite/tests/overloadedrecflds/should_run/all.T
- + testsuite/tests/overloadedrecflds/should_run/hasfieldrun03.hs
- + testsuite/tests/overloadedrecflds/should_run/hasfieldrun03.stdout


Changes:

=====================================
compiler/GHC/Tc/Instance/Class.hs
=====================================
@@ -1192,7 +1192,8 @@ appropriately cast.
 
 The HasField class is defined (in GHC.Records) thus:
 
-    class HasField (x :: k) r a | x r -> a where
+    type HasField :: forall {k} {r_rep} {a_rep} . k -> TYPE r_rep -> TYPE a_rep -> Constraint
+    class HasField x r a | x r -> a where
       getField :: r -> a
 
 Since this is a one-method class, it is represented as a newtype.
@@ -1248,8 +1249,8 @@ matchHasField dflags short_cut clas tys
   = do { fam_inst_envs <- tcGetFamInstEnvs
        ; rdr_env       <- getGlobalRdrEnv
        ; case tys of
-           -- We are matching HasField {k} x r a...
-           [_k_ty, x_ty, r_ty, a_ty]
+           -- We are matching HasField {k} {r_rep} {a_rep} x r a...
+           [_k_ty, _r_rep, _a_rep, x_ty, r_ty, a_ty]
                -- x should be a literal string
              | Just x <- isStrLitTy x_ty
                -- r should be an applied type constructor


=====================================
compiler/GHC/Tc/Validity.hs
=====================================
@@ -1755,7 +1755,7 @@ dropCastsB b = b   -- Don't bother in the kind of a forall
 
 -- | See Note [Validity checking of HasField instances]
 checkHasFieldInst :: Class -> [Type] -> TcM ()
-checkHasFieldInst cls tys@[_k_ty, lbl_ty, r_ty, _a_ty] =
+checkHasFieldInst cls tys@[_k_ty, _r_rep, _a_rep, lbl_ty, r_ty, _a_ty] =
   case splitTyConApp_maybe r_ty of
     Nothing -> add_err IllegalHasFieldInstanceNotATyCon
     Just (tc, _)


=====================================
docs/users_guide/9.10.1-notes.rst
=====================================
@@ -45,6 +45,12 @@ Language
       where
         y = f x
 
+- The built-in ``HasField`` class, used by :extension:`OverloadedRecordDot`, now
+  supports representation polymorphism (implementing part of `GHC Proposal #583
+  <https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0583-hasfield-redesign.rst>`_).
+  This means that code using :extension:`UnliftedDatatypes` or
+  :extension:`UnliftedNewtypes` can now use :extension:`OverloadedRecordDot`.
+
 - Due to an oversight, previous GHC releases (starting from 9.4) allowed the use
   of promoted data types in kinds, even when :extension:`DataKinds` was not
   enabled. That is, GHC would erroneously accept the following code: ::


=====================================
libraries/base/changelog.md
=====================================
@@ -7,6 +7,7 @@
   * Implement `stimes` for `instance Semigroup (Endo a)` explicitly ([CLC proposal #4](https://github.com/haskell/core-libraries-committee/issues/4))
   * Add laws relating between `Foldable` / `Traversable` with `Bifoldable` / `Bitraversable` ([CLC proposal #205](https://github.com/haskell/core-libraries-committee/issues/205))
   * The `Enum Int64` and `Enum Word64` instances now use native operations on 32-bit platforms, increasing performance by up to 1.5x on i386 and up to 5.6x with the JavaScript backend. ([CLC proposal #187](https://github.com/haskell/core-libraries-committee/issues/187))
+  * The `HasField` class now supports representation polymorphism ([CLC proposal #194](https://github.com/haskell/core-libraries-committee/issues/194))
   * Update to [Unicode 15.1.0](https://www.unicode.org/versions/Unicode15.1.0/).
   * Fix `fdIsNonBlocking` to always be `0` for regular files and block devices on unix, regardless of `O_NONBLOCK`
   * Always use `safe` call to `read` for regular files and block devices on unix if the RTS is multi-threaded, regardless of `O_NONBLOCK`.


=====================================
libraries/base/src/GHC/Records.hs
=====================================
@@ -1,11 +1,14 @@
 {-# LANGUAGE AllowAmbiguousTypes #-}
+{-# LANGUAGE ExplicitForAll #-}
 {-# LANGUAGE FunctionalDependencies #-}
 {-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE StandaloneKindSignatures #-}
+{-# LANGUAGE Trustworthy #-}
 
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  GHC.Records
--- Copyright   :  (c) Adam Gundry 2015-2016
+-- Copyright   :  (c) Adam Gundry 2015-2023
 -- License     :  see libraries/base/LICENSE
 --
 -- Maintainer  :  cvs-ghc at haskell.org
@@ -13,9 +16,9 @@
 -- Portability :  non-portable (GHC extensions)
 --
 -- This module defines the 'HasField' class used by the
--- @OverloadedRecordFields@ extension.  See the
--- <https://gitlab.haskell.org/ghc/ghc/wikis/records/overloaded-record-fields
--- wiki page> for more details.
+-- @OverloadedRecordDot@ extension.  See the
+-- <https://downloads.haskell.org/ghc/latest/docs/users_guide/exts/hasfield.html
+-- user's guide> for more details.
 --
 -----------------------------------------------------------------------------
 
@@ -23,16 +26,20 @@ module GHC.Records
        ( HasField(..)
        ) where
 
+import Data.Kind (Constraint)
+import GHC.Exts (TYPE)
+
 -- | Constraint representing the fact that the field @x@ belongs to
 -- the record type @r@ and has field type @a at .  This will be solved
 -- automatically, but manual instances may be provided as well.
 
---   HasField :: forall {k}. k -> * -> * -> Constraint
---   getField :: forall {k} (x::k) r a. HasField x r a => r -> a
+--   HasField :: forall {k} {r_rep} {a_rep} . k -> TYPE r_rep -> TYPE a_rep -> Constraint
+--   getField :: forall {k} {r_rep} {a_rep} (x::k) (r :: TYPE r_rep) (a :: TYPE a_rep) . HasField x r a => r -> a
 -- NB: The {k} means that k is an 'inferred' type variable, and
 --     hence not provided in visible type applications.  Thus you
 --     say     getField @"foo"
 --     not     getField @Symbol @"foo"
+type HasField :: forall {k} {r_rep} {a_rep} . k -> TYPE r_rep -> TYPE a_rep -> Constraint
 class HasField x r a | x r -> a where
   -- | Selector function to extract the field from the record.
   getField :: r -> a


=====================================
testsuite/tests/interface-stability/base-exports.stdout
=====================================
@@ -9101,8 +9101,8 @@ module GHC.Real where
   underflowError :: forall a. a
 
 module GHC.Records where
-  -- Safety: Safe-Inferred
-  type HasField :: forall {k}. k -> * -> * -> Constraint
+  -- Safety: Trustworthy
+  type HasField :: forall {k} {r_rep :: GHC.Types.RuntimeRep} {a_rep :: GHC.Types.RuntimeRep}. k -> TYPE r_rep -> TYPE a_rep -> Constraint
   class HasField x r a | x r -> a where
     getField :: r -> a
     {-# MINIMAL getField #-}


=====================================
testsuite/tests/overloadedrecflds/should_run/all.T
=====================================
@@ -15,6 +15,7 @@ test('overloadedlabelsrun04', [req_th, extra_files(['OverloadedLabelsRun04_A.hs'
      ['overloadedlabelsrun04', config.ghc_th_way_flags])
 test('hasfieldrun01', normal, compile_and_run, [''])
 test('hasfieldrun02', normal, compile_and_run, [''])
+test('hasfieldrun03', normal, compile_and_run, [''])
 test('T12243', normal, compile_and_run, [''])
 test('T11228', normal, compile_and_run, [''])
 test('T11671_run', normal, compile_and_run, [''])


=====================================
testsuite/tests/overloadedrecflds/should_run/hasfieldrun03.hs
=====================================
@@ -0,0 +1,26 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE UnliftedNewtypes #-}
+{-# LANGUAGE UnliftedDatatypes #-}
+
+import GHC.Exts (Int#, Int(I#), RuntimeRep(..), UnliftedType, TYPE)
+import GHC.Records (HasField(..))
+
+data U = MkU { f1 :: Int# }
+
+instance a ~ Int# => HasField "f2" U a where
+  getField = f1
+
+-- AMG TODO: example in proposal has V with wrong kind?
+type V :: TYPE IntRep -> UnliftedType
+data V x = MkV { g1 :: x }
+
+instance a ~ x => HasField "g2" (V x) a where
+  getField = g1
+
+main = do print (I# (getField @"f1" (MkU 42#)))
+          print (I# (getField @"f2" (MkU 42#)))
+          print (I# (getField @"g1" (MkV 100#)))
+          print (I# (getField @"g2" (MkV 100#)))


=====================================
testsuite/tests/overloadedrecflds/should_run/hasfieldrun03.stdout
=====================================
@@ -0,0 +1,4 @@
+42
+42
+100
+100



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/6763dbd21a3c12185446471aa982acc60024b925...13c4df6943745cf8e7fcb0162c165bb85e3069f6

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/6763dbd21a3c12185446471aa982acc60024b925...13c4df6943745cf8e7fcb0162c165bb85e3069f6
You're receiving this email because of your account on gitlab.haskell.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20231228/2fbe572d/attachment-0001.html>


More information about the ghc-commits mailing list