Simon Peyton Jones pushed to branch wip/T23162-spj at Glasgow Haskell Compiler / GHC
Commits:
-
46241879
by Simon Peyton Jones at 2025-07-07T16:05:46+01:00
-
e970a6b8
by Simon Peyton Jones at 2025-07-07T16:39:04+01:00
6 changed files:
- compiler/GHC/Tc/Solver/Dict.hs
- compiler/GHC/Tc/Solver/Equality.hs
- + compiler/GHC/Tc/Solver/FunDeps.hs
- compiler/GHC/Tc/Solver/Monad.hs
- compiler/GHC/Tc/Solver/Solve.hs
- compiler/ghc.cabal.in
Changes:
| ... | ... | @@ -8,9 +8,6 @@ module GHC.Tc.Solver.Dict ( |
| 8 | 8 | matchLocalInst, chooseInstance,
|
| 9 | 9 | makeSuperClasses, mkStrictSuperClasses,
|
| 10 | 10 | solveCallStack, -- For GHC.Tc.Solver
|
| 11 | - |
|
| 12 | - -- * Functional dependencies
|
|
| 13 | - doDictFunDepImprovement
|
|
| 14 | 11 | ) where
|
| 15 | 12 | |
| 16 | 13 | import GHC.Prelude
|
| ... | ... | @@ -1379,346 +1376,6 @@ with the least superclass depth (see Note [Replacement vs keeping]), |
| 1379 | 1376 | but that doesn't work for the example from #22216.
|
| 1380 | 1377 | -}
|
| 1381 | 1378 | |
| 1382 | -{- *********************************************************************
|
|
| 1383 | -* *
|
|
| 1384 | -* Functional dependencies, instantiation of equations
|
|
| 1385 | -* *
|
|
| 1386 | -************************************************************************
|
|
| 1387 | - |
|
| 1388 | -When we spot an equality arising from a functional dependency,
|
|
| 1389 | -we now use that equality (a "wanted") to rewrite the work-item
|
|
| 1390 | -constraint right away. This avoids two dangers
|
|
| 1391 | - |
|
| 1392 | - Danger 1: If we send the original constraint on down the pipeline
|
|
| 1393 | - it may react with an instance declaration, and in delicate
|
|
| 1394 | - situations (when a Given overlaps with an instance) that
|
|
| 1395 | - may produce new insoluble goals: see #4952
|
|
| 1396 | - |
|
| 1397 | - Danger 2: If we don't rewrite the constraint, it may re-react
|
|
| 1398 | - with the same thing later, and produce the same equality
|
|
| 1399 | - again --> termination worries.
|
|
| 1400 | - |
|
| 1401 | -To achieve this required some refactoring of GHC.Tc.Instance.FunDeps (nicer
|
|
| 1402 | -now!).
|
|
| 1403 | - |
|
| 1404 | -Note [FunDep and implicit parameter reactions]
|
|
| 1405 | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 1406 | -Currently, our story of interacting two dictionaries (or a dictionary
|
|
| 1407 | -and top-level instances) for functional dependencies (including implicit
|
|
| 1408 | -parameters), is that we simply produce new Wanted equalities. So for example
|
|
| 1409 | - |
|
| 1410 | - class D a b | a -> b where ...
|
|
| 1411 | - Inert:
|
|
| 1412 | - [G] d1 : D Int Bool
|
|
| 1413 | - WorkItem:
|
|
| 1414 | - [W] d2 : D Int alpha
|
|
| 1415 | - |
|
| 1416 | - We generate the extra work item
|
|
| 1417 | - [W] cv : alpha ~ Bool
|
|
| 1418 | - where 'cv' is currently unused. However, this new item can perhaps be
|
|
| 1419 | - spontaneously solved to become given and react with d2,
|
|
| 1420 | - discharging it in favour of a new constraint d2' thus:
|
|
| 1421 | - [W] d2' : D Int Bool
|
|
| 1422 | - d2 := d2' |> D Int cv
|
|
| 1423 | - Now d2' can be discharged from d1
|
|
| 1424 | - |
|
| 1425 | -We could be more aggressive and try to *immediately* solve the dictionary
|
|
| 1426 | -using those extra equalities.
|
|
| 1427 | - |
|
| 1428 | -If that were the case with the same inert set and work item we might discard
|
|
| 1429 | -d2 directly:
|
|
| 1430 | - |
|
| 1431 | - [W] cv : alpha ~ Bool
|
|
| 1432 | - d2 := d1 |> D Int cv
|
|
| 1433 | - |
|
| 1434 | -But in general it's a bit painful to figure out the necessary coercion,
|
|
| 1435 | -so we just take the first approach. Here is a better example. Consider:
|
|
| 1436 | - class C a b c | a -> b
|
|
| 1437 | -And:
|
|
| 1438 | - [G] d1 : C T Int Char
|
|
| 1439 | - [W] d2 : C T beta Int
|
|
| 1440 | -In this case, it's *not even possible* to solve the wanted immediately.
|
|
| 1441 | -So we should simply output the functional dependency and add this guy
|
|
| 1442 | -[but NOT its superclasses] back in the worklist. Even worse:
|
|
| 1443 | - [G] d1 : C T Int beta
|
|
| 1444 | - [W] d2: C T beta Int
|
|
| 1445 | -Then it is solvable, but its very hard to detect this on the spot.
|
|
| 1446 | - |
|
| 1447 | -It's exactly the same with implicit parameters, except that the
|
|
| 1448 | -"aggressive" approach would be much easier to implement.
|
|
| 1449 | - |
|
| 1450 | -Note [Fundeps with instances, and equality orientation]
|
|
| 1451 | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 1452 | -This Note describes a delicate interaction that constrains the orientation of
|
|
| 1453 | -equalities. This one is about fundeps, but the /exact/ same thing arises for
|
|
| 1454 | -type-family injectivity constraints: see Note [Improvement orientation].
|
|
| 1455 | - |
|
| 1456 | -doTopFunDepImprovement compares the constraint with all the instance
|
|
| 1457 | -declarations, to see if we can produce any equalities. E.g
|
|
| 1458 | - class C2 a b | a -> b
|
|
| 1459 | - instance C Int Bool
|
|
| 1460 | -Then the constraint (C Int ty) generates the equality [W] ty ~ Bool.
|
|
| 1461 | - |
|
| 1462 | -There is a nasty corner in #19415 which led to the typechecker looping:
|
|
| 1463 | - class C s t b | s -> t
|
|
| 1464 | - instance ... => C (T kx x) (T ky y) Int
|
|
| 1465 | - T :: forall k. k -> Type
|
|
| 1466 | - |
|
| 1467 | - work_item: dwrk :: C (T @ka (a::ka)) (T @kb0 (b0::kb0)) Char
|
|
| 1468 | - where kb0, b0 are unification vars
|
|
| 1469 | - |
|
| 1470 | - ==> {doTopFunDepImprovement: compare work_item with instance,
|
|
| 1471 | - generate /fresh/ unification variables kfresh0, yfresh0,
|
|
| 1472 | - emit a new Wanted, and add dwrk to inert set}
|
|
| 1473 | - |
|
| 1474 | - Suppose we emit this new Wanted from the fundep:
|
|
| 1475 | - [W] T kb0 (b0::kb0) ~ T kfresh0 (yfresh0::kfresh0)
|
|
| 1476 | - |
|
| 1477 | - ==> {solve that equality kb0 := kfresh0, b0 := yfresh0}
|
|
| 1478 | - Now kick out dwrk, since it mentions kb0
|
|
| 1479 | - But now we are back to the start! Loop!
|
|
| 1480 | - |
|
| 1481 | -NB1: This example relies on an instance that does not satisfy the
|
|
| 1482 | - coverage condition (although it may satisfy the weak coverage
|
|
| 1483 | - condition), and hence whose fundeps generate fresh unification
|
|
| 1484 | - variables. Not satisfying the coverage condition is known to
|
|
| 1485 | - lead to termination trouble, but in this case it's plain silly.
|
|
| 1486 | - |
|
| 1487 | -NB2: In this example, the third parameter to C ensures that the
|
|
| 1488 | - instance doesn't actually match the Wanted, so we can't use it to
|
|
| 1489 | - solve the Wanted
|
|
| 1490 | - |
|
| 1491 | -We solve the problem by (#21703):
|
|
| 1492 | - |
|
| 1493 | - carefully orienting the new Wanted so that all the
|
|
| 1494 | - freshly-generated unification variables are on the LHS.
|
|
| 1495 | - |
|
| 1496 | - Thus we call unifyWanteds on
|
|
| 1497 | - T kfresh0 (yfresh0::kfresh0) ~ T kb0 (b0::kb0)
|
|
| 1498 | - and /NOT/
|
|
| 1499 | - T kb0 (b0::kb0) ~ T kfresh0 (yfresh0::kfresh0)
|
|
| 1500 | - |
|
| 1501 | -Now we'll unify kfresh0:=kb0, yfresh0:=b0, and all is well. The general idea
|
|
| 1502 | -is that we want to preferentially eliminate those freshly-generated
|
|
| 1503 | -unification variables, rather than unifying older variables, which causes
|
|
| 1504 | -kick-out etc.
|
|
| 1505 | - |
|
| 1506 | -Keeping younger variables on the left also gives very minor improvement in
|
|
| 1507 | -the compiler performance by having less kick-outs and allocations (-0.1% on
|
|
| 1508 | -average). Indeed Historical Note [Eliminate younger unification variables]
|
|
| 1509 | -in GHC.Tc.Utils.Unify describes an earlier attempt to do so systematically,
|
|
| 1510 | -apparently now in abeyance.
|
|
| 1511 | - |
|
| 1512 | -But this is is a delicate solution. We must take care to /preserve/
|
|
| 1513 | -orientation during solving. Wrinkles:
|
|
| 1514 | - |
|
| 1515 | -(W1) We start with
|
|
| 1516 | - [W] T kfresh0 (yfresh0::kfresh0) ~ T kb0 (b0::kb0)
|
|
| 1517 | - Decompose to
|
|
| 1518 | - [W] kfresh0 ~ kb0
|
|
| 1519 | - [W] (yfresh0::kfresh0) ~ (b0::kb0)
|
|
| 1520 | - Preserve orientation when decomposing!!
|
|
| 1521 | - |
|
| 1522 | -(W2) Suppose we happen to tackle the second Wanted from (W1)
|
|
| 1523 | - first. Then in canEqCanLHSHetero we emit a /kind/ equality, as
|
|
| 1524 | - well as a now-homogeneous type equality
|
|
| 1525 | - [W] kco : kfresh0 ~ kb0
|
|
| 1526 | - [W] (yfresh0::kfresh0) ~ (b0::kb0) |> (sym kco)
|
|
| 1527 | - Preserve orientation in canEqCanLHSHetero!! (Failing to
|
|
| 1528 | - preserve orientation here was the immediate cause of #21703.)
|
|
| 1529 | - |
|
| 1530 | -(W3) There is a potential interaction with the swapping done by
|
|
| 1531 | - GHC.Tc.Utils.Unify.swapOverTyVars. We think it's fine, but it's
|
|
| 1532 | - a slight worry. See especially Note [TyVar/TyVar orientation] in
|
|
| 1533 | - that module.
|
|
| 1534 | - |
|
| 1535 | -The trouble is that "preserving orientation" is a rather global invariant,
|
|
| 1536 | -and sometimes we definitely do want to swap (e.g. Int ~ alpha), so we don't
|
|
| 1537 | -even have a precise statement of what the invariant is. The advantage
|
|
| 1538 | -of the preserve-orientation plan is that it is extremely cheap to implement,
|
|
| 1539 | -and apparently works beautifully.
|
|
| 1540 | - |
|
| 1541 | ---- Alternative plan (1) ---
|
|
| 1542 | -Rather than have an ill-defined invariant, another possiblity is to
|
|
| 1543 | -elminate those fresh unification variables at birth, when generating
|
|
| 1544 | -the new fundep-inspired equalities.
|
|
| 1545 | - |
|
| 1546 | -The key idea is to call `instFlexiX` in `emitFunDepWanteds` on only those
|
|
| 1547 | -type variables that are guaranteed to give us some progress. This means we
|
|
| 1548 | -have to locally (without calling emitWanteds) identify the type variables
|
|
| 1549 | -that do not give us any progress. In the above example, we _know_ that
|
|
| 1550 | -emitting the two wanteds `kco` and `co` is fruitless.
|
|
| 1551 | - |
|
| 1552 | - Q: How do we identify such no-ops?
|
|
| 1553 | - |
|
| 1554 | - 1. Generate a matching substitution from LHS to RHS
|
|
| 1555 | - ɸ = [kb0 :-> k0, b0 :-> y0]
|
|
| 1556 | - 2. Call `instFlexiX` on only those type variables that do not appear in the domain of ɸ
|
|
| 1557 | - ɸ' = instFlexiX ɸ (tvs - domain ɸ)
|
|
| 1558 | - 3. Apply ɸ' on LHS and then call emitWanteds
|
|
| 1559 | - unifyWanteds ... (subst ɸ' LHS) RHS
|
|
| 1560 | - |
|
| 1561 | -Why will this work? The matching substitution ɸ will be a best effort
|
|
| 1562 | -substitution that gives us all the easy solutions. It can be generated with
|
|
| 1563 | -modified version of `Core/Unify.unify_tys` where we run it in a matching mode
|
|
| 1564 | -and never generate `SurelyApart` and always return a `MaybeApart Subst`
|
|
| 1565 | -instead.
|
|
| 1566 | - |
|
| 1567 | -The same alternative plan would work for type-family injectivity constraints:
|
|
| 1568 | -see Note [Improvement orientation] in GHC.Tc.Solver.Equality.
|
|
| 1569 | ---- End of Alternative plan (1) ---
|
|
| 1570 | - |
|
| 1571 | ---- Alternative plan (2) ---
|
|
| 1572 | -We could have a new flavour of TcTyVar (like `TauTv`, `TyVarTv` etc; see GHC.Tc.Utils.TcType.MetaInfo)
|
|
| 1573 | -for the fresh unification variables introduced by functional dependencies. Say `FunDepTv`. Then in
|
|
| 1574 | -GHC.Tc.Utils.Unify.swapOverTyVars we could arrange to keep a `FunDepTv` on the left if possible.
|
|
| 1575 | -Looks possible, but it's one more complication.
|
|
| 1576 | ---- End of Alternative plan (2) ---
|
|
| 1577 | - |
|
| 1578 | - |
|
| 1579 | ---- Historical note: Failed Alternative Plan (3) ---
|
|
| 1580 | -Previously we used a flag `cc_fundeps` in `CDictCan`. It would flip to False
|
|
| 1581 | -once we used a fun dep to hint the solver to break and to stop emitting more
|
|
| 1582 | -wanteds. This solution was not complete, and caused a failures while trying
|
|
| 1583 | -to solve for transitive functional dependencies (test case: T21703)
|
|
| 1584 | --- End of Historical note: Failed Alternative Plan (3) --
|
|
| 1585 | - |
|
| 1586 | -Note [Do fundeps last]
|
|
| 1587 | -~~~~~~~~~~~~~~~~~~~~~~
|
|
| 1588 | -Consider T4254b:
|
|
| 1589 | - class FD a b | a -> b where { op :: a -> b }
|
|
| 1590 | - |
|
| 1591 | - instance FD Int Bool
|
|
| 1592 | - |
|
| 1593 | - foo :: forall a b. (a~Int,FD a b) => a -> Bool
|
|
| 1594 | - foo = op
|
|
| 1595 | - |
|
| 1596 | -(DFL1) Try local fundeps first.
|
|
| 1597 | - From the ambiguity check on the type signature we get
|
|
| 1598 | - [G] FD Int b
|
|
| 1599 | - [W] FD Int beta
|
|
| 1600 | - Interacting these gives beta:=b; then we start again and solve without
|
|
| 1601 | - trying fundeps between the new [W] FD Int b and the top-level instance.
|
|
| 1602 | - If we did, we'd generate [W] b ~ Bool, which fails.
|
|
| 1603 | - |
|
| 1604 | -(DFL2) Try solving from top-level instances before fundeps
|
|
| 1605 | - From the definition `foo = op` we get
|
|
| 1606 | - [G] FD Int b
|
|
| 1607 | - [W] FD Int Bool
|
|
| 1608 | - We solve this from the top level instance before even trying fundeps.
|
|
| 1609 | - If we did try fundeps, we'd generate [W] b ~ Bool, which fails.
|
|
| 1610 | - |
|
| 1611 | - |
|
| 1612 | -Note [Weird fundeps]
|
|
| 1613 | -~~~~~~~~~~~~~~~~~~~~
|
|
| 1614 | -Consider class Het a b | a -> b where
|
|
| 1615 | - het :: m (f c) -> a -> m b
|
|
| 1616 | - |
|
| 1617 | - class GHet (a :: * -> *) (b :: * -> *) | a -> b
|
|
| 1618 | - instance GHet (K a) (K [a])
|
|
| 1619 | - instance Het a b => GHet (K a) (K b)
|
|
| 1620 | - |
|
| 1621 | -The two instances don't actually conflict on their fundeps,
|
|
| 1622 | -although it's pretty strange. So they are both accepted. Now
|
|
| 1623 | -try [W] GHet (K Int) (K Bool)
|
|
| 1624 | -This triggers fundeps from both instance decls;
|
|
| 1625 | - [W] K Bool ~ K [a]
|
|
| 1626 | - [W] K Bool ~ K beta
|
|
| 1627 | -And there's a risk of complaining about Bool ~ [a]. But in fact
|
|
| 1628 | -the Wanted matches the second instance, so we never get as far
|
|
| 1629 | -as the fundeps.
|
|
| 1630 | - |
|
| 1631 | -#7875 is a case in point.
|
|
| 1632 | --}
|
|
| 1633 | - |
|
| 1634 | -doDictFunDepImprovement :: Cts -> TcS (Cts, Bool)
|
|
| 1635 | --- (doDictFunDepImprovement inst_envs cts)
|
|
| 1636 | --- * Generate the fundeps from interacting the
|
|
| 1637 | --- top-level `inst_envs` with the constraints `cts`
|
|
| 1638 | --- * Do the unifications and return any unsolved constraints
|
|
| 1639 | --- See Note [Fundeps with instances, and equality orientation]
|
|
| 1640 | -doDictFunDepImprovement unsolved_wanteds
|
|
| 1641 | - = do { inerts <- getInertCans -- The inert_dicts are all Givens
|
|
| 1642 | - ; inst_envs <- getInstEnvs
|
|
| 1643 | - ; (_, new_eqs, unifs) <- foldrM (do_one_dict inst_envs)
|
|
| 1644 | - (inert_dicts inerts, emptyBag, False)
|
|
| 1645 | - unsolved_wanteds
|
|
| 1646 | - ; return (new_eqs, unifs) }
|
|
| 1647 | - |
|
| 1648 | -do_one_dict :: InstEnvs -> Ct
|
|
| 1649 | - -> (DictMap DictCt, Cts, Bool)
|
|
| 1650 | - -> TcS (DictMap DictCt, Cts, Bool)
|
|
| 1651 | -do_one_dict inst_envs (CDictCan dict_ct) (local_dicts, new_eqs, unifs)
|
|
| 1652 | - = do { (new_eqs1, unifs1) <- do_one_top inst_envs dict_ct
|
|
| 1653 | - ; (local_dicts2, new_eqs2, unifs2) <- do_one_local local_dicts dict_ct
|
|
| 1654 | - ; return ( local_dicts2
|
|
| 1655 | - , new_eqs1 `unionBags` new_eqs2 `unionBags` new_eqs
|
|
| 1656 | - , unifs1 || unifs2 || unifs ) }
|
|
| 1657 | - |
|
| 1658 | -do_one_dict _ _ acc -- Non-DictCt constraints
|
|
| 1659 | - = return acc
|
|
| 1660 | - |
|
| 1661 | -do_one_top :: InstEnvs -> DictCt -> TcS (Cts, Bool)
|
|
| 1662 | -do_one_top inst_envs (DictCt { di_ev = ev, di_cls = cls, di_tys = xis })
|
|
| 1663 | - = unifyFunDepWanteds ev eqns
|
|
| 1664 | - where
|
|
| 1665 | - eqns :: [FunDepEqn (CtLoc, RewriterSet)]
|
|
| 1666 | - eqns = improveFromInstEnv inst_envs mk_ct_loc cls xis
|
|
| 1667 | - |
|
| 1668 | - dict_pred = mkClassPred cls xis
|
|
| 1669 | - dict_loc = ctEvLoc ev
|
|
| 1670 | - dict_origin = ctLocOrigin dict_loc
|
|
| 1671 | - dict_rewriters = ctEvRewriters ev
|
|
| 1672 | - |
|
| 1673 | - mk_ct_loc :: ClsInst -- The instance decl
|
|
| 1674 | - -> (CtLoc, RewriterSet)
|
|
| 1675 | - mk_ct_loc ispec
|
|
| 1676 | - = (dict_loc { ctl_origin = new_orig }, dict_rewriters)
|
|
| 1677 | - where
|
|
| 1678 | - inst_pred = mkClassPred cls (is_tys ispec)
|
|
| 1679 | - inst_loc = getSrcSpan (is_dfun ispec)
|
|
| 1680 | - new_orig = FunDepOrigin2 dict_pred dict_origin
|
|
| 1681 | - inst_pred inst_loc
|
|
| 1682 | - |
|
| 1683 | -do_one_local :: DictMap DictCt -> DictCt -> TcS (DictMap DictCt, Cts, Bool)
|
|
| 1684 | --- Using functional dependencies, interact the unsolved Wanteds
|
|
| 1685 | --- against each other and the inert Givens, to produce new equalities
|
|
| 1686 | -do_one_local locals dict_ct@(DictCt { di_cls = cls, di_ev = wanted_ev })
|
|
| 1687 | - -- locals contains all the Givens and earlier Wanteds
|
|
| 1688 | - = do { (new_eqs, unifs) <- foldrM do_interaction (emptyBag, False) $
|
|
| 1689 | - findDictsByClass locals cls
|
|
| 1690 | - ; return (addDict dict_ct locals, new_eqs, unifs) }
|
|
| 1691 | - where
|
|
| 1692 | - wanted_pred = ctEvPred wanted_ev
|
|
| 1693 | - wanted_loc = ctEvLoc wanted_ev
|
|
| 1694 | - |
|
| 1695 | - do_interaction :: DictCt -> (Cts,Bool) -> TcS (Cts,Bool)
|
|
| 1696 | - do_interaction (DictCt { di_ev = all_ev }) (new_eqs, unifs) -- This can be Given or Wanted
|
|
| 1697 | - = do { traceTcS "doLocalFunDepImprovement" $
|
|
| 1698 | - vcat [ ppr wanted_ev
|
|
| 1699 | - , pprCtLoc wanted_loc, ppr (isGivenLoc wanted_loc)
|
|
| 1700 | - , pprCtLoc all_loc, ppr (isGivenLoc all_loc)
|
|
| 1701 | - , pprCtLoc deriv_loc, ppr (isGivenLoc deriv_loc) ]
|
|
| 1702 | - |
|
| 1703 | - ; (new_eqs1, unifs1) <- unifyFunDepWanteds wanted_ev $
|
|
| 1704 | - improveFromAnother (deriv_loc, all_rewriters)
|
|
| 1705 | - all_pred wanted_pred
|
|
| 1706 | - ; return (new_eqs1 `unionBags` new_eqs, unifs1 || unifs) }
|
|
| 1707 | - where
|
|
| 1708 | - all_pred = ctEvPred all_ev
|
|
| 1709 | - all_loc = ctEvLoc all_ev
|
|
| 1710 | - all_rewriters = ctEvRewriters all_ev
|
|
| 1711 | - deriv_loc = wanted_loc { ctl_depth = deriv_depth
|
|
| 1712 | - , ctl_origin = deriv_origin }
|
|
| 1713 | - deriv_depth = ctl_depth wanted_loc `maxSubGoalDepth`
|
|
| 1714 | - ctl_depth all_loc
|
|
| 1715 | - deriv_origin = FunDepOrigin1 wanted_pred
|
|
| 1716 | - (ctLocOrigin wanted_loc)
|
|
| 1717 | - (ctLocSpan wanted_loc)
|
|
| 1718 | - all_pred
|
|
| 1719 | - (ctLocOrigin all_loc)
|
|
| 1720 | - (ctLocSpan all_loc)
|
|
| 1721 | - |
|
| 1722 | 1379 | |
| 1723 | 1380 | {- *********************************************************************
|
| 1724 | 1381 | * *
|
| ... | ... | @@ -14,6 +14,7 @@ import GHC.Tc.Solver.Irred( solveIrred ) |
| 14 | 14 | import GHC.Tc.Solver.Dict( matchLocalInst, chooseInstance )
|
| 15 | 15 | import GHC.Tc.Solver.Rewrite
|
| 16 | 16 | import GHC.Tc.Solver.Monad
|
| 17 | +import GHC.Tc.Solver.FunDeps( unifyAndEmitFunDepWanteds )
|
|
| 17 | 18 | import GHC.Tc.Solver.InertSet
|
| 18 | 19 | import GHC.Tc.Solver.Types( findFunEqsByTyCon )
|
| 19 | 20 | import GHC.Tc.Types.Evidence
|
| ... | ... | @@ -3108,13 +3109,17 @@ improve_wanted_top_fun_eqs fam_tc lhs_tys rhs_ty |
| 3108 | 3109 | | Just ops <- isBuiltInSynFamTyCon_maybe fam_tc
|
| 3109 | 3110 | = return (map snd $ tryInteractTopFam ops fam_tc lhs_tys rhs_ty)
|
| 3110 | 3111 | |
| 3112 | + -- ToDo: use ideas in #23162 for closed type families; injectivity only for open
|
|
| 3113 | + |
|
| 3111 | 3114 | -- See Note [Type inference for type families with injectivity]
|
| 3115 | + -- Open, so look for inj
|
|
| 3112 | 3116 | | Injective inj_args <- tyConInjectivityInfo fam_tc
|
| 3113 | 3117 | = do { fam_envs <- getFamInstEnvs
|
| 3114 | 3118 | ; top_eqns <- improve_injective_wanted_top fam_envs inj_args fam_tc lhs_tys rhs_ty
|
| 3115 | 3119 | ; let local_eqns = improve_injective_wanted_famfam inj_args fam_tc lhs_tys rhs_ty
|
| 3116 | 3120 | ; traceTcS "improve_wanted_top_fun_eqs" $
|
| 3117 | 3121 | vcat [ ppr fam_tc, text "local_eqns" <+> ppr local_eqns, text "top_eqns" <+> ppr top_eqns ]
|
| 3122 | + -- xxx ToDo: this does both local and top => bug?
|
|
| 3118 | 3123 | ; return (local_eqns ++ top_eqns) }
|
| 3119 | 3124 | |
| 3120 | 3125 | | otherwise -- No injectivity
|
| 1 | +{-# LANGUAGE DuplicateRecordFields #-}
|
|
| 2 | +{-# LANGUAGE MultiWayIf #-}
|
|
| 3 | + |
|
| 4 | +-- | Solving Class constraints CDictCan
|
|
| 5 | +module GHC.Tc.Solver.FunDeps (
|
|
| 6 | + unifyAndEmitFunDepWanteds,
|
|
| 7 | + doDictFunDepImprovement,
|
|
| 8 | + ImprovementResult, noImprovement
|
|
| 9 | + ) where
|
|
| 10 | + |
|
| 11 | +import GHC.Prelude
|
|
| 12 | + |
|
| 13 | +import GHC.Tc.Instance.FunDeps
|
|
| 14 | +import GHC.Tc.Types.Evidence
|
|
| 15 | +import GHC.Tc.Types.Constraint
|
|
| 16 | +import GHC.Tc.Types.CtLoc
|
|
| 17 | +import GHC.Tc.Types.Origin
|
|
| 18 | +import GHC.Tc.Solver.InertSet
|
|
| 19 | +import GHC.Tc.Solver.Monad
|
|
| 20 | +import GHC.Tc.Solver.Types
|
|
| 21 | +import GHC.Tc.Utils.TcType
|
|
| 22 | +import GHC.Tc.Utils.Unify( UnifyEnv(..) )
|
|
| 23 | +import GHC.Tc.Utils.Monad as TcM
|
|
| 24 | + |
|
| 25 | +import GHC.Core.Type
|
|
| 26 | +import GHC.Core.InstEnv ( InstEnvs, ClsInst(..) )
|
|
| 27 | +import GHC.Core.Coercion.Axiom( TypeEqn )
|
|
| 28 | + |
|
| 29 | +import GHC.Types.Name
|
|
| 30 | +import GHC.Types.Var.Set
|
|
| 31 | + |
|
| 32 | +import GHC.Utils.Outputable
|
|
| 33 | + |
|
| 34 | +import GHC.Data.Bag
|
|
| 35 | +import GHC.Data.Pair
|
|
| 36 | + |
|
| 37 | +import qualified Data.Semigroup as S
|
|
| 38 | + |
|
| 39 | +import Control.Monad
|
|
| 40 | + |
|
| 41 | +{- *********************************************************************
|
|
| 42 | +* *
|
|
| 43 | +* Functional dependencies, instantiation of equations
|
|
| 44 | +* *
|
|
| 45 | +************************************************************************
|
|
| 46 | + |
|
| 47 | +When we spot an equality arising from a functional dependency,
|
|
| 48 | +we now use that equality (a "wanted") to rewrite the work-item
|
|
| 49 | +constraint right away. This avoids two dangers
|
|
| 50 | + |
|
| 51 | + Danger 1: If we send the original constraint on down the pipeline
|
|
| 52 | + it may react with an instance declaration, and in delicate
|
|
| 53 | + situations (when a Given overlaps with an instance) that
|
|
| 54 | + may produce new insoluble goals: see #4952
|
|
| 55 | + |
|
| 56 | + Danger 2: If we don't rewrite the constraint, it may re-react
|
|
| 57 | + with the same thing later, and produce the same equality
|
|
| 58 | + again --> termination worries.
|
|
| 59 | + |
|
| 60 | +To achieve this required some refactoring of GHC.Tc.Instance.FunDeps (nicer
|
|
| 61 | +now!).
|
|
| 62 | + |
|
| 63 | +Note [FunDep and implicit parameter reactions]
|
|
| 64 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 65 | +Currently, our story of interacting two dictionaries (or a dictionary
|
|
| 66 | +and top-level instances) for functional dependencies (including implicit
|
|
| 67 | +parameters), is that we simply produce new Wanted equalities. So for example
|
|
| 68 | + |
|
| 69 | + class D a b | a -> b where ...
|
|
| 70 | + Inert:
|
|
| 71 | + [G] d1 : D Int Bool
|
|
| 72 | + WorkItem:
|
|
| 73 | + [W] d2 : D Int alpha
|
|
| 74 | + |
|
| 75 | + We generate the extra work item
|
|
| 76 | + [W] cv : alpha ~ Bool
|
|
| 77 | + where 'cv' is currently unused. However, this new item can perhaps be
|
|
| 78 | + spontaneously solved to become given and react with d2,
|
|
| 79 | + discharging it in favour of a new constraint d2' thus:
|
|
| 80 | + [W] d2' : D Int Bool
|
|
| 81 | + d2 := d2' |> D Int cv
|
|
| 82 | + Now d2' can be discharged from d1
|
|
| 83 | + |
|
| 84 | +We could be more aggressive and try to *immediately* solve the dictionary
|
|
| 85 | +using those extra equalities.
|
|
| 86 | + |
|
| 87 | +If that were the case with the same inert set and work item we might discard
|
|
| 88 | +d2 directly:
|
|
| 89 | + |
|
| 90 | + [W] cv : alpha ~ Bool
|
|
| 91 | + d2 := d1 |> D Int cv
|
|
| 92 | + |
|
| 93 | +But in general it's a bit painful to figure out the necessary coercion,
|
|
| 94 | +so we just take the first approach. Here is a better example. Consider:
|
|
| 95 | + class C a b c | a -> b
|
|
| 96 | +And:
|
|
| 97 | + [G] d1 : C T Int Char
|
|
| 98 | + [W] d2 : C T beta Int
|
|
| 99 | +In this case, it's *not even possible* to solve the wanted immediately.
|
|
| 100 | +So we should simply output the functional dependency and add this guy
|
|
| 101 | +[but NOT its superclasses] back in the worklist. Even worse:
|
|
| 102 | + [G] d1 : C T Int beta
|
|
| 103 | + [W] d2: C T beta Int
|
|
| 104 | +Then it is solvable, but its very hard to detect this on the spot.
|
|
| 105 | + |
|
| 106 | +It's exactly the same with implicit parameters, except that the
|
|
| 107 | +"aggressive" approach would be much easier to implement.
|
|
| 108 | + |
|
| 109 | +Note [Fundeps with instances, and equality orientation]
|
|
| 110 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 111 | +This Note describes a delicate interaction that constrains the orientation of
|
|
| 112 | +equalities. This one is about fundeps, but the /exact/ same thing arises for
|
|
| 113 | +type-family injectivity constraints: see Note [Improvement orientation].
|
|
| 114 | + |
|
| 115 | +doTopFunDepImprovement compares the constraint with all the instance
|
|
| 116 | +declarations, to see if we can produce any equalities. E.g
|
|
| 117 | + class C2 a b | a -> b
|
|
| 118 | + instance C Int Bool
|
|
| 119 | +Then the constraint (C Int ty) generates the equality [W] ty ~ Bool.
|
|
| 120 | + |
|
| 121 | +There is a nasty corner in #19415 which led to the typechecker looping:
|
|
| 122 | + class C s t b | s -> t
|
|
| 123 | + instance ... => C (T kx x) (T ky y) Int
|
|
| 124 | + T :: forall k. k -> Type
|
|
| 125 | + |
|
| 126 | + work_item: dwrk :: C (T @ka (a::ka)) (T @kb0 (b0::kb0)) Char
|
|
| 127 | + where kb0, b0 are unification vars
|
|
| 128 | + |
|
| 129 | + ==> {doTopFunDepImprovement: compare work_item with instance,
|
|
| 130 | + generate /fresh/ unification variables kfresh0, yfresh0,
|
|
| 131 | + emit a new Wanted, and add dwrk to inert set}
|
|
| 132 | + |
|
| 133 | + Suppose we emit this new Wanted from the fundep:
|
|
| 134 | + [W] T kb0 (b0::kb0) ~ T kfresh0 (yfresh0::kfresh0)
|
|
| 135 | + |
|
| 136 | + ==> {solve that equality kb0 := kfresh0, b0 := yfresh0}
|
|
| 137 | + Now kick out dwrk, since it mentions kb0
|
|
| 138 | + But now we are back to the start! Loop!
|
|
| 139 | + |
|
| 140 | +NB1: This example relies on an instance that does not satisfy the
|
|
| 141 | + coverage condition (although it may satisfy the weak coverage
|
|
| 142 | + condition), and hence whose fundeps generate fresh unification
|
|
| 143 | + variables. Not satisfying the coverage condition is known to
|
|
| 144 | + lead to termination trouble, but in this case it's plain silly.
|
|
| 145 | + |
|
| 146 | +NB2: In this example, the third parameter to C ensures that the
|
|
| 147 | + instance doesn't actually match the Wanted, so we can't use it to
|
|
| 148 | + solve the Wanted
|
|
| 149 | + |
|
| 150 | +We solve the problem by (#21703):
|
|
| 151 | + |
|
| 152 | + carefully orienting the new Wanted so that all the
|
|
| 153 | + freshly-generated unification variables are on the LHS.
|
|
| 154 | + |
|
| 155 | + Thus we call unifyWanteds on
|
|
| 156 | + T kfresh0 (yfresh0::kfresh0) ~ T kb0 (b0::kb0)
|
|
| 157 | + and /NOT/
|
|
| 158 | + T kb0 (b0::kb0) ~ T kfresh0 (yfresh0::kfresh0)
|
|
| 159 | + |
|
| 160 | +Now we'll unify kfresh0:=kb0, yfresh0:=b0, and all is well. The general idea
|
|
| 161 | +is that we want to preferentially eliminate those freshly-generated
|
|
| 162 | +unification variables, rather than unifying older variables, which causes
|
|
| 163 | +kick-out etc.
|
|
| 164 | + |
|
| 165 | +Keeping younger variables on the left also gives very minor improvement in
|
|
| 166 | +the compiler performance by having less kick-outs and allocations (-0.1% on
|
|
| 167 | +average). Indeed Historical Note [Eliminate younger unification variables]
|
|
| 168 | +in GHC.Tc.Utils.Unify describes an earlier attempt to do so systematically,
|
|
| 169 | +apparently now in abeyance.
|
|
| 170 | + |
|
| 171 | +But this is is a delicate solution. We must take care to /preserve/
|
|
| 172 | +orientation during solving. Wrinkles:
|
|
| 173 | + |
|
| 174 | +(W1) We start with
|
|
| 175 | + [W] T kfresh0 (yfresh0::kfresh0) ~ T kb0 (b0::kb0)
|
|
| 176 | + Decompose to
|
|
| 177 | + [W] kfresh0 ~ kb0
|
|
| 178 | + [W] (yfresh0::kfresh0) ~ (b0::kb0)
|
|
| 179 | + Preserve orientation when decomposing!!
|
|
| 180 | + |
|
| 181 | +(W2) Suppose we happen to tackle the second Wanted from (W1)
|
|
| 182 | + first. Then in canEqCanLHSHetero we emit a /kind/ equality, as
|
|
| 183 | + well as a now-homogeneous type equality
|
|
| 184 | + [W] kco : kfresh0 ~ kb0
|
|
| 185 | + [W] (yfresh0::kfresh0) ~ (b0::kb0) |> (sym kco)
|
|
| 186 | + Preserve orientation in canEqCanLHSHetero!! (Failing to
|
|
| 187 | + preserve orientation here was the immediate cause of #21703.)
|
|
| 188 | + |
|
| 189 | +(W3) There is a potential interaction with the swapping done by
|
|
| 190 | + GHC.Tc.Utils.Unify.swapOverTyVars. We think it's fine, but it's
|
|
| 191 | + a slight worry. See especially Note [TyVar/TyVar orientation] in
|
|
| 192 | + that module.
|
|
| 193 | + |
|
| 194 | +The trouble is that "preserving orientation" is a rather global invariant,
|
|
| 195 | +and sometimes we definitely do want to swap (e.g. Int ~ alpha), so we don't
|
|
| 196 | +even have a precise statement of what the invariant is. The advantage
|
|
| 197 | +of the preserve-orientation plan is that it is extremely cheap to implement,
|
|
| 198 | +and apparently works beautifully.
|
|
| 199 | + |
|
| 200 | +--- Alternative plan (1) ---
|
|
| 201 | +Rather than have an ill-defined invariant, another possiblity is to
|
|
| 202 | +elminate those fresh unification variables at birth, when generating
|
|
| 203 | +the new fundep-inspired equalities.
|
|
| 204 | + |
|
| 205 | +The key idea is to call `instFlexiX` in `emitFunDepWanteds` on only those
|
|
| 206 | +type variables that are guaranteed to give us some progress. This means we
|
|
| 207 | +have to locally (without calling emitWanteds) identify the type variables
|
|
| 208 | +that do not give us any progress. In the above example, we _know_ that
|
|
| 209 | +emitting the two wanteds `kco` and `co` is fruitless.
|
|
| 210 | + |
|
| 211 | + Q: How do we identify such no-ops?
|
|
| 212 | + |
|
| 213 | + 1. Generate a matching substitution from LHS to RHS
|
|
| 214 | + ɸ = [kb0 :-> k0, b0 :-> y0]
|
|
| 215 | + 2. Call `instFlexiX` on only those type variables that do not appear in the domain of ɸ
|
|
| 216 | + ɸ' = instFlexiX ɸ (tvs - domain ɸ)
|
|
| 217 | + 3. Apply ɸ' on LHS and then call emitWanteds
|
|
| 218 | + unifyWanteds ... (subst ɸ' LHS) RHS
|
|
| 219 | + |
|
| 220 | +Why will this work? The matching substitution ɸ will be a best effort
|
|
| 221 | +substitution that gives us all the easy solutions. It can be generated with
|
|
| 222 | +modified version of `Core/Unify.unify_tys` where we run it in a matching mode
|
|
| 223 | +and never generate `SurelyApart` and always return a `MaybeApart Subst`
|
|
| 224 | +instead.
|
|
| 225 | + |
|
| 226 | +The same alternative plan would work for type-family injectivity constraints:
|
|
| 227 | +see Note [Improvement orientation] in GHC.Tc.Solver.Equality.
|
|
| 228 | +--- End of Alternative plan (1) ---
|
|
| 229 | + |
|
| 230 | +--- Alternative plan (2) ---
|
|
| 231 | +We could have a new flavour of TcTyVar (like `TauTv`, `TyVarTv` etc; see GHC.Tc.Utils.TcType.MetaInfo)
|
|
| 232 | +for the fresh unification variables introduced by functional dependencies. Say `FunDepTv`. Then in
|
|
| 233 | +GHC.Tc.Utils.Unify.swapOverTyVars we could arrange to keep a `FunDepTv` on the left if possible.
|
|
| 234 | +Looks possible, but it's one more complication.
|
|
| 235 | +--- End of Alternative plan (2) ---
|
|
| 236 | + |
|
| 237 | + |
|
| 238 | +--- Historical note: Failed Alternative Plan (3) ---
|
|
| 239 | +Previously we used a flag `cc_fundeps` in `CDictCan`. It would flip to False
|
|
| 240 | +once we used a fun dep to hint the solver to break and to stop emitting more
|
|
| 241 | +wanteds. This solution was not complete, and caused a failures while trying
|
|
| 242 | +to solve for transitive functional dependencies (test case: T21703)
|
|
| 243 | +-- End of Historical note: Failed Alternative Plan (3) --
|
|
| 244 | + |
|
| 245 | +Note [Do fundeps last]
|
|
| 246 | +~~~~~~~~~~~~~~~~~~~~~~
|
|
| 247 | +Consider T4254b:
|
|
| 248 | + class FD a b | a -> b where { op :: a -> b }
|
|
| 249 | + |
|
| 250 | + instance FD Int Bool
|
|
| 251 | + |
|
| 252 | + foo :: forall a b. (a~Int,FD a b) => a -> Bool
|
|
| 253 | + foo = op
|
|
| 254 | + |
|
| 255 | +(DFL1) Try local fundeps first.
|
|
| 256 | + From the ambiguity check on the type signature we get
|
|
| 257 | + [G] FD Int b
|
|
| 258 | + [W] FD Int beta
|
|
| 259 | + If we ineract that Wanted with /both/ the t0p-level instance, /and/ the
|
|
| 260 | + local Given, we'll get
|
|
| 261 | + beta ~ Int and beta ~ b
|
|
| 262 | + respectively. That would generate (b~Bool), which would fai. I think
|
|
| 263 | + it doesn't matter which of the two we pick, but historically we have
|
|
| 264 | + picked teh local-fundeps firs.
|
|
| 265 | + |
|
| 266 | +(DFL2) Try solving from top-level instances before fundeps.
|
|
| 267 | + From the definition `foo = op` we get
|
|
| 268 | + [G] FD Int b
|
|
| 269 | + [W] FD Int Bool
|
|
| 270 | + We solve this from the top level instance before even trying fundeps.
|
|
| 271 | + If we did try fundeps, we'd generate [W] b ~ Bool, which fails.
|
|
| 272 | + |
|
| 273 | + (DFL2) is achieved by trying fundeps only on /unsolved/ Wanteds.
|
|
| 274 | + |
|
| 275 | + |
|
| 276 | +Note [Weird fundeps]
|
|
| 277 | +~~~~~~~~~~~~~~~~~~~~
|
|
| 278 | +Consider class Het a b | a -> b where
|
|
| 279 | + het :: m (f c) -> a -> m b
|
|
| 280 | + |
|
| 281 | + class GHet (a :: * -> *) (b :: * -> *) | a -> b
|
|
| 282 | + instance GHet (K a) (K [a])
|
|
| 283 | + instance Het a b => GHet (K a) (K b)
|
|
| 284 | + |
|
| 285 | +The two instances don't actually conflict on their fundeps,
|
|
| 286 | +although it's pretty strange. So they are both accepted. Now
|
|
| 287 | +try [W] GHet (K Int) (K Bool)
|
|
| 288 | +This triggers fundeps from both instance decls;
|
|
| 289 | + [W] K Bool ~ K [a]
|
|
| 290 | + [W] K Bool ~ K beta
|
|
| 291 | +And there's a risk of complaining about Bool ~ [a]. But in fact
|
|
| 292 | +the Wanted matches the second instance, so we never get as far
|
|
| 293 | +as the fundeps.
|
|
| 294 | + |
|
| 295 | +#7875 is a case in point.
|
|
| 296 | +-}
|
|
| 297 | + |
|
| 298 | +doDictFunDepImprovement :: Cts -> TcS ImprovementResult
|
|
| 299 | +-- (doDictFunDepImprovement inst_envs cts)
|
|
| 300 | +-- * Generate the fundeps from interacting the
|
|
| 301 | +-- top-level `inst_envs` with the constraints `cts`
|
|
| 302 | +-- * Do the unifications and return any unsolved constraints
|
|
| 303 | +-- See Note [Fundeps with instances, and equality orientation]
|
|
| 304 | +-- foldrM :: (Foldable t, Monad m) => (a -> b -> m b) -> b -> t a -> m b
|
|
| 305 | +doDictFunDepImprovement unsolved_wanteds
|
|
| 306 | + = do { inerts <- getInertCans -- The inert_dicts are all Givens
|
|
| 307 | + ; inst_envs <- getInstEnvs
|
|
| 308 | + ; (_, imp_res) <- foldM (do_one_dict inst_envs)
|
|
| 309 | + (inert_dicts inerts, noopImprovement)
|
|
| 310 | + unsolved_wanteds
|
|
| 311 | + ; return imp_res }
|
|
| 312 | + |
|
| 313 | +do_one_dict :: InstEnvs
|
|
| 314 | + -> (DictMap DictCt, ImprovementResult)
|
|
| 315 | + -> Ct
|
|
| 316 | + -> TcS (DictMap DictCt, ImprovementResult)
|
|
| 317 | +-- The `local_dicts` accumulator starts life as just the Givens, but
|
|
| 318 | +-- as we encounter each Wanted we augment it. Result: each Wanted
|
|
| 319 | +-- is interacted with all the Givens, and all prededing Wanteds.
|
|
| 320 | +-- This is worst-case quadratic because we have to compare each
|
|
| 321 | +-- constraint with all the others, to find all the pairwise interactions
|
|
| 322 | +do_one_dict inst_envs (local_dicts, imp_res) (CDictCan dict_ct)
|
|
| 323 | + = do { (local_dicts1, imp_res1) <- do_one_local local_dicts dict_ct
|
|
| 324 | + ; if noImprovement imp_res1
|
|
| 325 | + then do { imp_res2 <- do_one_top inst_envs dict_ct
|
|
| 326 | + ; return (local_dicts1, imp_res `plusImprovements` imp_res2) }
|
|
| 327 | + else return (local_dicts1, imp_res `plusImprovements` imp_res1) }
|
|
| 328 | + |
|
| 329 | +do_one_dict _ acc _ -- Non-DictCt constraints
|
|
| 330 | + = return acc
|
|
| 331 | + |
|
| 332 | +do_one_top :: InstEnvs -> DictCt -> TcS ImprovementResult
|
|
| 333 | +do_one_top inst_envs (DictCt { di_ev = ev, di_cls = cls, di_tys = xis })
|
|
| 334 | + = unifyFunDepWanteds ev eqns
|
|
| 335 | + where
|
|
| 336 | + eqns :: [FunDepEqn (CtLoc, RewriterSet)]
|
|
| 337 | + eqns = improveFromInstEnv inst_envs mk_ct_loc cls xis
|
|
| 338 | + |
|
| 339 | + dict_pred = mkClassPred cls xis
|
|
| 340 | + dict_loc = ctEvLoc ev
|
|
| 341 | + dict_origin = ctLocOrigin dict_loc
|
|
| 342 | + dict_rewriters = ctEvRewriters ev
|
|
| 343 | + |
|
| 344 | + mk_ct_loc :: ClsInst -- The instance decl
|
|
| 345 | + -> (CtLoc, RewriterSet)
|
|
| 346 | + mk_ct_loc ispec
|
|
| 347 | + = (dict_loc { ctl_origin = new_orig }, dict_rewriters)
|
|
| 348 | + where
|
|
| 349 | + inst_pred = mkClassPred cls (is_tys ispec)
|
|
| 350 | + inst_loc = getSrcSpan (is_dfun ispec)
|
|
| 351 | + new_orig = FunDepOrigin2 dict_pred dict_origin
|
|
| 352 | + inst_pred inst_loc
|
|
| 353 | + |
|
| 354 | +do_one_local :: DictMap DictCt -> DictCt -> TcS (DictMap DictCt, ImprovementResult)
|
|
| 355 | +-- Using functional dependencies, interact the unsolved Wanteds
|
|
| 356 | +-- against each other and the inert Givens, to produce new equalities
|
|
| 357 | +do_one_local locals dict_ct@(DictCt { di_cls = cls, di_ev = wanted_ev })
|
|
| 358 | + -- locals contains all the Givens and earlier Wanteds
|
|
| 359 | + = do { imp_res <- foldM do_interaction noopImprovement $
|
|
| 360 | + findDictsByClass locals cls
|
|
| 361 | + ; return (addDict dict_ct locals, imp_res) }
|
|
| 362 | + where
|
|
| 363 | + wanted_pred = ctEvPred wanted_ev
|
|
| 364 | + wanted_loc = ctEvLoc wanted_ev
|
|
| 365 | + |
|
| 366 | + do_interaction :: (Cts,Bool) -> DictCt -> TcS (Cts,Bool)
|
|
| 367 | + do_interaction (new_eqs, unifs) (DictCt { di_ev = all_ev }) -- This can be Given or Wanted
|
|
| 368 | + = do { traceTcS "doLocalFunDepImprovement" $
|
|
| 369 | + vcat [ ppr wanted_ev
|
|
| 370 | + , pprCtLoc wanted_loc, ppr (isGivenLoc wanted_loc)
|
|
| 371 | + , pprCtLoc all_loc, ppr (isGivenLoc all_loc)
|
|
| 372 | + , pprCtLoc deriv_loc, ppr (isGivenLoc deriv_loc) ]
|
|
| 373 | + |
|
| 374 | + ; (new_eqs1, unifs1) <- unifyFunDepWanteds wanted_ev $
|
|
| 375 | + improveFromAnother (deriv_loc, all_rewriters)
|
|
| 376 | + all_pred wanted_pred
|
|
| 377 | + ; return (new_eqs1 `unionBags` new_eqs, unifs1 || unifs) }
|
|
| 378 | + where
|
|
| 379 | + all_pred = ctEvPred all_ev
|
|
| 380 | + all_loc = ctEvLoc all_ev
|
|
| 381 | + all_rewriters = ctEvRewriters all_ev
|
|
| 382 | + deriv_loc = wanted_loc { ctl_depth = deriv_depth
|
|
| 383 | + , ctl_origin = deriv_origin }
|
|
| 384 | + deriv_depth = ctl_depth wanted_loc `maxSubGoalDepth`
|
|
| 385 | + ctl_depth all_loc
|
|
| 386 | + deriv_origin = FunDepOrigin1 wanted_pred
|
|
| 387 | + (ctLocOrigin wanted_loc)
|
|
| 388 | + (ctLocSpan wanted_loc)
|
|
| 389 | + all_pred
|
|
| 390 | + (ctLocOrigin all_loc)
|
|
| 391 | + (ctLocSpan all_loc)
|
|
| 392 | + |
|
| 393 | + |
|
| 394 | +{-
|
|
| 395 | +************************************************************************
|
|
| 396 | +* *
|
|
| 397 | + Emitting equalities arising from fundeps
|
|
| 398 | +* *
|
|
| 399 | +************************************************************************
|
|
| 400 | +-}
|
|
| 401 | + |
|
| 402 | +type ImprovementResult = (Cts, Bool)
|
|
| 403 | + -- The Cts are the new equality constraints
|
|
| 404 | + -- The Bool is True if we unified any meta-ty-vars on when
|
|
| 405 | + -- generating those new equality constraints
|
|
| 406 | + |
|
| 407 | +noopImprovement :: ImprovementResult
|
|
| 408 | +noopImprovement = (emptyBag, False)
|
|
| 409 | + |
|
| 410 | +noImprovement :: ImprovementResult -> Bool
|
|
| 411 | +noImprovement (cts,unifs) = not unifs && isEmptyBag cts
|
|
| 412 | + |
|
| 413 | +plusImprovements :: ImprovementResult -> ImprovementResult -> ImprovementResult
|
|
| 414 | +plusImprovements (cts1,unif1) (cts2,unif2)
|
|
| 415 | + = (cts1 `unionBags` cts2, unif1 || unif2)
|
|
| 416 | + |
|
| 417 | + |
|
| 418 | +unifyAndEmitFunDepWanteds :: CtEvidence -- The work item
|
|
| 419 | + -> [FunDepEqn (CtLoc, RewriterSet)]
|
|
| 420 | + -> TcS Bool -- True <=> some unification happened
|
|
| 421 | +unifyAndEmitFunDepWanteds ev fd_eqns
|
|
| 422 | + = do { (new_eqs, unifs) <- unifyFunDepWanteds ev fd_eqns
|
|
| 423 | + |
|
| 424 | + ; -- Emit the deferred constraints
|
|
| 425 | + -- See Note [Work-list ordering] in GHC.Tc.Solved.Equality
|
|
| 426 | + --
|
|
| 427 | + -- All the constraints in `cts` share the same rewriter set so,
|
|
| 428 | + -- rather than looking at it one by one, we pass it to
|
|
| 429 | + -- extendWorkListChildEqs; just a small optimisation.
|
|
| 430 | + ; unless (isEmptyBag new_eqs) $
|
|
| 431 | + updWorkListTcS (extendWorkListChildEqs ev new_eqs)
|
|
| 432 | + |
|
| 433 | + ; return unifs }
|
|
| 434 | + |
|
| 435 | +unifyFunDepWanteds :: CtEvidence -- The work item
|
|
| 436 | + -> [FunDepEqn (CtLoc, RewriterSet)]
|
|
| 437 | + -> TcS ImprovementResult
|
|
| 438 | + |
|
| 439 | +unifyFunDepWanteds _ [] = return noopImprovement -- common case noop
|
|
| 440 | +-- See Note [FunDep and implicit parameter reactions]
|
|
| 441 | + |
|
| 442 | +unifyFunDepWanteds ev fd_eqns
|
|
| 443 | + = do { (fresh_tvs_s, cts, unified_tvs) <- wrapUnifierX ev Nominal do_fundeps
|
|
| 444 | + |
|
| 445 | + -- Figure out if a "real" unification happened: See Note [unifyFunDeps]
|
|
| 446 | + ; let unif_happened = any is_old_tv unified_tvs
|
|
| 447 | + fresh_tvs = mkVarSet (concat fresh_tvs_s)
|
|
| 448 | + is_old_tv tv = not (tv `elemVarSet` fresh_tvs)
|
|
| 449 | + |
|
| 450 | + ; return (cts, unif_happened) }
|
|
| 451 | + where
|
|
| 452 | + do_fundeps :: UnifyEnv -> TcM [[TcTyVar]]
|
|
| 453 | + do_fundeps env = mapM (do_one env) fd_eqns
|
|
| 454 | + |
|
| 455 | + do_one :: UnifyEnv -> FunDepEqn (CtLoc, RewriterSet) -> TcM [TcTyVar]
|
|
| 456 | + do_one uenv (FDEqn { fd_qtvs = tvs, fd_eqs = eqs, fd_loc = (loc, rewriters) })
|
|
| 457 | + = do { (fresh_tvs, eqs') <- instantiateFunDepEqn tvs (reverse eqs)
|
|
| 458 | + -- (reverse eqs): See Note [Reverse order of fundep equations]
|
|
| 459 | + ; uPairsTcM env_one eqs'
|
|
| 460 | + ; return fresh_tvs }
|
|
| 461 | + where
|
|
| 462 | + env_one = uenv { u_rewriters = u_rewriters uenv S.<> rewriters
|
|
| 463 | + , u_loc = loc }
|
|
| 464 | + |
|
| 465 | +instantiateFunDepEqn :: [TyVar] -> [TypeEqn] -> TcM ([TcTyVar], [TypeEqn])
|
|
| 466 | +instantiateFunDepEqn tvs eqs
|
|
| 467 | + | null tvs
|
|
| 468 | + = return ([], eqs)
|
|
| 469 | + | otherwise
|
|
| 470 | + = do { TcM.traceTc "emitFunDepWanteds 2" (ppr tvs $$ ppr eqs)
|
|
| 471 | + ; (tvs', subst) <- instFlexiXTcM emptySubst tvs -- Takes account of kind substitution
|
|
| 472 | + ; return (tvs', map (subst_pair subst) eqs) }
|
|
| 473 | + where
|
|
| 474 | + subst_pair subst (Pair ty1 ty2)
|
|
| 475 | + = Pair (substTyUnchecked subst' ty1) ty2
|
|
| 476 | + -- ty2 does not mention fd_qtvs, so no need to subst it.
|
|
| 477 | + -- See GHC.Tc.Instance.Fundeps Note [Improving against instances]
|
|
| 478 | + -- Wrinkle (1)
|
|
| 479 | + where
|
|
| 480 | + subst' = extendSubstInScopeSet subst (tyCoVarsOfType ty1)
|
|
| 481 | + -- The free vars of ty1 aren't just fd_qtvs: ty1 is the result
|
|
| 482 | + -- of matching with the [W] constraint. So we add its free
|
|
| 483 | + -- vars to InScopeSet, to satisfy substTy's invariants, even
|
|
| 484 | + -- though ty1 will never (currently) be a poytype, so this
|
|
| 485 | + -- InScopeSet will never be looked at.
|
|
| 486 | + |
| ... | ... | @@ -105,10 +105,9 @@ module GHC.Tc.Solver.Monad ( |
| 105 | 105 | |
| 106 | 106 | -- Unification
|
| 107 | 107 | wrapUnifierX, wrapUnifierTcS, unifyFunDeps, uPairsTcM, unifyForAllBody,
|
| 108 | - unifyFunDepWanteds, unifyAndEmitFunDepWanteds,
|
|
| 109 | 108 | |
| 110 | 109 | -- MetaTyVars
|
| 111 | - newFlexiTcSTy, instFlexiX,
|
|
| 110 | + newFlexiTcSTy, instFlexiX, instFlexiXTcM,
|
|
| 112 | 111 | cloneMetaTyVar,
|
| 113 | 112 | tcInstSkolTyVarsX,
|
| 114 | 113 | |
| ... | ... | @@ -129,8 +128,7 @@ module GHC.Tc.Solver.Monad ( |
| 129 | 128 | pprEq,
|
| 130 | 129 | |
| 131 | 130 | -- Enforcing invariants for type equalities
|
| 132 | - checkTypeEq,
|
|
| 133 | - instantiateFunDepEqn
|
|
| 131 | + checkTypeEq
|
|
| 134 | 132 | ) where
|
| 135 | 133 | |
| 136 | 134 | import GHC.Prelude
|
| ... | ... | @@ -2235,83 +2233,6 @@ solverDepthError loc ty |
| 2235 | 2233 | where
|
| 2236 | 2234 | depth = ctLocDepth loc
|
| 2237 | 2235 | |
| 2238 | -{-
|
|
| 2239 | -************************************************************************
|
|
| 2240 | -* *
|
|
| 2241 | - Emitting equalities arising from fundeps
|
|
| 2242 | -* *
|
|
| 2243 | -************************************************************************
|
|
| 2244 | --}
|
|
| 2245 | - |
|
| 2246 | -unifyAndEmitFunDepWanteds :: CtEvidence -- The work item
|
|
| 2247 | - -> [FunDepEqn (CtLoc, RewriterSet)]
|
|
| 2248 | - -> TcS Bool -- True <=> some unification happened
|
|
| 2249 | -unifyAndEmitFunDepWanteds ev fd_eqns
|
|
| 2250 | - = do { (new_eqs, unifs) <- unifyFunDepWanteds ev fd_eqns
|
|
| 2251 | - |
|
| 2252 | - ; -- Emit the deferred constraints
|
|
| 2253 | - -- See Note [Work-list ordering] in GHC.Tc.Solved.Equality
|
|
| 2254 | - --
|
|
| 2255 | - -- All the constraints in `cts` share the same rewriter set so,
|
|
| 2256 | - -- rather than looking at it one by one, we pass it to
|
|
| 2257 | - -- extendWorkListChildEqs; just a small optimisation.
|
|
| 2258 | - ; unless (isEmptyBag new_eqs) $
|
|
| 2259 | - updWorkListTcS (extendWorkListChildEqs ev new_eqs)
|
|
| 2260 | - |
|
| 2261 | - ; return unifs }
|
|
| 2262 | - |
|
| 2263 | -unifyFunDepWanteds :: CtEvidence -- The work item
|
|
| 2264 | - -> [FunDepEqn (CtLoc, RewriterSet)]
|
|
| 2265 | - -> TcS (Cts, Bool) -- True <=> some unification happened
|
|
| 2266 | - |
|
| 2267 | -unifyFunDepWanteds _ [] = return (emptyBag, False) -- common case noop
|
|
| 2268 | --- See Note [FunDep and implicit parameter reactions]
|
|
| 2269 | - |
|
| 2270 | -unifyFunDepWanteds ev fd_eqns
|
|
| 2271 | - = do { (fresh_tvs_s, cts, unified_tvs) <- wrapUnifierX ev Nominal do_fundeps
|
|
| 2272 | - |
|
| 2273 | - -- Figure out if a "real" unification happened: See Note [unifyFunDeps]
|
|
| 2274 | - ; let unif_happened = any is_old_tv unified_tvs
|
|
| 2275 | - fresh_tvs = mkVarSet (concat fresh_tvs_s)
|
|
| 2276 | - is_old_tv tv = not (tv `elemVarSet` fresh_tvs)
|
|
| 2277 | - |
|
| 2278 | - ; return (cts, unif_happened) }
|
|
| 2279 | - where
|
|
| 2280 | - do_fundeps :: UnifyEnv -> TcM [[TcTyVar]]
|
|
| 2281 | - do_fundeps env = mapM (do_one env) fd_eqns
|
|
| 2282 | - |
|
| 2283 | - do_one :: UnifyEnv -> FunDepEqn (CtLoc, RewriterSet) -> TcM [TcTyVar]
|
|
| 2284 | - do_one uenv (FDEqn { fd_qtvs = tvs, fd_eqs = eqs, fd_loc = (loc, rewriters) })
|
|
| 2285 | - = do { (fresh_tvs, eqs') <- instantiateFunDepEqn tvs (reverse eqs)
|
|
| 2286 | - -- (reverse eqs): See Note [Reverse order of fundep equations]
|
|
| 2287 | - ; uPairsTcM env_one eqs'
|
|
| 2288 | - ; return fresh_tvs }
|
|
| 2289 | - where
|
|
| 2290 | - env_one = uenv { u_rewriters = u_rewriters uenv S.<> rewriters
|
|
| 2291 | - , u_loc = loc }
|
|
| 2292 | - |
|
| 2293 | -instantiateFunDepEqn :: [TyVar] -> [TypeEqn] -> TcM ([TcTyVar], [TypeEqn])
|
|
| 2294 | -instantiateFunDepEqn tvs eqs
|
|
| 2295 | - | null tvs
|
|
| 2296 | - = return ([], eqs)
|
|
| 2297 | - | otherwise
|
|
| 2298 | - = do { TcM.traceTc "emitFunDepWanteds 2" (ppr tvs $$ ppr eqs)
|
|
| 2299 | - ; (tvs', subst) <- instFlexiXTcM emptySubst tvs -- Takes account of kind substitution
|
|
| 2300 | - ; return (tvs', map (subst_pair subst) eqs) }
|
|
| 2301 | - where
|
|
| 2302 | - subst_pair subst (Pair ty1 ty2)
|
|
| 2303 | - = Pair (substTyUnchecked subst' ty1) ty2
|
|
| 2304 | - -- ty2 does not mention fd_qtvs, so no need to subst it.
|
|
| 2305 | - -- See GHC.Tc.Instance.Fundeps Note [Improving against instances]
|
|
| 2306 | - -- Wrinkle (1)
|
|
| 2307 | - where
|
|
| 2308 | - subst' = extendSubstInScopeSet subst (tyCoVarsOfType ty1)
|
|
| 2309 | - -- The free vars of ty1 aren't just fd_qtvs: ty1 is the result
|
|
| 2310 | - -- of matching with the [W] constraint. So we add its free
|
|
| 2311 | - -- vars to InScopeSet, to satisfy substTy's invariants, even
|
|
| 2312 | - -- though ty1 will never (currently) be a poytype, so this
|
|
| 2313 | - -- InScopeSet will never be looked at.
|
|
| 2314 | - |
|
| 2315 | 2236 | {-
|
| 2316 | 2237 | ************************************************************************
|
| 2317 | 2238 | * *
|
| ... | ... | @@ -15,6 +15,7 @@ module GHC.Tc.Solver.Solve ( |
| 15 | 15 | import GHC.Prelude
|
| 16 | 16 | |
| 17 | 17 | import GHC.Tc.Solver.Dict
|
| 18 | +import GHC.Tc.Solver.FunDeps( doDictFunDepImprovement )
|
|
| 18 | 19 | import GHC.Tc.Solver.Equality( solveEquality )
|
| 19 | 20 | import GHC.Tc.Solver.Irred( solveIrred )
|
| 20 | 21 | import GHC.Tc.Solver.Rewrite( rewrite, rewriteType )
|
| ... | ... | @@ -119,13 +120,13 @@ simplify_loop n limit definitely_redo_implications |
| 119 | 120 | , int (lengthBag simples) <+> text "simples to solve" ])
|
| 120 | 121 | ; traceTcS "simplify_loop: wc =" (ppr wc)
|
| 121 | 122 | |
| 122 | - ; (unifs1, wc1) <- reportUnifications $ -- See Note [Superclass iteration]
|
|
| 123 | - solveSimpleWanteds simples
|
|
| 123 | + ; (n_unifs, wc1) <- reportUnifications $ -- See Note [Superclass iteration]
|
|
| 124 | + solveSimpleWanteds simples
|
|
| 124 | 125 | -- Any insoluble constraints are in 'simples' and so get rewritten
|
| 125 | 126 | -- See Note [Rewrite insolubles] in GHC.Tc.Solver.InertSet
|
| 126 | 127 | |
| 127 | 128 | ; wc2 <- if not definitely_redo_implications -- See Note [Superclass iteration]
|
| 128 | - && unifs1 == 0 -- for this conditional
|
|
| 129 | + && n_unifs == 0 -- for this conditional
|
|
| 129 | 130 | && isEmptyBag (wc_impl wc1)
|
| 130 | 131 | then return (wc { wc_simple = wc_simple wc1 }) -- Short cut
|
| 131 | 132 | else do { implics2 <- solveNestedImplications $
|
| ... | ... | @@ -207,10 +208,19 @@ maybe_simplify_again n limit unif_happened wc@(WC { wc_simple = simples }) |
| 207 | 208 | |
| 208 | 209 | try_fundeps :: TcS (Maybe NextAction)
|
| 209 | 210 | try_fundeps
|
| 210 | - = do { (new_eqs, unifs) <- doDictFunDepImprovement simples
|
|
| 211 | - ; if null new_eqs && not unifs
|
|
| 211 | + = do { (new_eqs, unifs1) <- doDictFunDepImprovement simples
|
|
| 212 | + ; if null new_eqs && not unifs1
|
|
| 212 | 213 | then return Nothing
|
| 213 | - else return (Just (NA_TryAgain (wc `addSimples` new_eqs) unifs)) }
|
|
| 214 | + else
|
|
| 215 | + -- We solve new_eqs immediately, hoping to get some unifications
|
|
| 216 | + -- If instead we just added them to `wc` we'll iterate and (in case when
|
|
| 217 | + -- that doesn't solve it) we'll add the same constraint again... loop!
|
|
| 218 | + do { traceTcS "try_fundeps" (ppr unifs1 $$ ppr new_eqs)
|
|
| 219 | + ; (n_unifs2, _wc) <- reportUnifications $
|
|
| 220 | + solveSimpleWanteds new_eqs
|
|
| 221 | + ; if (unifs1 || n_unifs2 > 0)
|
|
| 222 | + then return (Just (NA_TryAgain wc True))
|
|
| 223 | + else return Nothing } }
|
|
| 214 | 224 | |
| 215 | 225 | {- Note [Superclass iteration]
|
| 216 | 226 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -854,6 +854,7 @@ Library |
| 854 | 854 | GHC.Tc.Solver.Irred
|
| 855 | 855 | GHC.Tc.Solver.Equality
|
| 856 | 856 | GHC.Tc.Solver.Dict
|
| 857 | + GHC.Tc.Solver.FunDeps
|
|
| 857 | 858 | GHC.Tc.Solver.Monad
|
| 858 | 859 | GHC.Tc.Solver.Types
|
| 859 | 860 | GHC.Tc.TyCl
|