Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
-
c052c724
by Simon Peyton Jones at 2025-11-06T21:34:06-05:00
4 changed files:
- compiler/GHC/Tc/Solver/Dict.hs
- compiler/GHC/Tc/Solver/Monad.hs
- + testsuite/tests/typecheck/should_compile/T26451.hs
- testsuite/tests/typecheck/should_compile/all.T
Changes:
| ... | ... | @@ -263,7 +263,9 @@ in two places: |
| 263 | 263 | * In `updInertDicts`, in this module, when adding [G] (?x :: ty), remove any
|
| 264 | 264 | existing [G] (?x :: ty'), regardless of ty'.
|
| 265 | 265 | |
| 266 | -* Wrinkle (SIP1): we must be careful of superclasses. Consider
|
|
| 266 | +There are wrinkles:
|
|
| 267 | + |
|
| 268 | +* Wrinkle (SIP1): we must be careful of superclasses (#14218). Consider
|
|
| 267 | 269 | f,g :: (?x::Int, C a) => a -> a
|
| 268 | 270 | f v = let ?x = 4 in g v
|
| 269 | 271 | |
| ... | ... | @@ -271,24 +273,31 @@ in two places: |
| 271 | 273 | We must /not/ solve this from the Given (?x::Int, C a), because of
|
| 272 | 274 | the intervening binding for (?x::Int). #14218.
|
| 273 | 275 | |
| 274 | - We deal with this by arranging that when we add [G] (?x::ty) we delete
|
|
| 276 | + We deal with this by arranging that when we add [G] (?x::ty) we /delete/
|
|
| 275 | 277 | * from the inert_cans, and
|
| 276 | 278 | * from the inert_solved_dicts
|
| 277 | 279 | any existing [G] (?x::ty) /and/ any [G] D tys, where (D tys) has a superclass
|
| 278 | 280 | with (?x::ty). See Note [Local implicit parameters] in GHC.Core.Predicate.
|
| 279 | 281 | |
| 280 | - An important special case is constraint tuples like [G] (% ?x::ty, Eq a %).
|
|
| 281 | - But it could happen for `class xx => D xx where ...` and the constraint D
|
|
| 282 | - (?x :: int). This corner (constraint-kinded variables instantiated with
|
|
| 283 | - implicit parameter constraints) is not well explored.
|
|
| 282 | + An very important special case is constraint tuples like [G] (% ?x::ty, Eq a %).
|
|
| 283 | + |
|
| 284 | + But it could also happen for `class xx => D xx where ...` and the constraint
|
|
| 285 | + D (?x :: int); again see Note [Local implicit parameters]. This corner
|
|
| 286 | + (constraint-kinded variables instantiated with implicit parameter constraints)
|
|
| 287 | + is not well explored.
|
|
| 284 | 288 | |
| 285 | - Example in #14218, and #23761
|
|
| 289 | + You might worry about whether deleting an /entire/ constraint just because
|
|
| 290 | + a distant superclass has an implicit parameter might make another Wanted for
|
|
| 291 | + that constraint un-solvable. Indeed so. But for constraint tuples it doesn't
|
|
| 292 | + matter -- their entire payload is their superclasses. And the other case is
|
|
| 293 | + the ill-explored corner above.
|
|
| 286 | 294 | |
| 287 | 295 | The code that accounts for (SIP1) is in updInertDicts; in particular the call to
|
| 288 | 296 | GHC.Core.Predicate.mentionsIP.
|
| 289 | 297 | |
| 290 | 298 | * Wrinkle (SIP2): we must apply this update semantics for `inert_solved_dicts`
|
| 291 | - as well as `inert_cans`.
|
|
| 299 | + as well as `inert_cans` (#23761).
|
|
| 300 | + |
|
| 292 | 301 | You might think that wouldn't be necessary, because an element of
|
| 293 | 302 | `inert_solved_dicts` is never an implicit parameter (see
|
| 294 | 303 | Note [Solved dictionaries] in GHC.Tc.Solver.InertSet).
|
| ... | ... | @@ -301,6 +310,19 @@ in two places: |
| 301 | 310 | Now (C (?x::Int)) has a superclass (?x::Int). This may look exotic, but it
|
| 302 | 311 | happens particularly for constraint tuples, like `(% ?x::Int, Eq a %)`.
|
| 303 | 312 | |
| 313 | +* Wrinkle (SIP3)
|
|
| 314 | + - Note that for the inert dictionaries, `inert_cans`, we must /only/ delete
|
|
| 315 | + existing /Givens/! Deleting an existing Wanted led to #26451; we just never
|
|
| 316 | + solved it!
|
|
| 317 | + |
|
| 318 | + - In contrast, the solved dictionaries, `inert_solved_dicts`, are really like
|
|
| 319 | + Givens; they may be "inherited" from outer scopes, so we must delete any
|
|
| 320 | + solved dictionaries for this implicit parameter for /both/ Givens /and/
|
|
| 321 | + Wanteds.
|
|
| 322 | + |
|
| 323 | + Otherwise the new Given doesn't properly shadow those inherited solved
|
|
| 324 | + dictionaries. Test T23761 showed this up.
|
|
| 325 | + |
|
| 304 | 326 | Example 1:
|
| 305 | 327 | |
| 306 | 328 | Suppose we have (typecheck/should_compile/ImplicitParamFDs)
|
| ... | ... | @@ -377,28 +377,53 @@ in GHC.Tc.Solver.Dict. |
| 377 | 377 | -}
|
| 378 | 378 | |
| 379 | 379 | updInertDicts :: DictCt -> TcS ()
|
| 380 | -updInertDicts dict_ct@(DictCt { di_cls = cls, di_ev = ev, di_tys = tys })
|
|
| 381 | - = do { traceTcS "Adding inert dict" (ppr dict_ct $$ ppr cls <+> ppr tys)
|
|
| 382 | - |
|
| 383 | - ; if | isGiven ev, Just (str_ty, _) <- isIPPred_maybe cls tys
|
|
| 384 | - -> -- For [G] ?x::ty, remove any dicts mentioning ?x,
|
|
| 385 | - -- from /both/ inert_cans /and/ inert_solved_dicts (#23761)
|
|
| 386 | - -- See (SIP1) and (SIP2) in Note [Shadowing of implicit parameters]
|
|
| 387 | - updInertSet $ \ inerts@(IS { inert_cans = ics, inert_solved_dicts = solved }) ->
|
|
| 388 | - inerts { inert_cans = updDicts (filterDicts (does_not_mention_ip_for str_ty)) ics
|
|
| 389 | - , inert_solved_dicts = filterDicts (does_not_mention_ip_for str_ty) solved }
|
|
| 390 | - | otherwise
|
|
| 391 | - -> return ()
|
|
| 380 | +updInertDicts dict_ct
|
|
| 381 | + = do { traceTcS "Adding inert dict" (ppr dict_ct)
|
|
| 382 | + |
|
| 383 | + -- For Given implicit parameters (only), delete any existing
|
|
| 384 | + -- Givens for the same implicit parameter.
|
|
| 385 | + -- See Note [Shadowing of implicit parameters]
|
|
| 386 | + ; deleteGivenIPs dict_ct
|
|
| 387 | + |
|
| 392 | 388 | -- Add the new constraint to the inert set
|
| 393 | 389 | ; updInertCans (updDicts (addDict dict_ct)) }
|
| 390 | + |
|
| 391 | +deleteGivenIPs :: DictCt -> TcS ()
|
|
| 392 | +-- Special magic when adding a Given implicit parameter to the inert set
|
|
| 393 | +-- For [G] ?x::ty, remove any existing /Givens/ mentioning ?x,
|
|
| 394 | +-- from /both/ inert_cans /and/ inert_solved_dicts (#23761)
|
|
| 395 | +-- See Note [Shadowing of implicit parameters]
|
|
| 396 | +deleteGivenIPs (DictCt { di_cls = cls, di_ev = ev, di_tys = tys })
|
|
| 397 | + | isGiven ev
|
|
| 398 | + , Just (str_ty, _) <- isIPPred_maybe cls tys
|
|
| 399 | + = updInertSet $ \ inerts@(IS { inert_cans = ics, inert_solved_dicts = solved }) ->
|
|
| 400 | + inerts { inert_cans = updDicts (filterDicts (keep_can str_ty)) ics
|
|
| 401 | + , inert_solved_dicts = filterDicts (keep_solved str_ty) solved }
|
|
| 402 | + | otherwise
|
|
| 403 | + = return ()
|
|
| 394 | 404 | where
|
| 395 | - -- Does this class constraint or any of its superclasses mention
|
|
| 396 | - -- an implicit parameter (?str :: ty) for the given 'str' and any type 'ty'?
|
|
| 397 | - does_not_mention_ip_for :: Type -> DictCt -> Bool
|
|
| 398 | - does_not_mention_ip_for str_ty (DictCt { di_cls = cls, di_tys = tys })
|
|
| 399 | - = not $ mightMentionIP (not . typesAreApart str_ty) (const True) cls tys
|
|
| 400 | - -- See Note [Using typesAreApart when calling mightMentionIP]
|
|
| 401 | - -- in GHC.Core.Predicate
|
|
| 405 | + keep_can, keep_solved :: Type -> DictCt -> Bool
|
|
| 406 | + -- keep_can: we keep an inert dictionary UNLESS
|
|
| 407 | + -- (1) it is a Given
|
|
| 408 | + -- (2) it binds an implicit parameter (?str :: ty) for the given 'str'
|
|
| 409 | + -- regardless of 'ty', possibly via its superclasses
|
|
| 410 | + -- The test is a bit conservative, hence `mightMentionIP` and `typesAreApart`
|
|
| 411 | + -- See Note [Using typesAreApart when calling mightMentionIP]
|
|
| 412 | + -- in GHC.Core.Predicate
|
|
| 413 | + --
|
|
| 414 | + -- keep_solved: same as keep_can, but for /all/ constraints not just Givens
|
|
| 415 | + --
|
|
| 416 | + -- Why two functions? See (SIP3) in Note [Shadowing of implicit parameters]
|
|
| 417 | + keep_can str (DictCt { di_ev = ev, di_cls = cls, di_tys = tys })
|
|
| 418 | + = not (isGiven ev -- (1)
|
|
| 419 | + && mentions_ip str cls tys) -- (2)
|
|
| 420 | + keep_solved str (DictCt { di_cls = cls, di_tys = tys })
|
|
| 421 | + = not (mentions_ip str cls tys)
|
|
| 422 | + |
|
| 423 | + -- mentions_ip: the inert constraint might provide evidence
|
|
| 424 | + -- for an implicit parameter (?str :: ty) for the given 'str'
|
|
| 425 | + mentions_ip str cls tys
|
|
| 426 | + = mightMentionIP (not . typesAreApart str) (const True) cls tys
|
|
| 402 | 427 | |
| 403 | 428 | updInertIrreds :: IrredCt -> TcS ()
|
| 404 | 429 | updInertIrreds irred
|
| 1 | +{-# LANGUAGE ImplicitParams, TypeFamilies, FunctionalDependencies, ScopedTypeVariables #-}
|
|
| 2 | + |
|
| 3 | +module T26451 where
|
|
| 4 | + |
|
| 5 | +type family F a
|
|
| 6 | +type instance F Bool = [Char]
|
|
| 7 | + |
|
| 8 | +class C a b | b -> a
|
|
| 9 | +instance C Bool Bool
|
|
| 10 | +instance C Char Char
|
|
| 11 | + |
|
| 12 | +eq :: forall a b. C a b => a -> b -> ()
|
|
| 13 | +eq p q = ()
|
|
| 14 | + |
|
| 15 | +g :: a -> F a
|
|
| 16 | +g = g
|
|
| 17 | + |
|
| 18 | +f (x::tx) (y::ty) -- x :: alpha y :: beta
|
|
| 19 | + = let ?v = g x -- ?ip :: F alpha
|
|
| 20 | + in (?v::[ty], eq x True)
|
|
| 21 | + |
|
| 22 | + |
|
| 23 | +{- tx, and ty are unification variables
|
|
| 24 | + |
|
| 25 | +Inert: [G] dg :: IP "v" (F tx)
|
|
| 26 | + [W] dw :: IP "v" [ty]
|
|
| 27 | +Work-list: [W] dc1 :: C tx Bool
|
|
| 28 | + [W] dc2 :: C ty Char
|
|
| 29 | + |
|
| 30 | +* Solve dc1, we get tx := Bool from fundep
|
|
| 31 | +* Kick out dg
|
|
| 32 | +* Solve dg to get [G] dc : IP "v" [Char]
|
|
| 33 | +* Add that new dg to the inert set: that simply deletes dw!!!
|
|
| 34 | +-} |
| ... | ... | @@ -955,3 +955,4 @@ test('T26376', normal, compile, ['']) |
| 955 | 955 | test('T26457', normal, compile, [''])
|
| 956 | 956 | test('T17705', normal, compile, [''])
|
| 957 | 957 | test('T14745', normal, compile, [''])
|
| 958 | +test('T26451', normal, compile, ['']) |