| ... |
... |
@@ -45,19 +45,19 @@ import Data.Maybe( mapMaybe ) |
|
45
|
45
|
Here is our plan for dealing with functional dependencies
|
|
46
|
46
|
|
|
47
|
47
|
* When we have failed to solve a Wanted constraint, do this
|
|
48
|
|
- 1. Generate any fundep-equalities [FunDepEqn] from that constraint.
|
|
49
|
|
- 2. Try to solve that [FunDepEqn]
|
|
|
48
|
+ 1. Generate any fundep-equalities [FunDepEqns] from that constraint.
|
|
|
49
|
+ 2. Try to solve that [FunDepEqns]
|
|
50
|
50
|
3. If any unifications happened, send the constraint back to the
|
|
51
|
51
|
start of the pipeline
|
|
52
|
52
|
|
|
53
|
|
-* Step (1) How we generate those [FunDepEqn] varies:
|
|
|
53
|
+* Step (1) How we generate those [FunDepEqns] varies:
|
|
54
|
54
|
- tryDictFunDeps: for class constraints (C t1 .. tn)
|
|
55
|
55
|
we look at top-level instances and inert Givens
|
|
56
|
56
|
- tryEqFunDeps: for type-family equalities (F t1 .. tn ~ ty)
|
|
57
|
57
|
we look at top-level family instances
|
|
58
|
58
|
and inert Given family equalities
|
|
59
|
59
|
|
|
60
|
|
-* Step (2). We use `solveFunDeps` to solve the [FunDepEqn] in a nested
|
|
|
60
|
+* Step (2). We use `solveFunDeps` to solve the [FunDepEqns] in a nested
|
|
61
|
61
|
solver. Key property:
|
|
62
|
62
|
|
|
63
|
63
|
The ONLY effect of `solveFunDeps` is possibly to perform unifications:
|
| ... |
... |
@@ -169,14 +169,14 @@ Why? Because if we do (YES) we'll think we have made some progress |
|
169
|
169
|
(some unification has happened), and hence go round again; but actually all we
|
|
170
|
170
|
have done is to replace `alpha` with `gamma1`.
|
|
171
|
171
|
|
|
172
|
|
-These "fresh unification variables" in fundep-equalities are ubituitous.
|
|
|
172
|
+These "fresh unification variables" in fundep-equalities are ubiquitous.
|
|
173
|
173
|
For example
|
|
174
|
174
|
class C a b | a -> b
|
|
175
|
175
|
instance .. => C Int [x]
|
|
176
|
176
|
If we see
|
|
177
|
177
|
[W] C Int alpha
|
|
178
|
178
|
we'll generate a fundep-equality [W] alpha ~ [beta1]
|
|
179
|
|
-where `beta1` is one of those "fresh unification variables
|
|
|
179
|
+where `beta1` is one of those "fresh unification variables"
|
|
180
|
180
|
|
|
181
|
181
|
This problem shows up in several guises; see (at the bottom)
|
|
182
|
182
|
* Historical Note [Improvement orientation]
|
| ... |
... |
@@ -184,10 +184,10 @@ This problem shows up in several guises; see (at the bottom) |
|
184
|
184
|
|
|
185
|
185
|
The solution is super-simple:
|
|
186
|
186
|
|
|
187
|
|
- * A fundep-equality is described by `FunDepEqn`, whose `fd_qtvs` field explicitly
|
|
|
187
|
+ * A fundep-equality is described by `FunDepEqns`, whose `fd_qtvs` field explicitly
|
|
188
|
188
|
lists the "fresh variables"
|
|
189
|
189
|
|
|
190
|
|
- * Function `instantiateFunDepEqn` instantiates a `FunDepEqn`, and CRUCIALLY
|
|
|
190
|
+ * Function `instantiateFunDepEqn` instantiates a `FunDepEqns`, and CRUCIALLY
|
|
191
|
191
|
gives the new unification variables a level one deeper than the current
|
|
192
|
192
|
level.
|
|
193
|
193
|
|
| ... |
... |
@@ -196,8 +196,8 @@ The solution is super-simple: |
|
196
|
196
|
Note [Deeper level on the left]. That ensures that the fresh `gamma1`
|
|
197
|
197
|
will be eliminated in favour of `alpha`. Hooray.
|
|
198
|
198
|
|
|
199
|
|
- * Better still, we solve the [FunDepEqn] with
|
|
200
|
|
- solveFunDeps :: CtEvidence -> [FunDepEqn] -> TcS Bool
|
|
|
199
|
+ * Better still, we solve the [FunDepEqns] with
|
|
|
200
|
+ solveFunDeps :: CtEvidence -> [FunDepEqns] -> TcS Bool
|
|
201
|
201
|
It uses `reportUnifications` to see if any unification happened at this
|
|
202
|
202
|
level or outside -- that is, it does NOT report unifications to the fresh
|
|
203
|
203
|
unification variables. So `solveFunDeps` returns True only if it
|
| ... |
... |
@@ -320,7 +320,7 @@ tryDictFunDepsLocal dict_ct@(DictCt { di_cls = cls, di_ev = work_ev }) |
|
320
|
320
|
|
|
321
|
321
|
; traceTcS "tryDictFunDepsLocal {" (ppr dict_ct)
|
|
322
|
322
|
|
|
323
|
|
- ; let eqns :: [FunDepEqn]
|
|
|
323
|
+ ; let eqns :: [FunDepEqns]
|
|
324
|
324
|
eqns = foldr ((++) . do_interaction) [] $
|
|
325
|
325
|
findDictsByClass (inert_dicts inerts) cls
|
|
326
|
326
|
; imp <- solveFunDeps work_ev eqns
|
| ... |
... |
@@ -335,7 +335,7 @@ tryDictFunDepsLocal dict_ct@(DictCt { di_cls = cls, di_ev = work_ev }) |
|
335
|
335
|
work_pred = ctEvPred work_ev
|
|
336
|
336
|
work_is_given = isGiven work_ev
|
|
337
|
337
|
|
|
338
|
|
- do_interaction :: DictCt -> [FunDepEqn]
|
|
|
338
|
+ do_interaction :: DictCt -> [FunDepEqns]
|
|
339
|
339
|
do_interaction (DictCt { di_ev = inert_ev }) -- This can be Given or Wanted
|
|
340
|
340
|
| work_is_given && isGiven inert_ev
|
|
341
|
341
|
-- Do not create FDs from Given/Given interactions
|
| ... |
... |
@@ -353,7 +353,7 @@ tryDictFunDepsTop dict_ct@(DictCt { di_ev = ev, di_cls = cls, di_tys = xis }) |
|
353
|
353
|
do { inst_envs <- getInstEnvs
|
|
354
|
354
|
|
|
355
|
355
|
; traceTcS "tryDictFunDepsTop {" (ppr dict_ct)
|
|
356
|
|
- ; let eqns :: [FunDepEqn]
|
|
|
356
|
+ ; let eqns :: [FunDepEqns]
|
|
357
|
357
|
eqns = improveFromInstEnv inst_envs cls xis
|
|
358
|
358
|
; imp <- solveFunDeps ev eqns
|
|
359
|
359
|
; traceTcS "tryDictFunDepsTop }" (text "imp =" <+> ppr imp)
|
| ... |
... |
@@ -466,7 +466,7 @@ tryFamEqFunDeps fam_tc args work_item@(EqCt { eq_ev = ev, eq_rhs = rhs }) |
|
466
|
466
|
| otherwise
|
|
467
|
467
|
= nopStage ()
|
|
468
|
468
|
|
|
469
|
|
-tryFDEqns :: TyCon -> [TcType] -> EqCt -> TcS [FunDepEqn] -> SolverStage ()
|
|
|
469
|
+tryFDEqns :: TyCon -> [TcType] -> EqCt -> TcS [FunDepEqns] -> SolverStage ()
|
|
470
|
470
|
tryFDEqns fam_tc work_args work_item@(EqCt { eq_ev = ev, eq_rhs= rhs }) mk_fd_eqns
|
|
471
|
471
|
= Stage $
|
|
472
|
472
|
do { fd_eqns <- mk_fd_eqns
|
| ... |
... |
@@ -481,7 +481,7 @@ tryFDEqns fam_tc work_args work_item@(EqCt { eq_ev = ev, eq_rhs= rhs }) mk_fd_eq |
|
481
|
481
|
-----------------------------------------
|
|
482
|
482
|
-- User-defined type families
|
|
483
|
483
|
-----------------------------------------
|
|
484
|
|
-mkTopUserFamEqFDs :: TyCon -> [Bool] -> [TcType] -> Xi -> TcS [FunDepEqn]
|
|
|
484
|
+mkTopUserFamEqFDs :: TyCon -> [Bool] -> [TcType] -> Xi -> TcS [FunDepEqns]
|
|
485
|
485
|
-- Implements (INJFAM:Wanted/top)
|
|
486
|
486
|
mkTopUserFamEqFDs fam_tc inj_flags work_args work_rhs
|
|
487
|
487
|
= do { fam_envs <- getFamInstEnvs
|
| ... |
... |
@@ -499,7 +499,7 @@ mkTopUserFamEqFDs fam_tc inj_flags work_args work_rhs |
|
499
|
499
|
| otherwise
|
|
500
|
500
|
= []
|
|
501
|
501
|
|
|
502
|
|
- do_one :: CoAxBranch -> Maybe FunDepEqn
|
|
|
502
|
+ do_one :: CoAxBranch -> Maybe FunDepEqns
|
|
503
|
503
|
do_one branch@(CoAxBranch { cab_tvs = branch_tvs
|
|
504
|
504
|
, cab_lhs = branch_lhs_tys
|
|
505
|
505
|
, cab_rhs = branch_rhs })
|
| ... |
... |
@@ -525,7 +525,7 @@ mkTopUserFamEqFDs fam_tc inj_flags work_args work_rhs |
|
525
|
525
|
!(subst', tvs') = trim_qtvs subst1 tvs
|
|
526
|
526
|
in (subst', tv':tvs')
|
|
527
|
527
|
|
|
528
|
|
-mkLocalUserFamEqFDs :: TyCon -> [Bool] -> [TcType] -> Xi -> TcS [FunDepEqn]
|
|
|
528
|
+mkLocalUserFamEqFDs :: TyCon -> [Bool] -> [TcType] -> Xi -> TcS [FunDepEqns]
|
|
529
|
529
|
mkLocalUserFamEqFDs fam_tc inj_flags work_args work_rhs
|
|
530
|
530
|
= do { fun_eqs_for_me <- getInertFamEqsFor fam_tc
|
|
531
|
531
|
|
| ... |
... |
@@ -538,7 +538,7 @@ mkLocalUserFamEqFDs fam_tc inj_flags work_args work_rhs |
|
538
|
538
|
|
|
539
|
539
|
; return (eqns_from_inerts ++ eqns_from_self) }
|
|
540
|
540
|
where
|
|
541
|
|
- do_one :: EqCt -> Maybe FunDepEqn
|
|
|
541
|
+ do_one :: EqCt -> Maybe FunDepEqns
|
|
542
|
542
|
do_one (EqCt { eq_lhs = TyFamLHS _ inert_args, eq_rhs = inert_rhs })
|
|
543
|
543
|
| work_rhs `tcEqType` inert_rhs = Just (mk_eqn inert_args)
|
|
544
|
544
|
| otherwise = Nothing
|
| ... |
... |
@@ -604,24 +604,24 @@ tryGivenBuiltinFamEqFDs fam_tc ops work_args (EqCt { eq_ev = work_ev, eq_rhs = w |
|
604
|
604
|
|
|
605
|
605
|
do_one _ = return ()
|
|
606
|
606
|
|
|
607
|
|
-mkTopBuiltinFamEqFDs :: TyCon -> BuiltInSynFamily -> [TcType] -> Xi -> TcS [FunDepEqn]
|
|
|
607
|
+mkTopBuiltinFamEqFDs :: TyCon -> BuiltInSynFamily -> [TcType] -> Xi -> TcS [FunDepEqns]
|
|
608
|
608
|
mkTopBuiltinFamEqFDs fam_tc ops work_args work_rhs
|
|
609
|
|
- = return [FDEqn { fd_qtvs = []
|
|
610
|
|
- , fd_eqs = map snd $ tryInteractTopFam ops fam_tc work_args work_rhs }]
|
|
|
609
|
+ = return [FDEqns { fd_qtvs = []
|
|
|
610
|
+ , fd_eqs = map snd $ tryInteractTopFam ops fam_tc work_args work_rhs }]
|
|
611
|
611
|
|
|
612
|
|
-mkLocalBuiltinFamEqFDs :: TyCon -> BuiltInSynFamily -> [TcType] -> Xi -> TcS [FunDepEqn]
|
|
|
612
|
+mkLocalBuiltinFamEqFDs :: TyCon -> BuiltInSynFamily -> [TcType] -> Xi -> TcS [FunDepEqns]
|
|
613
|
613
|
mkLocalBuiltinFamEqFDs fam_tc ops work_args work_rhs
|
|
614
|
614
|
= do { fun_eqs_for_me <- getInertFamEqsFor fam_tc
|
|
615
|
615
|
|
|
616
|
|
- ; let do_one :: EqCt -> [FunDepEqn]
|
|
|
616
|
+ ; let do_one :: EqCt -> [FunDepEqns]
|
|
617
|
617
|
do_one (EqCt { eq_lhs = TyFamLHS _ inert_args, eq_rhs = inert_rhs })
|
|
618
|
618
|
| inert_rhs `tcEqType` work_rhs = [mk_eqn inert_args]
|
|
619
|
619
|
| otherwise = []
|
|
620
|
620
|
do_one _ = pprPanic "interactFunEq 1" (ppr fam_tc) -- TyVarLHS
|
|
621
|
621
|
|
|
622
|
|
- mk_eqn :: [TcType] -> FunDepEqn
|
|
623
|
|
- mk_eqn iargs = FDEqn { fd_qtvs = []
|
|
624
|
|
- , fd_eqs = map snd $ tryInteractInertFam ops fam_tc
|
|
|
622
|
+ mk_eqn :: [TcType] -> FunDepEqns
|
|
|
623
|
+ mk_eqn iargs = FDEqns { fd_qtvs = []
|
|
|
624
|
+ , fd_eqs = map snd $ tryInteractInertFam ops fam_tc
|
|
625
|
625
|
work_args iargs }
|
|
626
|
626
|
|
|
627
|
627
|
; let eqns_from_inerts = concatMap do_one fun_eqs_for_me
|
| ... |
... |
@@ -634,12 +634,12 @@ mkLocalBuiltinFamEqFDs fam_tc ops work_args work_rhs |
|
634
|
634
|
mkInjectivityFDEqn :: [Bool] -- Injectivity flags
|
|
635
|
635
|
-> [TcTyVar] -- Quantify these
|
|
636
|
636
|
-> [TcType] -> [TcType] -- Make these equal
|
|
637
|
|
- -> FunDepEqn
|
|
|
637
|
+ -> FunDepEqns
|
|
638
|
638
|
-- When F s1 s2 s3 ~ F t1 t2 t3, and F has injectivity info [True,False,True]
|
|
639
|
|
--- return the FDEqn { fd_eqs = [Pair s1 t1, Pair s3 t3] }
|
|
|
639
|
+-- return the FDEqns { fd_eqs = [Pair s1 t1, Pair s3 t3] }
|
|
640
|
640
|
-- The injectivity flags [Bool] will not all be False, but nothing goes wrong if they are
|
|
641
|
641
|
mkInjectivityFDEqn inj_args qtvs lhs_args rhs_args
|
|
642
|
|
- = FDEqn { fd_qtvs = qtvs, fd_eqs = eqs }
|
|
|
642
|
+ = FDEqns { fd_qtvs = qtvs, fd_eqs = eqs }
|
|
643
|
643
|
where
|
|
644
|
644
|
eqs = [ Pair lhs_arg rhs_arg
|
|
645
|
645
|
| (True, lhs_arg, rhs_arg) <- zip3 inj_args lhs_args rhs_args ]
|
| ... |
... |
@@ -669,19 +669,19 @@ For /injective/, /user-defined/ type families |
|
669
|
669
|
|
|
670
|
670
|
* (INJFAM:Wanted/Self) see `mkLocalUserFamEqFDs`
|
|
671
|
671
|
work item: [W] F s1 s2 ~ F t1 t2
|
|
672
|
|
- We can generate FDEqn (s2 ~ t2)
|
|
|
672
|
+ We can generate FunDepEqns: (s2 ~ t2)
|
|
673
|
673
|
|
|
674
|
674
|
* (INJFAM:Wanted/other) see `mkLocalUserFamEqFDs`
|
|
675
|
675
|
work item: [W] F s1 s2 ~ rhs -- Wanted
|
|
676
|
676
|
inert: [G/W] F t2 t2 ~ rhs -- Same `rhs`, Given or Wanted
|
|
677
|
|
- We can generate FDEqn (s2 ~ t2)
|
|
|
677
|
+ We can generate FunDepEqns: (s2 ~ t2)
|
|
678
|
678
|
|
|
679
|
679
|
* (INJFAM:Wanted/top) see `mkTopUserFamEqFDs`
|
|
680
|
680
|
work item: [W] F s1 s2 ~ rhs
|
|
681
|
681
|
type instance forall a b c. F t1 t2 ~ top_rhs
|
|
682
|
682
|
and we can /match/ the LHS, so that
|
|
683
|
683
|
S(top_rhs) = rhs
|
|
684
|
|
- then we can generate the FDEqn forall a c. s2 ~ S(t2)
|
|
|
684
|
+ then we can generate the FunDepEqns: forall a c. s2 ~ S(t2)
|
|
685
|
685
|
But see wrinkle (TIF1), (TIF2)
|
|
686
|
686
|
|
|
687
|
687
|
For /built-in/ type families, it's pretty similar, except that
|
| ... |
... |
@@ -703,10 +703,10 @@ For /built-in/ type families, it's pretty similar, except that |
|
703
|
703
|
[W] F @kappa alpha beta ~ Maybe (Proxy @kappa (delta::kappa))
|
|
704
|
704
|
|
|
705
|
705
|
we match (Proxy @kappa delta) against the template (Proxy k a), succeeding
|
|
706
|
|
- with substitution [k:->kappa, a:->delta]. We want to generate this FunDepEqn
|
|
|
706
|
+ with substitution [k:->kappa, a:->delta]. We want to generate this FunDepEqns
|
|
707
|
707
|
FDEqn { fd_qtvs = [b:kappa], fd_eqs = [ beta ~ Proxy @kappa b ] }
|
|
708
|
708
|
Notice that
|
|
709
|
|
- * we must quantify the FunDepEqn over `b`, which is not matched; for this
|
|
|
709
|
+ * we must quantify the FunDepEqns over `b`, which is not matched; for this
|
|
710
|
710
|
we will generate a fresh unfication variable in `instantiateFunDepEqn`.
|
|
711
|
711
|
* we must substitute `k:->kappa` in the kind of `b`.
|
|
712
|
712
|
This fancy footwork for `fd_qtvs` is done by `trim_qtvs` in
|
| ... |
... |
@@ -756,7 +756,7 @@ solving. |
|
756
|
756
|
********************************************************************* -}
|
|
757
|
757
|
|
|
758
|
758
|
solveFunDeps :: CtEvidence -- The work item
|
|
759
|
|
- -> [FunDepEqn]
|
|
|
759
|
+ -> [FunDepEqns]
|
|
760
|
760
|
-> TcS Bool
|
|
761
|
761
|
-- Solve a bunch of type-equality equations, generated by functional dependencies
|
|
762
|
762
|
-- By "solve" we mean: (only) do unifications. We do not generate evidence, and
|
| ... |
... |
@@ -784,12 +784,12 @@ solveFunDeps work_ev fd_eqns |
|
784
|
784
|
do_fundeps :: UnifyEnv -> TcM ()
|
|
785
|
785
|
do_fundeps env = mapM_ (do_one env) fd_eqns
|
|
786
|
786
|
|
|
787
|
|
- do_one :: UnifyEnv -> FunDepEqn -> TcM ()
|
|
|
787
|
+ do_one :: UnifyEnv -> FunDepEqns -> TcM ()
|
|
788
|
788
|
do_one uenv eqn = do { eqs <- instantiateFunDepEqn eqn
|
|
789
|
789
|
; uPairsTcM uenv eqs }
|
|
790
|
790
|
|
|
791
|
|
-instantiateFunDepEqn :: FunDepEqn -> TcM [TypeEqn]
|
|
792
|
|
-instantiateFunDepEqn (FDEqn { fd_qtvs = tvs, fd_eqs = eqs })
|
|
|
791
|
+instantiateFunDepEqn :: FunDepEqns -> TcM [TypeEqn]
|
|
|
792
|
+instantiateFunDepEqn (FDEqns { fd_qtvs = tvs, fd_eqs = eqs })
|
|
793
|
793
|
| null tvs
|
|
794
|
794
|
= return rev_eqs
|
|
795
|
795
|
| otherwise
|