Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
-
7b2d1e6d
by Simon Peyton Jones at 2025-05-11T03:24:47-04:00
6 changed files:
- compiler/GHC/Tc/Solver/Equality.hs
- compiler/GHC/Tc/Solver/InertSet.hs
- + testsuite/tests/typecheck/should_compile/T26020.hs
- + testsuite/tests/typecheck/should_compile/T26020a.hs
- + testsuite/tests/typecheck/should_compile/T26020a_help.hs
- testsuite/tests/typecheck/should_compile/all.T
Changes:
... | ... | @@ -1098,7 +1098,7 @@ There are two ways in which decomposing (N ty1) ~r (N ty2) could be incomplete: |
1098 | 1098 | them. This is done in can_eq_nc. Of course, we can't unwrap if the data
|
1099 | 1099 | constructor isn't in scope. See Note [Unwrap newtypes first].
|
1100 | 1100 | |
1101 | -* Incompleteness example (EX2): see #24887
|
|
1101 | +* Incompleteness example (EX2): prioritise Nominal equalities. See #24887
|
|
1102 | 1102 | data family D a
|
1103 | 1103 | data instance D Int = MkD1 (D Char)
|
1104 | 1104 | data instance D Bool = MkD2 (D Char)
|
... | ... | @@ -1116,7 +1116,7 @@ There are two ways in which decomposing (N ty1) ~r (N ty2) could be incomplete: |
1116 | 1116 | CONCLUSION: prioritise nominal equalites in the work list.
|
1117 | 1117 | See Note [Prioritise equalities] in GHC.Tc.Solver.InertSet.
|
1118 | 1118 | |
1119 | -* Incompleteness example (EX3): available Givens
|
|
1119 | +* Incompleteness example (EX3): check available Givens
|
|
1120 | 1120 | newtype Nt a = Mk Bool -- NB: a is not used in the RHS,
|
1121 | 1121 | type role Nt representational -- but the user gives it an R role anyway
|
1122 | 1122 | |
... | ... | @@ -1134,36 +1134,41 @@ There are two ways in which decomposing (N ty1) ~r (N ty2) could be incomplete: |
1134 | 1134 | equalities that could later solve it.
|
1135 | 1135 | |
1136 | 1136 | But what precisely does it mean to say "any Given equalities that could
|
1137 | - later solve it"?
|
|
1138 | - |
|
1139 | - In #22924 we had
|
|
1140 | - [G] f a ~R# a [W] Const (f a) a ~R# Const a a
|
|
1141 | - where Const is an abstract newtype. If we decomposed the newtype, we
|
|
1142 | - could solve. Not-decomposing on the grounds that (f a ~R# a) might turn
|
|
1143 | - into (Const (f a) a ~R# Const a a) seems a bit silly.
|
|
1144 | - |
|
1145 | - In #22331 we had
|
|
1146 | - [G] N a ~R# N b [W] N b ~R# N a
|
|
1147 | - (where N is abstract so we can't unwrap). Here we really /don't/ want to
|
|
1148 | - decompose, because the /only/ way to solve the Wanted is from that Given
|
|
1149 | - (with a Sym).
|
|
1150 | - |
|
1151 | - In #22519 we had
|
|
1152 | - [G] a <= b [W] IO Age ~R# IO Int
|
|
1153 | - |
|
1154 | - (where IO is abstract so we can't unwrap, and newtype Age = Int; and (<=)
|
|
1155 | - is a type-level comparison on Nats). Here we /must/ decompose, despite the
|
|
1156 | - existence of an Irred Given, or we will simply be stuck. (Side note: We
|
|
1157 | - flirted with deep-rewriting of newtypes (see discussion on #22519 and
|
|
1158 | - !9623) but that turned out not to solve #22924, and also makes type
|
|
1159 | - inference loop more often on recursive newtypes.)
|
|
1137 | + later solve it"? It's tricky!
|
|
1138 | + |
|
1139 | + * In #22924 we had
|
|
1140 | + [G] f a ~R# a [W] Const (f a) a ~R# Const a a
|
|
1141 | + where Const is an abstract newtype. If we decomposed the newtype, we
|
|
1142 | + could solve. Not-decomposing on the grounds that (f a ~R# a) might turn
|
|
1143 | + into (Const (f a) a ~R# Const a a) seems a bit silly.
|
|
1144 | + |
|
1145 | + * In #22331 we had
|
|
1146 | + [G] N a ~R# N b [W] N b ~R# N a
|
|
1147 | + (where N is abstract so we can't unwrap). Here we really /don't/ want to
|
|
1148 | + decompose, because the /only/ way to solve the Wanted is from that Given
|
|
1149 | + (with a Sym).
|
|
1150 | + |
|
1151 | + * In #22519 we had
|
|
1152 | + [G] a <= b [W] IO Age ~R# IO Int
|
|
1153 | + |
|
1154 | + (where IO is abstract so we can't unwrap, and newtype Age = Int; and (<=)
|
|
1155 | + is a type-level comparison on Nats). Here we /must/ decompose, despite the
|
|
1156 | + existence of an Irred Given, or we will simply be stuck. (Side note: We
|
|
1157 | + flirted with deep-rewriting of newtypes (see discussion on #22519 and
|
|
1158 | + !9623) but that turned out not to solve #22924, and also makes type
|
|
1159 | + inference loop more often on recursive newtypes.)
|
|
1160 | + |
|
1161 | + * In #26020 we had a /quantified/ constraint
|
|
1162 | + forall x. Coercible (N t1) (N t2)
|
|
1163 | + and (roughly) [W] N t1 ~R# N t2
|
|
1164 | + That quantified constraint can solve the Wanted, so don't decompose!
|
|
1160 | 1165 | |
1161 | 1166 | The currently-implemented compromise is this:
|
1162 | - |
|
1163 | - we decompose [W] N s ~R# N t unless there is a [G] N s' ~ N t'
|
|
1164 | - |
|
1165 | - that is, a Given Irred equality with both sides headed with N.
|
|
1166 | - See the call to noGivenNewtypeReprEqs in canTyConApp.
|
|
1167 | + We decompose [W] N s ~R# N t unless there is
|
|
1168 | + - an Irred [G] N s' ~ N t'
|
|
1169 | + - a quantified [G] forall ... => N s' ~ N t'
|
|
1170 | + that is, a Given equality with both sides headed with N.
|
|
1171 | + See the call to `noGivenNewtypeReprEqs` in `canTyConApp`.
|
|
1167 | 1172 | |
1168 | 1173 | This is not perfect. In principle a Given like [G] (a b) ~ (c d), or
|
1169 | 1174 | even just [G] c, could later turn into N s ~ N t. But since the free
|
... | ... | @@ -1174,7 +1179,7 @@ There are two ways in which decomposing (N ty1) ~r (N ty2) could be incomplete: |
1174 | 1179 | un-expanded equality superclasses; but only in some very obscure
|
1175 | 1180 | recursive-superclass situations.
|
1176 | 1181 | |
1177 | - Yet another approach (!) is desribed in
|
|
1182 | + Yet another approach (!) is described in
|
|
1178 | 1183 | Note [Decomposing newtypes a bit more aggressively].
|
1179 | 1184 | |
1180 | 1185 | Remember: decomposing Wanteds is always /sound/. This Note is
|
... | ... | @@ -70,7 +70,7 @@ import GHC.Core.Predicate |
70 | 70 | import qualified GHC.Core.TyCo.Rep as Rep
|
71 | 71 | import GHC.Core.TyCon
|
72 | 72 | import GHC.Core.Class( classTyCon )
|
73 | -import GHC.Builtin.Names( eqPrimTyConKey, heqTyConKey, eqTyConKey )
|
|
73 | +import GHC.Builtin.Names( eqPrimTyConKey, heqTyConKey, eqTyConKey, coercibleTyConKey )
|
|
74 | 74 | import GHC.Utils.Misc ( partitionWith )
|
75 | 75 | import GHC.Utils.Outputable
|
76 | 76 | import GHC.Utils.Panic
|
... | ... | @@ -1862,21 +1862,34 @@ isOuterTyVar tclvl tv |
1862 | 1862 | | otherwise = False -- Coercion variables; doesn't much matter
|
1863 | 1863 | |
1864 | 1864 | noGivenNewtypeReprEqs :: TyCon -> InertSet -> Bool
|
1865 | --- True <=> there is no Irred looking like (N tys1 ~ N tys2)
|
|
1866 | --- See Note [Decomposing newtype equalities] (EX2) in GHC.Tc.Solver.Equality
|
|
1867 | --- This is the only call site.
|
|
1868 | -noGivenNewtypeReprEqs tc inerts
|
|
1869 | - = not (anyBag might_help (inert_irreds (inert_cans inerts)))
|
|
1865 | +-- True <=> there is no Given looking like (N tys1 ~ N tys2)
|
|
1866 | +-- See Note [Decomposing newtype equalities] (EX3) in GHC.Tc.Solver.Equality
|
|
1867 | +noGivenNewtypeReprEqs tc (IS { inert_cans = inerts })
|
|
1868 | + | IC { inert_irreds = irreds, inert_insts = quant_cts } <- inerts
|
|
1869 | + = not (anyBag might_help_irred irreds || any might_help_qc quant_cts)
|
|
1870 | + -- Look in both inert_irreds /and/ inert_insts (#26020)
|
|
1870 | 1871 | where
|
1871 | - might_help irred
|
|
1872 | - = case classifyPredType (ctEvPred (irredCtEvidence irred)) of
|
|
1873 | - EqPred ReprEq t1 t2
|
|
1874 | - | Just (tc1,_) <- tcSplitTyConApp_maybe t1
|
|
1875 | - , tc == tc1
|
|
1876 | - , Just (tc2,_) <- tcSplitTyConApp_maybe t2
|
|
1877 | - , tc == tc2
|
|
1878 | - -> True
|
|
1879 | - _ -> False
|
|
1872 | + might_help_irred (IrredCt { ir_ev = ev })
|
|
1873 | + | EqPred ReprEq t1 t2 <- classifyPredType (ctEvPred ev)
|
|
1874 | + = headed_by_tc t1 t2
|
|
1875 | + | otherwise
|
|
1876 | + = False
|
|
1877 | + |
|
1878 | + might_help_qc (QCI { qci_body = pred })
|
|
1879 | + | ClassPred cls [_, t1, t2] <- classifyPredType pred
|
|
1880 | + , cls `hasKey` coercibleTyConKey
|
|
1881 | + = headed_by_tc t1 t2
|
|
1882 | + | otherwise
|
|
1883 | + = False
|
|
1884 | + |
|
1885 | + headed_by_tc t1 t2
|
|
1886 | + | Just (tc1,_) <- tcSplitTyConApp_maybe t1
|
|
1887 | + , tc == tc1
|
|
1888 | + , Just (tc2,_) <- tcSplitTyConApp_maybe t2
|
|
1889 | + , tc == tc2
|
|
1890 | + = True
|
|
1891 | + | otherwise
|
|
1892 | + = False
|
|
1880 | 1893 | |
1881 | 1894 | -- | Is it (potentially) loopy to use the first @ct1@ to solve @ct2@?
|
1882 | 1895 | --
|
1 | +{-# LANGUAGE TypeFamilies #-}
|
|
2 | +{-# LANGUAGE QuantifiedConstraints #-}
|
|
3 | + |
|
4 | +module T26020 where
|
|
5 | + |
|
6 | +import Data.Kind
|
|
7 | +import Data.Coerce
|
|
8 | + |
|
9 | +class C r where
|
|
10 | + data T r :: Type -> Type
|
|
11 | + |
|
12 | +-- type family F r
|
|
13 | +-- data T r i = MkR r (F i)
|
|
14 | + |
|
15 | +coT :: (forall x. Coercible (T r i) (T r o))
|
|
16 | + => T r i -> T r o
|
|
17 | +coT = coerce |
1 | +{-# LANGUAGE QuantifiedConstraints #-}
|
|
2 | +module T26020a where
|
|
3 | + |
|
4 | +import T26020a_help( N ) -- Not the MkN constructor
|
|
5 | +import Data.Coerce
|
|
6 | + |
|
7 | +coT :: (forall x. Coercible (N i) (N o))
|
|
8 | + => N i -> N o
|
|
9 | +coT = coerce |
1 | +{-# LANGUAGE TypeFamilies #-}
|
|
2 | + |
|
3 | +module T26020a_help where
|
|
4 | + |
|
5 | +type family F a
|
|
6 | +newtype N a = MkN (F a)
|
|
7 | + |
... | ... | @@ -938,3 +938,5 @@ test('T25266a', normal, compile_fail, ['']) |
938 | 938 | test('T25266b', normal, compile, [''])
|
939 | 939 | test('T25597', normal, compile, [''])
|
940 | 940 | test('T25960', normal, compile, [''])
|
941 | +test('T26020', normal, compile, [''])
|
|
942 | +test('T26020a', [extra_files(['T26020a_help.hs'])], multimod_compile, ['T26020a', '-v0']) |