Simon Peyton Jones pushed to branch wip/T23162-spj at Glasgow Haskell Compiler / GHC

Commits:

4 changed files:

Changes:

  • compiler/GHC/Tc/Solver/Dict.hs
    ... ... @@ -10,7 +10,7 @@ module GHC.Tc.Solver.Dict (
    10 10
       solveCallStack,    -- For GHC.Tc.Solver
    
    11 11
     
    
    12 12
       -- * Functional dependencies
    
    13
    -  generateTopFunDeps
    
    13
    +  doTopFunDepImprovement, doLocalFunDepImprovement
    
    14 14
       ) where
    
    15 15
     
    
    16 16
     import GHC.Prelude
    
    ... ... @@ -95,7 +95,7 @@ solveDict dict_ct@(DictCt { di_ev = ev, di_cls = cls, di_tys = tys })
    95 95
     
    
    96 96
            -- Try fundeps /after/ tryInstances:
    
    97 97
            --     see (DFL2) in Note [Do fundeps last]
    
    98
    -       ; doLocalFunDepImprovement dict_ct
    
    98
    +--       ; doLocalFunDepImprovement dict_ct
    
    99 99
                -- doLocalFunDepImprovement does StartAgain if there
    
    100 100
                -- are any fundeps: see (DFL1) in Note [Do fundeps last]
    
    101 101
     
    
    ... ... @@ -1434,7 +1434,7 @@ But in general it's a bit painful to figure out the necessary coercion,
    1434 1434
     so we just take the first approach. Here is a better example. Consider:
    
    1435 1435
         class C a b c | a -> b
    
    1436 1436
     And:
    
    1437
    -     [G]  d1 : C T Int Char
    
    1437
    +     [G] d1 : C T Int Char
    
    1438 1438
          [W] d2 : C T beta Int
    
    1439 1439
     In this case, it's *not even possible* to solve the wanted immediately.
    
    1440 1440
     So we should simply output the functional dependency and add this guy
    
    ... ... @@ -1630,16 +1630,23 @@ as the fundeps.
    1630 1630
     #7875 is a case in point.
    
    1631 1631
     -}
    
    1632 1632
     
    
    1633
    -generateTopFunDeps :: InstEnvs -> Cts -> [FunDepEqn (CtLoc, RewriterSet)]
    
    1633
    +doTopFunDepImprovement :: Bag DictCt -> TcS (Cts, Bool)
    
    1634
    +-- (doFunDeps inst_envs cts)
    
    1635
    +--   * Generate the fundeps from interacting the
    
    1636
    +--     top-level `inst_envs` with the constraints `cts`
    
    1637
    +--   * Do the unifications and return any unsolved constraints
    
    1634 1638
     -- See Note [Fundeps with instances, and equality orientation]
    
    1635
    -generateTopFunDeps inst_evs cts
    
    1636
    -  = foldMap do_top cts -- "RAE" `unionBags` interactions
    
    1639
    +doTopFunDepImprovement cts
    
    1640
    +  = do { inst_envs <- getInstEnvs
    
    1641
    +       ; do_dict_fundeps (do_one inst_envs) cts }
    
    1637 1642
       where
    
    1638
    -    do_top :: Ct -> [FunDepEqn (CtLoc, RewriterSet)]
    
    1639
    -    do_top (CDictCan (DictCt { di_ev = ev, di_cls = cls, di_tys = xis }))
    
    1640
    -      = assert (not (isGiven ev)) $
    
    1641
    -        improveFromInstEnv inst_evs mk_ct_loc cls xis
    
    1643
    +    do_one :: InstEnvs -> DictCt -> TcS (Cts, Bool)
    
    1644
    +    do_one inst_envs (DictCt { di_ev = ev, di_cls = cls, di_tys = xis })
    
    1645
    +      = unifyFunDepWanteds ev eqns
    
    1642 1646
           where
    
    1647
    +        eqns :: [FunDepEqn (CtLoc, RewriterSet)]
    
    1648
    +        eqns = improveFromInstEnv inst_envs mk_ct_loc cls xis
    
    1649
    +
    
    1643 1650
             dict_pred      = mkClassPred cls xis
    
    1644 1651
             dict_loc       = ctEvLoc ev
    
    1645 1652
             dict_origin    = ctLocOrigin dict_loc
    
    ... ... @@ -1655,93 +1662,57 @@ generateTopFunDeps inst_evs cts
    1655 1662
                 new_orig  = FunDepOrigin2 dict_pred dict_origin
    
    1656 1663
                                           inst_pred inst_loc
    
    1657 1664
     
    
    1658
    -    do_top _other = []
    
    1659
    -
    
    1660
    -
    
    1661
    -doLocalFunDepImprovement :: DictCt -> SolverStage ()
    
    1662
    --- Add wanted constraints from type-class functional dependencies.
    
    1663
    -doLocalFunDepImprovement dict_ct@(DictCt { di_ev = work_ev, di_cls = cls })
    
    1664
    -  = Stage $
    
    1665
    -    do { inerts <- getInertCans
    
    1666
    -       ; imp <- foldlM add_fds False (findDictsByClass (inert_dicts inerts) cls)
    
    1667
    -       ; if imp then startAgainWith (CDictCan dict_ct)
    
    1668
    -                     else continueWith () }
    
    1665
    +doLocalFunDepImprovement :: Bag DictCt -> TcS (Cts,Bool)
    
    1666
    +-- Add wanted constraints from type-class functional dependencies
    
    1667
    +-- against Givens
    
    1668
    +doLocalFunDepImprovement cts
    
    1669
    +  = do { inerts <- getInertCans  -- The inert_dicts are all Givens
    
    1670
    +       ; do_dict_fundeps (do_one (inert_dicts inerts)) cts }
    
    1669 1671
       where
    
    1670
    -    work_pred = ctEvPred work_ev
    
    1671
    -    work_loc  = ctEvLoc work_ev
    
    1672
    -
    
    1673
    -    add_fds :: Bool -> DictCt -> TcS Bool
    
    1674
    -    add_fds so_far (DictCt { di_ev = inert_ev })
    
    1675
    -      | isGiven work_ev && isGiven inert_ev
    
    1676
    -        -- Do not create FDs from Given/Given interactions: See Note [No Given/Given fundeps]
    
    1677
    -      = return so_far
    
    1678
    -      | otherwise
    
    1679
    -      = do { traceTcS "doLocalFunDepImprovement" (vcat
    
    1680
    -                [ ppr work_ev
    
    1681
    -                , pprCtLoc work_loc, ppr (isGivenLoc work_loc)
    
    1682
    -                , pprCtLoc inert_loc, ppr (isGivenLoc inert_loc)
    
    1683
    -                , pprCtLoc derived_loc, ppr (isGivenLoc derived_loc) ])
    
    1684
    -
    
    1685
    -           ; (new_eqs, unifs)
    
    1686
    -                 <- unifyFunDepWanteds work_ev $
    
    1687
    -                    improveFromAnother (derived_loc, inert_rewriters)
    
    1688
    -                                       inert_pred work_pred
    
    1689
    -
    
    1690
    -           -- Emit the deferred constraints
    
    1691
    -           -- See Note [Work-list ordering] in GHC.Tc.Solved.Equality
    
    1692
    -           --
    
    1693
    -           -- All the constraints in `cts` share the same rewriter set so,
    
    1694
    -           -- rather than looking at it one by one, we pass it to
    
    1695
    -           -- extendWorkListChildEqs; just a small optimisation.
    
    1696
    -           ; unless (isEmptyBag cts) $
    
    1697
    -             updWorkListTcS (extendWorkListChildEqs ev new_eqs)
    
    1698
    -
    
    1699
    -           ; return (so_far || unifs)
    
    1700
    -        }
    
    1672
    +    do_one givens (DictCt { di_cls = cls, di_ev = wanted_ev })
    
    1673
    +      = do_dict_fundeps do_one_given (findDictsByClass givens cls)
    
    1701 1674
           where
    
    1702
    -        inert_pred = ctEvPred inert_ev
    
    1703
    -        inert_loc  = ctEvLoc inert_ev
    
    1704
    -        inert_rewriters = ctEvRewriters inert_ev
    
    1705
    -        derived_loc = work_loc { ctl_depth  = ctl_depth work_loc `maxSubGoalDepth`
    
    1706
    -                                              ctl_depth inert_loc
    
    1707
    -                               , ctl_origin = FunDepOrigin1 work_pred
    
    1708
    -                                                            (ctLocOrigin work_loc)
    
    1709
    -                                                            (ctLocSpan work_loc)
    
    1710
    -                                                            inert_pred
    
    1711
    -                                                            (ctLocOrigin inert_loc)
    
    1712
    -                                                            (ctLocSpan inert_loc) }
    
    1713
    -
    
    1714
    -doTopFunDepImprovement :: DictCt -> SolverStage ()
    
    1715
    --- Try to functional-dependency improvement between the constraint
    
    1716
    --- and the top-level instance declarations
    
    1717
    --- See Note [Fundeps with instances, and equality orientation]
    
    1718
    --- See also Note [Weird fundeps]
    
    1719
    -doTopFunDepImprovement dict_ct@(DictCt { di_ev = ev, di_cls = cls, di_tys = xis })
    
    1720
    -  | isGiven ev     -- No improvement for Givens
    
    1721
    -  = Stage $ continueWith ()
    
    1722
    -  | otherwise
    
    1723
    -  = Stage $
    
    1724
    -    do { traceTcS "try_fundeps" (ppr dict_ct)
    
    1725
    -       ; instEnvs <- getInstEnvs
    
    1726
    -       ; let fundep_eqns = improveFromInstEnv instEnvs mk_ct_loc cls xis
    
    1727
    -       ; imp <- emitFunDepWanteds ev fundep_eqns
    
    1728
    -       ; if imp then startAgainWith (CDictCan dict_ct)
    
    1729
    -                     else continueWith () }
    
    1675
    +        wanted_pred = ctEvPred wanted_ev
    
    1676
    +        wanted_loc  = ctEvLoc  wanted_ev
    
    1677
    +
    
    1678
    +        do_one_given :: DictCt -> TcS (Cts,Bool)
    
    1679
    +        do_one_given (DictCt { di_ev = given_ev })
    
    1680
    +          = do { traceTcS "doLocalFunDepImprovement" $
    
    1681
    +                 vcat [ ppr wanted_ev
    
    1682
    +                      , pprCtLoc wanted_loc, ppr (isGivenLoc wanted_loc)
    
    1683
    +                      , pprCtLoc given_loc, ppr (isGivenLoc given_loc)
    
    1684
    +                      , pprCtLoc deriv_loc, ppr (isGivenLoc deriv_loc) ]
    
    1685
    +
    
    1686
    +               ; unifyFunDepWanteds wanted_ev $
    
    1687
    +                 improveFromAnother (deriv_loc, given_rewriters)
    
    1688
    +                                    given_pred wanted_pred }
    
    1689
    +          where
    
    1690
    +            given_pred  = ctEvPred given_ev
    
    1691
    +            given_loc   = ctEvLoc given_ev
    
    1692
    +            given_rewriters = ctEvRewriters given_ev
    
    1693
    +            deriv_loc = wanted_loc { ctl_depth  = deriv_depth
    
    1694
    +                                   , ctl_origin = deriv_origin }
    
    1695
    +            deriv_depth = ctl_depth wanted_loc `maxSubGoalDepth`
    
    1696
    +                          ctl_depth given_loc
    
    1697
    +            deriv_origin = FunDepOrigin1 wanted_pred
    
    1698
    +                                         (ctLocOrigin wanted_loc)
    
    1699
    +                                         (ctLocSpan wanted_loc)
    
    1700
    +                                         given_pred
    
    1701
    +                                         (ctLocOrigin given_loc)
    
    1702
    +                                         (ctLocSpan given_loc)
    
    1703
    +
    
    1704
    +do_dict_fundeps :: (DictCt -> TcS (Cts,Bool)) -> Bag DictCt -> TcS (Cts,Bool)
    
    1705
    +do_dict_fundeps do_dict_fundep cts
    
    1706
    +  = foldr do_one (return (emptyBag, False)) cts
    
    1730 1707
       where
    
    1731
    -     dict_pred      = mkClassPred cls xis
    
    1732
    -     dict_loc       = ctEvLoc ev
    
    1733
    -     dict_origin    = ctLocOrigin dict_loc
    
    1734
    -     dict_rewriters = ctEvRewriters ev
    
    1735
    -
    
    1736
    -     mk_ct_loc :: ClsInst   -- The instance decl
    
    1737
    -               -> (CtLoc, RewriterSet)
    
    1738
    -     mk_ct_loc ispec
    
    1739
    -       = ( dict_loc { ctl_origin = FunDepOrigin2 dict_pred dict_origin
    
    1740
    -                                                 inst_pred inst_loc }
    
    1741
    -         , dict_rewriters )
    
    1742
    -       where
    
    1743
    -         inst_pred = mkClassPred cls (is_tys ispec)
    
    1744
    -         inst_loc  = getSrcSpan (is_dfun ispec)
    
    1708
    +    do_one :: DictCt -> TcS (Cts,Bool) -> TcS (Cts,Bool)
    
    1709
    +    do_one dict_ct do_rest
    
    1710
    +      = -- assert (not (isGiven (dictCtEvidence dict_ct)) $
    
    1711
    +        do { (cts1, unifs1) <- do_dict_fundep dict_ct
    
    1712
    +           ; if isEmptyBag cts1 && not unifs1
    
    1713
    +             then do_rest  -- Common case
    
    1714
    +             else do { (cts2, unifs2) <- do_rest
    
    1715
    +                     ; return (cts1 `unionBags` cts2, unifs1 || unifs2) } }
    
    1745 1716
     
    
    1746 1717
     
    
    1747 1718
     {- *********************************************************************
    

  • compiler/GHC/Tc/Solver/Equality.hs
    ... ... @@ -118,7 +118,7 @@ solveEquality ev eq_rel ty1 ty2
    118 118
                                     ; solveIrred irred_ct } ;
    
    119 119
     
    
    120 120
                 Right eq_ct   -> do { tryInertEqs eq_ct
    
    121
    -                                ; tryFunDeps  eq_rel eq_ct
    
    121
    +                                ; tryFunDeps  eq_ct
    
    122 122
                                     ; tryQCsEqCt  eq_ct
    
    123 123
                                     ; simpleStage (updInertEqs eq_ct)
    
    124 124
                                     ; stopWithStage (eqCtEvidence eq_ct) "Kept inert EqCt" } } }
    
    ... ... @@ -3044,8 +3044,8 @@ equality with the template on the left. Delicate, but it works.
    3044 3044
     -}
    
    3045 3045
     
    
    3046 3046
     --------------------
    
    3047
    -tryFunDeps :: EqRel -> EqCt -> SolverStage ()
    
    3048
    -tryFunDeps eq_rel work_item@(EqCt { eq_lhs = lhs, eq_ev = ev })
    
    3047
    +tryFunDeps :: EqCt -> SolverStage ()
    
    3048
    +tryFunDeps work_item@(EqCt { eq_lhs = lhs, eq_ev = ev, eq_eq_rel = eq_rel })
    
    3049 3049
       | NomEq <- eq_rel
    
    3050 3050
       , TyFamLHS tc args <- lhs
    
    3051 3051
       = Stage $
    
    ... ... @@ -3264,7 +3264,7 @@ improveWantedLocalFunEqs funeqs_for_tc fam_tc args work_ev rhs
    3264 3264
       = do { traceTcS "interactFunEq improvements: " $
    
    3265 3265
                        vcat [ text "Eqns:" <+> ppr improvement_eqns
    
    3266 3266
                             , text "Candidates:" <+> ppr funeqs_for_tc ]
    
    3267
    -       ; emitFunDepWanteds work_ev improvement_eqns }
    
    3267
    +       ; unifyAndEmitFunDepWanteds work_ev improvement_eqns }
    
    3268 3268
       where
    
    3269 3269
         work_loc      = ctEvLoc work_ev
    
    3270 3270
         work_pred     = ctEvPred work_ev
    

  • compiler/GHC/Tc/Solver/Monad.hs
    ... ... @@ -105,7 +105,7 @@ module GHC.Tc.Solver.Monad (
    105 105
     
    
    106 106
         -- Unification
    
    107 107
         wrapUnifierX, wrapUnifierTcS, unifyFunDeps, uPairsTcM, unifyForAllBody,
    
    108
    -    unifyFunDepWanteds,
    
    108
    +    unifyFunDepWanteds, unifyAndEmitFunDepWanteds,
    
    109 109
     
    
    110 110
         -- MetaTyVars
    
    111 111
         newFlexiTcSTy, instFlexiX,
    
    ... ... @@ -2243,6 +2243,23 @@ solverDepthError loc ty
    2243 2243
     ************************************************************************
    
    2244 2244
     -}
    
    2245 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
    +
    
    2246 2263
     unifyFunDepWanteds :: CtEvidence  -- The work item
    
    2247 2264
                       -> [FunDepEqn (CtLoc, RewriterSet)]
    
    2248 2265
                       -> TcS (Cts, Bool)   -- True <=> some unification happened
    

  • compiler/GHC/Tc/Solver/Solve.hs
    ... ... @@ -26,7 +26,6 @@ import GHC.Tc.Types
    26 26
     import GHC.Tc.Types.Origin
    
    27 27
     import GHC.Tc.Types.Constraint
    
    28 28
     import GHC.Tc.Types.CtLoc( mkGivenLoc )
    
    29
    -import GHC.Tc.Instance.FunDeps ( FunDepEqn(..) )
    
    30 29
     import GHC.Tc.Solver.InertSet
    
    31 30
     import GHC.Tc.Solver.Monad
    
    32 31
     import GHC.Tc.Utils.Monad   as TcM
    
    ... ... @@ -47,7 +46,6 @@ import GHC.Types.Unique.Set( nonDetStrictFoldUniqSet )
    47 46
     
    
    48 47
     import GHC.Data.Bag
    
    49 48
     import GHC.Data.Maybe
    
    50
    -import GHC.Data.Pair
    
    51 49
     
    
    52 50
     import GHC.Utils.Outputable
    
    53 51
     import GHC.Utils.Panic
    
    ... ... @@ -207,14 +205,21 @@ maybe_simplify_again n limit unif_happened wc@(WC { wc_simple = simples })
    207 205
           | otherwise
    
    208 206
           = return Nothing
    
    209 207
     
    
    208
    +    dicts :: Bag DictCt
    
    209
    +    dicts = mapMaybeBag is_dict simples
    
    210
    +          where
    
    211
    +            is_dict (CDictCan d) = Just d
    
    212
    +            is_dict _            = Nothing
    
    213
    +
    
    210 214
         try_fundeps :: TcS (Maybe NextAction)
    
    211 215
         try_fundeps
    
    212
    -      = do { inst_envs <- getInstEnvs
    
    213
    -           ; let fundep_eqns = generateTopFunDeps inst_envs simples
    
    214
    -           ; (new_eqs, unif_happened) <- unifyFunDepWanteds fundep_eqns
    
    215
    -           ; if null new_eqs && not unif_happened
    
    216
    +      = do { (new_eqs1, unifs1) <- doTopFunDepImprovement dicts
    
    217
    +           ; (new_eqs2, unifs2) <- doLocalFunDepImprovement dicts
    
    218
    +           ; let new_eqs = new_eqs1 `unionBags` new_eqs2
    
    219
    +                 unifs   = unifs1 || unifs2
    
    220
    +           ; if null new_eqs && not unifs
    
    216 221
                  then return Nothing
    
    217
    -             else return (Just (NA_TryAgain (wc `addSimples` new_eqs) unif_happened)) }
    
    222
    +             else return (Just (NA_TryAgain (wc `addSimples` new_eqs) unifs)) }
    
    218 223
     
    
    219 224
     {- Note [Superclass iteration]
    
    220 225
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~