Simon Peyton Jones pushed to branch wip/26737 at Glasgow Haskell Compiler / GHC
Commits:
-
8ee3246a
by Simon Peyton Jones at 2026-01-16T08:37:31+00:00
13 changed files:
- compiler/GHC/Builtin/Names.hs
- docs/users_guide/9.16.1-notes.rst
- libraries/ghc-internal/ghc-internal.cabal.in
- libraries/ghc-internal/src/GHC/Internal/Classes.hs
- + libraries/ghc-internal/src/GHC/Internal/Classes/IP.hs
- testsuite/tests/interface-stability/base-exports.stdout
- testsuite/tests/interface-stability/base-exports.stdout-mingw32
- testsuite/tests/interface-stability/base-exports.stdout-ws-32
- testsuite/tests/interface-stability/ghc-prim-exports.stdout
- testsuite/tests/interface-stability/ghc-prim-exports.stdout-mingw32
- testsuite/tests/th/TH_implicitParams.stdout
- + testsuite/tests/typecheck/should_compile/T26737.hs
- testsuite/tests/typecheck/should_compile/all.T
Changes:
| ... | ... | @@ -526,7 +526,7 @@ genericTyConNames = [ |
| 526 | 526 | |
| 527 | 527 | gHC_PRIM, gHC_PRIM_PANIC,
|
| 528 | 528 | gHC_TYPES, gHC_INTERNAL_DATA_DATA, gHC_MAGIC, gHC_MAGIC_DICT,
|
| 529 | - gHC_CLASSES, gHC_PRIMOPWRAPPERS :: Module
|
|
| 529 | + gHC_CLASSES, gHC_CLASSES_IP, gHC_PRIMOPWRAPPERS :: Module
|
|
| 530 | 530 | gHC_PRIM = mkGhcInternalModule (fsLit "GHC.Internal.Prim") -- Primitive types and values
|
| 531 | 531 | gHC_PRIM_PANIC = mkGhcInternalModule (fsLit "GHC.Internal.Prim.Panic")
|
| 532 | 532 | gHC_TYPES = mkGhcInternalModule (fsLit "GHC.Internal.Types")
|
| ... | ... | @@ -534,6 +534,7 @@ gHC_MAGIC = mkGhcInternalModule (fsLit "GHC.Internal.Magic") |
| 534 | 534 | gHC_MAGIC_DICT = mkGhcInternalModule (fsLit "GHC.Internal.Magic.Dict")
|
| 535 | 535 | gHC_CSTRING = mkGhcInternalModule (fsLit "GHC.Internal.CString")
|
| 536 | 536 | gHC_CLASSES = mkGhcInternalModule (fsLit "GHC.Internal.Classes")
|
| 537 | +gHC_CLASSES_IP = mkGhcInternalModule (fsLit "GHC.Internal.Classes.IP")
|
|
| 537 | 538 | gHC_PRIMOPWRAPPERS = mkGhcInternalModule (fsLit "GHC.Internal.PrimopWrappers")
|
| 538 | 539 | gHC_INTERNAL_TUPLE = mkGhcInternalModule (fsLit "GHC.Internal.Tuple")
|
| 539 | 540 | |
| ... | ... | @@ -1521,7 +1522,7 @@ fromLabelClassOpName |
| 1521 | 1522 | -- Implicit Parameters
|
| 1522 | 1523 | ipClassName :: Name
|
| 1523 | 1524 | ipClassName
|
| 1524 | - = clsQual gHC_CLASSES (fsLit "IP") ipClassKey
|
|
| 1525 | + = clsQual gHC_CLASSES_IP (fsLit "IP") ipClassKey
|
|
| 1525 | 1526 | |
| 1526 | 1527 | -- Overloaded record fields
|
| 1527 | 1528 | hasFieldClassName :: Name
|
| ... | ... | @@ -30,6 +30,18 @@ Language |
| 30 | 30 | - The extension :extension:`ExplicitNamespaces` now allows namespace-specified
|
| 31 | 31 | wildcards ``type ..`` and ``data ..`` in import and export lists.
|
| 32 | 32 | |
| 33 | +- Implicit parameters and ``ImpredicativeTypes``. GHC now knows
|
|
| 34 | + that if ``?foo::S`` is coecible to ``?foo::T`` only if ``S`` is coercible to ``T``.
|
|
| 35 | + Example (from :ghc-ticket:`#26737`)::
|
|
| 36 | + |
|
| 37 | + {-# LANGUAGE ImplicitParams, ImpredicativeTypes #-}
|
|
| 38 | + newtype N = MkN Int
|
|
| 39 | + test :: ((?foo::N) => Bool) -> ((?foo::Int) => Bool)
|
|
| 40 | + test = coerce
|
|
| 41 | + |
|
| 42 | + This is achieved by arranging that ``?foo :: T`` has a representational
|
|
| 43 | + role for ``T``.
|
|
| 44 | + |
|
| 33 | 45 | Compiler
|
| 34 | 46 | ~~~~~~~~
|
| 35 | 47 |
| ... | ... | @@ -343,6 +343,7 @@ Library |
| 343 | 343 | |
| 344 | 344 | GHC.Internal.CString
|
| 345 | 345 | GHC.Internal.Classes
|
| 346 | + GHC.Internal.Classes.IP
|
|
| 346 | 347 | GHC.Internal.Debug
|
| 347 | 348 | GHC.Internal.Magic
|
| 348 | 349 | GHC.Internal.Magic.Dict
|
| 1 | 1 | {-# LANGUAGE Trustworthy #-}
|
| 2 | 2 | {-# LANGUAGE NoImplicitPrelude, MagicHash, StandaloneDeriving, BangPatterns,
|
| 3 | 3 | KindSignatures, DataKinds, ConstraintKinds,
|
| 4 | - MultiParamTypeClasses, FunctionalDependencies #-}
|
|
| 5 | -{-# LANGUAGE UnboxedTuples #-}
|
|
| 6 | -{-# LANGUAGE AllowAmbiguousTypes #-}
|
|
| 7 | - -- ip :: IP x a => a is strictly speaking ambiguous, but IP is magic
|
|
| 4 | + MultiParamTypeClasses, FunctionalDependencies,
|
|
| 5 | + UnboxedTuples #-}
|
|
| 6 | + |
|
| 8 | 7 | {-# LANGUAGE UndecidableSuperClasses #-}
|
| 9 | 8 | -- Because of the type-variable superclasses for tuples
|
| 10 | 9 | |
| ... | ... | @@ -142,6 +141,7 @@ import GHC.Internal.Prim |
| 142 | 141 | import GHC.Internal.Tuple
|
| 143 | 142 | import GHC.Internal.CString (unpackCString#)
|
| 144 | 143 | import GHC.Internal.Types
|
| 144 | +import GHC.Internal.Classes.IP
|
|
| 145 | 145 | |
| 146 | 146 | infix 4 ==, /=, <, <=, >=, >
|
| 147 | 147 | infixr 3 &&
|
| ... | ... | @@ -149,12 +149,6 @@ infixr 2 || |
| 149 | 149 | |
| 150 | 150 | default () -- Double isn't available yet
|
| 151 | 151 | |
| 152 | --- | The syntax @?x :: a@ is desugared into @IP "x" a@
|
|
| 153 | --- IP is declared very early, so that libraries can take
|
|
| 154 | --- advantage of the implicit-call-stack feature
|
|
| 155 | -class IP (x :: Symbol) a | x -> a where
|
|
| 156 | - ip :: a
|
|
| 157 | - |
|
| 158 | 152 | {- $matching_overloaded_methods_in_rules
|
| 159 | 153 | |
| 160 | 154 | Matching on class methods (e.g. @(==)@) in rewrite rules tends to be a bit
|
| 1 | +{-# LANGUAGE Trustworthy #-}
|
|
| 2 | +{-# LANGUAGE NoImplicitPrelude, MagicHash, StandaloneDeriving, BangPatterns,
|
|
| 3 | + KindSignatures, DataKinds, ConstraintKinds,
|
|
| 4 | + MultiParamTypeClasses, FunctionalDependencies #-}
|
|
| 5 | + |
|
| 6 | +{-# LANGUAGE AllowAmbiguousTypes, RoleAnnotations, IncoherentInstances #-}
|
|
| 7 | + -- LANGUAGE pragmas: see Note [IP: implicit parameter class]
|
|
| 8 | + |
|
| 9 | +{-# OPTIONS_HADDOCK not-home #-}
|
|
| 10 | +-----------------------------------------------------------------------------
|
|
| 11 | +-- |
|
|
| 12 | +-- Module : GHC.Internal.Classes.IP
|
|
| 13 | +-- Copyright : (c) The University of Glasgow, 1992-2002
|
|
| 14 | +-- License : see libraries/base/LICENSE
|
|
| 15 | +--
|
|
| 16 | +-- Maintainer : ghc-devs@haskell.org
|
|
| 17 | +-- Stability : internal
|
|
| 18 | +-- Portability : non-portable (GHC extensions)
|
|
| 19 | +--
|
|
| 20 | +-- Basic classes.
|
|
| 21 | +-- Do not import this module directly. It is an GHC internal only
|
|
| 22 | +-- module. Some of its contents are instead available from @Prelude@
|
|
| 23 | +-- and @GHC.Int@.
|
|
| 24 | +--
|
|
| 25 | +-----------------------------------------------------------------------------
|
|
| 26 | + |
|
| 27 | +module GHC.Internal.Classes.IP( IP(..)) where
|
|
| 28 | + |
|
| 29 | +import GHC.Internal.Types
|
|
| 30 | + |
|
| 31 | + |
|
| 32 | +default () -- Double isn't available yet
|
|
| 33 | + |
|
| 34 | +-- | The syntax @?x :: a@ is desugared into @IP "x" a@
|
|
| 35 | +-- IP is declared very early, so that libraries can take
|
|
| 36 | +-- advantage of the implicit-call-stack feature
|
|
| 37 | +type role IP nominal representational -- See (IPRoles)
|
|
| 38 | +class IP (x :: Symbol) a | x -> a where
|
|
| 39 | + ip :: a
|
|
| 40 | + |
|
| 41 | +{- Note [IP: implicit parameter class]
|
|
| 42 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 43 | +An implicit parameter constraint (?foo::ty) is just short for
|
|
| 44 | + |
|
| 45 | + IP "foo" ty
|
|
| 46 | + |
|
| 47 | +where ghc-internal:GHC.Internal.Classes.IP is a special class that
|
|
| 48 | +GHC knows about, defined in this module.
|
|
| 49 | + |
|
| 50 | +* It is a unary type class, with one method `ip`, so it has no cost.
|
|
| 51 | + For example, (?foo::Int) is represented just by an Int.
|
|
| 52 | + |
|
| 53 | +* Criticially, it has a functional dependency:
|
|
| 54 | + class IP (x :: Symbol) a | x -> a where ...
|
|
| 55 | + So if we have
|
|
| 56 | + [G] IP "foo" Int
|
|
| 57 | + [W] IP "foo" alpha
|
|
| 58 | + the fundep wil lgive us alpha ~ Int, as desired.
|
|
| 59 | + |
|
| 60 | +* The solver has a number of special cases for implicit parameters,
|
|
| 61 | + mainly because a binding (let ?foo::Int = rhs in body)
|
|
| 62 | + is like a local instance declaration for IP. Search for uses
|
|
| 63 | + of `isIPClass`.
|
|
| 64 | + |
|
| 65 | +Wrinkles
|
|
| 66 | + |
|
| 67 | +(IPAmbiguity) The single method of IP has an ambiguous type
|
|
| 68 | + ip :: forall a. IP s a => a
|
|
| 69 | + Hence the LANGUAGE pragama AllowAmbiguousTypes.
|
|
| 70 | + The method `ip` is never called by the user, so ambiguity doesn't matter.
|
|
| 71 | + |
|
| 72 | +(IPRoles) IP has a role annotation. Why? See #26737. We want
|
|
| 73 | + [W] IP "foo" t1 ~R# IP "foo" t2
|
|
| 74 | + to decompose to give [W] IP t1 ~R# t2, using /representational/
|
|
| 75 | + equality for (t1 ~R# t2) not nominal.
|
|
| 76 | + |
|
| 77 | + This usually gives a complaint about incoherence, because in general
|
|
| 78 | + (t1 ~R# t2) does NOT imply (C t1) ~R# (C t2) for any normal class.
|
|
| 79 | + But it does for IP, because instance selection is controlled by the Symbol,
|
|
| 80 | + not the type of the payload. Hence LANGUAGE pragma IncoherentInstances.
|
|
| 81 | + (It is unfortunate that we need a module-wide IncoherentInstances here;
|
|
| 82 | + see #17167.)
|
|
| 83 | + |
|
| 84 | + Side note: arguably this treatment could be applied to any class
|
|
| 85 | + with a functional dependency; but for now we restrict it to IP.
|
|
| 86 | +-}
|
|
| 87 | + |
| ... | ... | @@ -3293,6 +3293,7 @@ module GHC.Base where |
| 3293 | 3293 | {-# MINIMAL fmap #-}
|
| 3294 | 3294 | type IO :: * -> *
|
| 3295 | 3295 | newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))
|
| 3296 | + type role IP nominal representational
|
|
| 3296 | 3297 | type IP :: Symbol -> * -> Constraint
|
| 3297 | 3298 | class IP x a | x -> a where
|
| 3298 | 3299 | ip :: a
|
| ... | ... | @@ -3293,6 +3293,7 @@ module GHC.Base where |
| 3293 | 3293 | {-# MINIMAL fmap #-}
|
| 3294 | 3294 | type IO :: * -> *
|
| 3295 | 3295 | newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))
|
| 3296 | + type role IP nominal representational
|
|
| 3296 | 3297 | type IP :: Symbol -> * -> Constraint
|
| 3297 | 3298 | class IP x a | x -> a where
|
| 3298 | 3299 | ip :: a
|
| ... | ... | @@ -3293,6 +3293,7 @@ module GHC.Base where |
| 3293 | 3293 | {-# MINIMAL fmap #-}
|
| 3294 | 3294 | type IO :: * -> *
|
| 3295 | 3295 | newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))
|
| 3296 | + type role IP nominal representational
|
|
| 3296 | 3297 | type IP :: Symbol -> * -> Constraint
|
| 3297 | 3298 | class IP x a | x -> a where
|
| 3298 | 3299 | ip :: a
|
| ... | ... | @@ -1171,6 +1171,7 @@ module GHC.Classes where |
| 1171 | 1171 | (==) :: a -> a -> GHC.Internal.Types.Bool
|
| 1172 | 1172 | (/=) :: a -> a -> GHC.Internal.Types.Bool
|
| 1173 | 1173 | {-# MINIMAL (==) | (/=) #-}
|
| 1174 | + type role IP nominal representational
|
|
| 1174 | 1175 | type IP :: GHC.Internal.Types.Symbol -> * -> Constraint
|
| 1175 | 1176 | class IP x a | x -> a where
|
| 1176 | 1177 | ip :: a
|
| ... | ... | @@ -1171,6 +1171,7 @@ module GHC.Classes where |
| 1171 | 1171 | (==) :: a -> a -> GHC.Internal.Types.Bool
|
| 1172 | 1172 | (/=) :: a -> a -> GHC.Internal.Types.Bool
|
| 1173 | 1173 | {-# MINIMAL (==) | (/=) #-}
|
| 1174 | + type role IP nominal representational
|
|
| 1174 | 1175 | type IP :: GHC.Internal.Types.Symbol -> * -> Constraint
|
| 1175 | 1176 | class IP x a | x -> a where
|
| 1176 | 1177 | ip :: a
|
| 1 | -Main.funcToReify :: GHC.Internal.Classes.IP "z"
|
|
| 2 | - GHC.Internal.Types.Int =>
|
|
| 1 | +Main.funcToReify :: GHC.Internal.Classes.IP.IP "z"
|
|
| 2 | + GHC.Internal.Types.Int =>
|
|
| 3 | 3 | GHC.Internal.Types.Int
|
| 4 | 4 | 5
|
| 5 | 5 | 1
|
| 1 | +{-# LANGUAGE ImpredicativeTypes, ImplicitParams #-}
|
|
| 2 | + |
|
| 3 | +module T26737 where
|
|
| 4 | + |
|
| 5 | +import Data.Coerce
|
|
| 6 | + |
|
| 7 | +newtype Foo = MkFoo Int
|
|
| 8 | + |
|
| 9 | +b :: ((?foo :: Foo) => Int) -> ((?foo :: Int) => Int)
|
|
| 10 | +b = coerce @(((?foo :: Foo) => Int)) @(((?foo :: Int) => Int)) |
| ... | ... | @@ -957,3 +957,4 @@ test('T17705', normal, compile, ['']) |
| 957 | 957 | test('T14745', normal, compile, [''])
|
| 958 | 958 | test('T26451', normal, compile, [''])
|
| 959 | 959 | test('T26582', normal, compile, [''])
|
| 960 | +test('T26737', normal, compile, ['']) |