Simon Peyton Jones pushed to branch wip/T23162-spj at Glasgow Haskell Compiler / GHC
Commits:
-
02401833
by Simon Peyton Jones at 2025-08-10T00:14:42+01:00
4 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
Changes:
... | ... | @@ -21,7 +21,7 @@ import GHC.Tc.Types.Constraint |
21 | 21 | import GHC.Tc.Types.CtLoc
|
22 | 22 | import GHC.Tc.Types.Origin
|
23 | 23 | import GHC.Tc.Types.EvTerm( evCallStack )
|
24 | -import GHC.Tc.Solver.FunDeps( doDictFunDepImprovement )
|
|
24 | +import GHC.Tc.Solver.FunDeps( tryDictFunDeps )
|
|
25 | 25 | import GHC.Tc.Solver.InertSet
|
26 | 26 | import GHC.Tc.Solver.Monad
|
27 | 27 | import GHC.Tc.Solver.Types
|
... | ... | @@ -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 | - ; doDictFunDepImprovement dict_ct
|
|
98 | + ; tryDictFunDeps dict_ct
|
|
99 | 99 | |
100 | 100 | ; simpleStage (updInertDicts dict_ct)
|
101 | 101 | ; stopWithStage (dictCtEvidence dict_ct) "Kept inert DictCt" }
|
... | ... | @@ -16,9 +16,8 @@ import GHC.Tc.Solver.Irred( solveIrred ) |
16 | 16 | import GHC.Tc.Solver.Dict( matchLocalInst, chooseInstance )
|
17 | 17 | import GHC.Tc.Solver.Rewrite
|
18 | 18 | import GHC.Tc.Solver.Monad
|
19 | -import GHC.Tc.Solver.FunDeps( unifyAndEmitFunDepWanteds )
|
|
19 | +import GHC.Tc.Solver.FunDeps( tryEqFunDeps )
|
|
20 | 20 | import GHC.Tc.Solver.InertSet
|
21 | -import GHC.Tc.Solver.Types( findFunEqsByTyCon )
|
|
22 | 21 | import GHC.Tc.Types.Evidence
|
23 | 22 | import GHC.Tc.Types.Constraint
|
24 | 23 | import GHC.Tc.Types.CtLoc
|
... | ... | @@ -26,7 +25,6 @@ import GHC.Tc.Types.Origin |
26 | 25 | import GHC.Tc.Utils.Unify
|
27 | 26 | import GHC.Tc.Utils.TcType
|
28 | 27 | import GHC.Tc.Instance.Family ( tcTopNormaliseNewTypeTF_maybe )
|
29 | -import GHC.Tc.Instance.FunDeps( FunDepEqn(..) )
|
|
30 | 28 | import qualified GHC.Tc.Utils.Monad as TcM
|
31 | 29 | |
32 | 30 | import GHC.Core.Type
|
... | ... | @@ -36,21 +34,15 @@ import GHC.Core.DataCon ( dataConName ) |
36 | 34 | import GHC.Core.TyCon
|
37 | 35 | import GHC.Core.TyCo.Rep -- cleverly decomposes types, good for completeness checking
|
38 | 36 | import GHC.Core.Coercion
|
39 | -import GHC.Core.Coercion.Axiom
|
|
40 | 37 | import GHC.Core.Reduction
|
41 | -import GHC.Core.Unify( tcUnifyTyForInjectivity )
|
|
42 | -import GHC.Core.FamInstEnv ( FamInstEnvs, FamInst(..), apartnessCheck
|
|
43 | - , lookupFamInstEnvByTyCon )
|
|
38 | +import GHC.Core.FamInstEnv ( FamInstEnvs )
|
|
44 | 39 | import GHC.Core
|
45 | - |
|
46 | 40 | import GHC.Types.Var
|
47 | 41 | import GHC.Types.Var.Env
|
48 | 42 | import GHC.Types.Var.Set( anyVarSet )
|
49 | 43 | import GHC.Types.Name.Reader
|
50 | 44 | import GHC.Types.Basic
|
51 | 45 | |
52 | -import GHC.Builtin.Types.Literals ( tryInteractTopFam, tryInteractInertFam )
|
|
53 | - |
|
54 | 46 | import GHC.Utils.Outputable
|
55 | 47 | import GHC.Utils.Panic
|
56 | 48 | import GHC.Utils.Misc
|
... | ... | @@ -120,9 +112,9 @@ solveEquality ev eq_rel ty1 ty2 |
120 | 112 | Left irred_ct -> do { tryQCsIrredEqCt irred_ct
|
121 | 113 | ; solveIrred irred_ct } ;
|
122 | 114 | |
123 | - Right eq_ct -> do { tryInertEqs eq_ct
|
|
124 | - ; tryFunDeps eq_ct
|
|
125 | - ; tryQCsEqCt eq_ct
|
|
115 | + Right eq_ct -> do { tryInertEqs eq_ct
|
|
116 | + ; tryEqFunDeps eq_ct
|
|
117 | + ; tryQCsEqCt eq_ct
|
|
126 | 118 | ; simpleStage (updInertEqs eq_ct)
|
127 | 119 | ; stopWithStage (eqCtEvidence eq_ct) "Kept inert EqCt" } } }
|
128 | 120 | |
... | ... | @@ -2025,7 +2017,7 @@ canEqCanLHSFinish_try_unification ev eq_rel swapped lhs rhs |
2025 | 2017 | evCoercion (mkNomReflCo final_rhs)
|
2026 | 2018 | |
2027 | 2019 | -- Kick out any constraints that can now be rewritten
|
2028 | - ; kickOutAfterUnification [tv]
|
|
2020 | + ; recordUnification tv
|
|
2029 | 2021 | |
2030 | 2022 | ; return (Stop new_ev (text "Solved by unification")) }
|
2031 | 2023 | |
... | ... | @@ -2996,456 +2988,3 @@ lovely quantified constraint. Alas! |
2996 | 2988 | This test arranges to ignore the instance-based solution under these
|
2997 | 2989 | (rare) circumstances. It's sad, but I really don't see what else we can do.
|
2998 | 2990 | -} |
2999 | - |
|
3000 | - |
|
3001 | -{-
|
|
3002 | -**********************************************************************
|
|
3003 | -* *
|
|
3004 | - Functional dependencies for type families
|
|
3005 | -* *
|
|
3006 | -**********************************************************************
|
|
3007 | - |
|
3008 | -Note [Reverse order of fundep equations]
|
|
3009 | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
3010 | -Consider this scenario (from dependent/should_fail/T13135_simple):
|
|
3011 | - |
|
3012 | - type Sig :: Type -> Type
|
|
3013 | - data Sig a = SigFun a (Sig a)
|
|
3014 | - |
|
3015 | - type SmartFun :: forall (t :: Type). Sig t -> Type
|
|
3016 | - type family SmartFun sig = r | r -> sig where
|
|
3017 | - SmartFun @Type (SigFun @Type a sig) = a -> SmartFun @Type sig
|
|
3018 | - |
|
3019 | - [W] SmartFun @kappa sigma ~ (Int -> Bool)
|
|
3020 | - |
|
3021 | -The injectivity of SmartFun allows us to produce two new equalities:
|
|
3022 | - |
|
3023 | - [W] w1 :: Type ~ kappa
|
|
3024 | - [W] w2 :: SigFun @Type Int beta ~ sigma
|
|
3025 | - |
|
3026 | -for some fresh (beta :: SigType). The second Wanted here is actually
|
|
3027 | -heterogeneous: the LHS has type Sig Type while the RHS has type Sig kappa.
|
|
3028 | -Of course, if we solve the first wanted first, the second becomes homogeneous.
|
|
3029 | - |
|
3030 | -When looking for injectivity-inspired equalities, we work left-to-right,
|
|
3031 | -producing the two equalities in the order written above. However, these
|
|
3032 | -equalities are then passed into wrapUnifierTcS, which will fail, adding these
|
|
3033 | -to the work list. However, crucially, the work list operates like a *stack*.
|
|
3034 | -So, because we add w1 and then w2, we process w2 first. This is silly: solving
|
|
3035 | -w1 would unlock w2. So we make sure to add equalities to the work
|
|
3036 | -list in left-to-right order, which requires a few key calls to 'reverse'.
|
|
3037 | - |
|
3038 | -This treatment is also used for class-based functional dependencies, although
|
|
3039 | -we do not have a program yet known to exhibit a loop there. It just seems
|
|
3040 | -like the right thing to do.
|
|
3041 | - |
|
3042 | -When this was originally conceived, it was necessary to avoid a loop in T13135.
|
|
3043 | -That loop is now avoided by continuing with the kind equality (not the type
|
|
3044 | -equality) in canEqCanLHSHetero (see Note [Equalities with heterogeneous kinds]).
|
|
3045 | -However, the idea of working left-to-right still seems worthwhile, and so the calls
|
|
3046 | -to 'reverse' remain.
|
|
3047 | - |
|
3048 | -Note [Improvement orientation]
|
|
3049 | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
3050 | -See also Note [Fundeps with instances, and equality orientation], which describes
|
|
3051 | -the Exact Same Problem, with the same solution, but for functional dependencies.
|
|
3052 | - |
|
3053 | -A very delicate point is the orientation of equalities
|
|
3054 | -arising from injectivity improvement (#12522). Suppose we have
|
|
3055 | - type family F x = t | t -> x
|
|
3056 | - type instance F (a, Int) = (Int, G a)
|
|
3057 | -where G is injective; and wanted constraints
|
|
3058 | - |
|
3059 | - [W] F (alpha, beta) ~ (Int, <some type>)
|
|
3060 | - |
|
3061 | -The injectivity will give rise to constraints
|
|
3062 | - |
|
3063 | - [W] gamma1 ~ alpha
|
|
3064 | - [W] Int ~ beta
|
|
3065 | - |
|
3066 | -The fresh unification variable gamma1 comes from the fact that we
|
|
3067 | -can only do "partial improvement" here; see Section 5.2 of
|
|
3068 | -"Injective type families for Haskell" (HS'15).
|
|
3069 | - |
|
3070 | -Now, it's very important to orient the equations this way round,
|
|
3071 | -so that the fresh unification variable will be eliminated in
|
|
3072 | -favour of alpha. If we instead had
|
|
3073 | - [W] alpha ~ gamma1
|
|
3074 | -then we would unify alpha := gamma1; and kick out the wanted
|
|
3075 | -constraint. But when we substitute it back in, it'd look like
|
|
3076 | - [W] F (gamma1, beta) ~ fuv
|
|
3077 | -and exactly the same thing would happen again! Infinite loop.
|
|
3078 | - |
|
3079 | -This all seems fragile, and it might seem more robust to avoid
|
|
3080 | -introducing gamma1 in the first place, in the case where the
|
|
3081 | -actual argument (alpha, beta) partly matches the improvement
|
|
3082 | -template. But that's a bit tricky, esp when we remember that the
|
|
3083 | -kinds much match too; so it's easier to let the normal machinery
|
|
3084 | -handle it. Instead we are careful to orient the new
|
|
3085 | -equality with the template on the left. Delicate, but it works.
|
|
3086 | - |
|
3087 | --}
|
|
3088 | - |
|
3089 | ---------------------
|
|
3090 | - |
|
3091 | -tryFunDeps :: EqCt -> SolverStage ()
|
|
3092 | -tryFunDeps work_item@(EqCt { eq_lhs = lhs, eq_ev = ev, eq_eq_rel = eq_rel })
|
|
3093 | - | NomEq <- eq_rel
|
|
3094 | - , TyFamLHS tc args <- lhs
|
|
3095 | - = Stage $
|
|
3096 | - do { inerts <- getInertCans
|
|
3097 | - ; imp1 <- improveLocalFunEqs inerts tc args work_item
|
|
3098 | - ; imp2 <- improveTopFunEqs tc args work_item
|
|
3099 | - ; if (imp1 || imp2)
|
|
3100 | - then startAgainWith (mkNonCanonical ev)
|
|
3101 | - else continueWith () }
|
|
3102 | - | otherwise
|
|
3103 | - = nopStage ()
|
|
3104 | - |
|
3105 | ---------------------
|
|
3106 | -improveTopFunEqs :: TyCon -> [TcType] -> EqCt -> TcS Bool
|
|
3107 | --- TyCon is definitely a type family
|
|
3108 | --- See Note [FunDep and implicit parameter reactions]
|
|
3109 | -improveTopFunEqs fam_tc args (EqCt { eq_ev = ev, eq_rhs = rhs_ty })
|
|
3110 | - | isGiven ev = improveGivenTopFunEqs fam_tc args ev rhs_ty
|
|
3111 | - | otherwise = improveWantedTopFunEqs fam_tc args ev rhs_ty
|
|
3112 | - |
|
3113 | -improveGivenTopFunEqs :: TyCon -> [TcType] -> CtEvidence -> Xi -> TcS Bool
|
|
3114 | --- TyCon is definitely a type family
|
|
3115 | --- Work-item is a Given
|
|
3116 | -improveGivenTopFunEqs fam_tc args ev rhs_ty
|
|
3117 | - | Just ops <- isBuiltInSynFamTyCon_maybe fam_tc
|
|
3118 | - = do { traceTcS "improveGivenTopFunEqs" (ppr fam_tc <+> ppr args $$ ppr ev $$ ppr rhs_ty)
|
|
3119 | - ; emitNewGivens (ctEvLoc ev) $
|
|
3120 | - [ (Nominal, new_co)
|
|
3121 | - | (ax, _) <- tryInteractTopFam ops fam_tc args rhs_ty
|
|
3122 | - , let new_co = mkAxiomCo ax [given_co] ]
|
|
3123 | - ; return False } -- False: no unifications
|
|
3124 | - | otherwise
|
|
3125 | - = return False
|
|
3126 | - where
|
|
3127 | - given_co :: Coercion = ctEvCoercion ev
|
|
3128 | - |
|
3129 | -improveWantedTopFunEqs :: TyCon -> [TcType] -> CtEvidence -> Xi -> TcS Bool
|
|
3130 | --- TyCon is definitely a type family
|
|
3131 | --- Work-item is a Wanted
|
|
3132 | -improveWantedTopFunEqs fam_tc args ev rhs_ty
|
|
3133 | - = do { eqns <- improve_wanted_top_fun_eqs fam_tc args rhs_ty
|
|
3134 | - ; traceTcS "improveTopFunEqs" (vcat [ text "lhs:" <+> ppr fam_tc <+> ppr args
|
|
3135 | - , text "rhs:" <+> ppr rhs_ty
|
|
3136 | - , text "eqns:" <+> ppr eqns ])
|
|
3137 | - ; unifyFunDeps ev Nominal $ \uenv ->
|
|
3138 | - uPairsTcM (bump_depth uenv) (reverse eqns) }
|
|
3139 | - -- Missing that `reverse` causes T13135 and T13135_simple to loop.
|
|
3140 | - -- See Note [Reverse order of fundep equations]
|
|
3141 | - |
|
3142 | - where
|
|
3143 | - bump_depth env = env { u_loc = bumpCtLocDepth (u_loc env) }
|
|
3144 | - -- ToDo: this location is wrong; it should be FunDepOrigin2
|
|
3145 | - -- See #14778
|
|
3146 | - |
|
3147 | -improve_wanted_top_fun_eqs :: TyCon -> [TcType] -> Xi
|
|
3148 | - -> TcS [TypeEqn]
|
|
3149 | --- TyCon is definitely a type family
|
|
3150 | -improve_wanted_top_fun_eqs fam_tc lhs_tys rhs_ty
|
|
3151 | - | Just ops <- isBuiltInSynFamTyCon_maybe fam_tc
|
|
3152 | - = return (map snd $ tryInteractTopFam ops fam_tc lhs_tys rhs_ty)
|
|
3153 | - |
|
3154 | - -- ToDo: use ideas in #23162 for closed type families; injectivity only for open
|
|
3155 | - |
|
3156 | - -- See Note [Type inference for type families with injectivity]
|
|
3157 | - -- Open, so look for inj
|
|
3158 | - | Injective inj_args <- tyConInjectivityInfo fam_tc
|
|
3159 | - = do { fam_envs <- getFamInstEnvs
|
|
3160 | - ; top_eqns <- improve_injective_wanted_top fam_envs inj_args fam_tc lhs_tys rhs_ty
|
|
3161 | - ; let local_eqns = improve_injective_wanted_famfam inj_args fam_tc lhs_tys rhs_ty
|
|
3162 | - ; traceTcS "improve_wanted_top_fun_eqs" $
|
|
3163 | - vcat [ ppr fam_tc, text "local_eqns" <+> ppr local_eqns, text "top_eqns" <+> ppr top_eqns ]
|
|
3164 | - -- xxx ToDo: this does both local and top => bug?
|
|
3165 | - ; return (local_eqns ++ top_eqns) }
|
|
3166 | - |
|
3167 | - | otherwise -- No injectivity
|
|
3168 | - = return []
|
|
3169 | - |
|
3170 | -improve_injective_wanted_top :: FamInstEnvs -> [Bool] -> TyCon -> [TcType] -> Xi -> TcS [TypeEqn]
|
|
3171 | --- Interact with top-level instance declarations
|
|
3172 | --- See Section 5.2 in the Injective Type Families paper
|
|
3173 | -improve_injective_wanted_top fam_envs inj_args fam_tc lhs_tys rhs_ty
|
|
3174 | - = concatMapM do_one branches
|
|
3175 | - where
|
|
3176 | - branches :: [CoAxBranch]
|
|
3177 | - branches | isOpenTypeFamilyTyCon fam_tc
|
|
3178 | - , let fam_insts = lookupFamInstEnvByTyCon fam_envs fam_tc
|
|
3179 | - = concatMap (fromBranches . coAxiomBranches . fi_axiom) fam_insts
|
|
3180 | - |
|
3181 | - | Just ax <- isClosedSynFamilyTyConWithAxiom_maybe fam_tc
|
|
3182 | - = fromBranches (coAxiomBranches ax)
|
|
3183 | - |
|
3184 | - | otherwise
|
|
3185 | - = []
|
|
3186 | - |
|
3187 | - do_one :: CoAxBranch -> TcS [TypeEqn]
|
|
3188 | - do_one branch@(CoAxBranch { cab_tvs = branch_tvs, cab_lhs = branch_lhs_tys, cab_rhs = branch_rhs })
|
|
3189 | - | let in_scope1 = in_scope `extendInScopeSetList` branch_tvs
|
|
3190 | - , Just subst <- tcUnifyTyForInjectivity False in_scope1 branch_rhs rhs_ty
|
|
3191 | - -- False: matching, not unifying
|
|
3192 | - = do { let inSubst tv = tv `elemVarEnv` getTvSubstEnv subst
|
|
3193 | - unsubstTvs = filterOut inSubst branch_tvs
|
|
3194 | - -- The order of unsubstTvs is important; it must be
|
|
3195 | - -- in telescope order e.g. (k:*) (a:k)
|
|
3196 | - |
|
3197 | - ; (_subst_tvs, subst1) <- instFlexiX subst unsubstTvs
|
|
3198 | - -- If the current substitution bind [k -> *], and
|
|
3199 | - -- one of the un-substituted tyvars is (a::k), we'd better
|
|
3200 | - -- be sure to apply the current substitution to a's kind.
|
|
3201 | - -- Hence instFlexiX. #13135 was an example.
|
|
3202 | - |
|
3203 | - ; traceTcS "improve_inj_top" $
|
|
3204 | - vcat [ text "branch_rhs" <+> ppr branch_rhs
|
|
3205 | - , text "rhs_ty" <+> ppr rhs_ty
|
|
3206 | - , text "subst" <+> ppr subst
|
|
3207 | - , text "subst1" <+> ppr subst1 ]
|
|
3208 | - ; if apartnessCheck (substTys subst1 branch_lhs_tys) branch
|
|
3209 | - then do { traceTcS "improv_inj_top1" (ppr branch_lhs_tys)
|
|
3210 | - ; return (mkInjectivityEqns inj_args (map (substTy subst1) branch_lhs_tys) lhs_tys) }
|
|
3211 | - -- NB: The fresh unification variables (from unsubstTvs) are on the left
|
|
3212 | - -- See Note [Improvement orientation]
|
|
3213 | - else do { traceTcS "improve_inj_top2" empty; return [] } }
|
|
3214 | - | otherwise
|
|
3215 | - = do { traceTcS "improve_inj_top:fail" (ppr branch_rhs $$ ppr rhs_ty $$ ppr in_scope $$ ppr branch_tvs)
|
|
3216 | - ; return [] }
|
|
3217 | - |
|
3218 | - in_scope = mkInScopeSet (tyCoVarsOfType rhs_ty)
|
|
3219 | - |
|
3220 | - |
|
3221 | -improve_injective_wanted_famfam :: [Bool] -> TyCon -> [TcType] -> Xi -> [TypeEqn]
|
|
3222 | --- Interact with itself, specifically F s1 s2 ~ F t1 t2
|
|
3223 | -improve_injective_wanted_famfam inj_args fam_tc lhs_tys rhs_ty
|
|
3224 | - | Just (tc, rhs_tys) <- tcSplitTyConApp_maybe rhs_ty
|
|
3225 | - , tc == fam_tc
|
|
3226 | - = mkInjectivityEqns inj_args lhs_tys rhs_tys
|
|
3227 | - | otherwise
|
|
3228 | - = []
|
|
3229 | - |
|
3230 | -mkInjectivityEqns :: [Bool] -> [TcType] -> [TcType] -> [TypeEqn]
|
|
3231 | --- When F s1 s2 s3 ~ F t1 t2 t3, and F has injectivity info [True,False,True]
|
|
3232 | --- return the equations [Pair s1 t1, Pair s3 t3]
|
|
3233 | -mkInjectivityEqns inj_args lhs_args rhs_args
|
|
3234 | - = [ Pair lhs_arg rhs_arg | (True, lhs_arg, rhs_arg) <- zip3 inj_args lhs_args rhs_args ]
|
|
3235 | - |
|
3236 | ----------------------------------------------
|
|
3237 | -improveLocalFunEqs :: InertCans
|
|
3238 | - -> TyCon -> [TcType] -> EqCt -- F args ~ rhs
|
|
3239 | - -> TcS Bool
|
|
3240 | --- Emit equalities from interaction between two equalities
|
|
3241 | -improveLocalFunEqs inerts fam_tc args (EqCt { eq_ev = work_ev, eq_rhs = rhs })
|
|
3242 | - | isGiven work_ev = improveGivenLocalFunEqs funeqs_for_tc fam_tc args work_ev rhs
|
|
3243 | - | otherwise = improveWantedLocalFunEqs funeqs_for_tc fam_tc args work_ev rhs
|
|
3244 | - where
|
|
3245 | - funeqs = inert_funeqs inerts
|
|
3246 | - funeqs_for_tc :: [EqCt] -- Mixture of Given and Wanted
|
|
3247 | - funeqs_for_tc = [ funeq_ct | equal_ct_list <- findFunEqsByTyCon funeqs fam_tc
|
|
3248 | - , funeq_ct <- equal_ct_list
|
|
3249 | - , NomEq == eq_eq_rel funeq_ct ]
|
|
3250 | - -- Representational equalities don't interact
|
|
3251 | - -- with type family dependencies
|
|
3252 | - |
|
3253 | - |
|
3254 | -improveGivenLocalFunEqs :: [EqCt] -- Inert items, mixture of Given and Wanted
|
|
3255 | - -> TyCon -> [TcType] -> CtEvidence -> Xi -- Work item (Given)
|
|
3256 | - -> TcS Bool -- Always False (no unifications)
|
|
3257 | --- Emit equalities from interaction between two Given type-family equalities
|
|
3258 | --- e.g. (x+y1~z, x+y2~z) => (y1 ~ y2)
|
|
3259 | -improveGivenLocalFunEqs funeqs_for_tc fam_tc work_args work_ev work_rhs
|
|
3260 | - | Just ops <- isBuiltInSynFamTyCon_maybe fam_tc
|
|
3261 | - = do { mapM_ (do_one ops) funeqs_for_tc
|
|
3262 | - ; return False } -- False: no unifications
|
|
3263 | - | otherwise
|
|
3264 | - = return False
|
|
3265 | - where
|
|
3266 | - given_co :: Coercion = ctEvCoercion work_ev
|
|
3267 | - |
|
3268 | - do_one :: BuiltInSynFamily -> EqCt -> TcS ()
|
|
3269 | - -- Used only work-item is Given
|
|
3270 | - do_one ops EqCt { eq_ev = inert_ev, eq_lhs = inert_lhs, eq_rhs = inert_rhs }
|
|
3271 | - | isGiven inert_ev -- Given/Given interaction
|
|
3272 | - , TyFamLHS _ inert_args <- inert_lhs -- Inert item is F inert_args ~ inert_rhs
|
|
3273 | - , work_rhs `tcEqType` inert_rhs -- Both RHSs are the same
|
|
3274 | - , -- So we have work_ev : F work_args ~ rhs
|
|
3275 | - -- inert_ev : F inert_args ~ rhs
|
|
3276 | - let pairs :: [(CoAxiomRule, TypeEqn)]
|
|
3277 | - pairs = tryInteractInertFam ops fam_tc work_args inert_args
|
|
3278 | - , not (null pairs)
|
|
3279 | - = do { traceTcS "improveGivenLocalFunEqs" (vcat[ ppr fam_tc <+> ppr work_args
|
|
3280 | - , text "work_ev" <+> ppr work_ev
|
|
3281 | - , text "inert_ev" <+> ppr inert_ev
|
|
3282 | - , ppr work_rhs
|
|
3283 | - , ppr pairs ])
|
|
3284 | - ; emitNewGivens (ctEvLoc inert_ev) (map mk_ax_co pairs) }
|
|
3285 | - -- This CtLoc for the new Givens doesn't reflect the
|
|
3286 | - -- fact that it's a combination of Givens, but I don't
|
|
3287 | - -- this that matters.
|
|
3288 | - where
|
|
3289 | - inert_co = ctEvCoercion inert_ev
|
|
3290 | - mk_ax_co (ax,_) = (Nominal, mkAxiomCo ax [combined_co])
|
|
3291 | - where
|
|
3292 | - combined_co = given_co `mkTransCo` mkSymCo inert_co
|
|
3293 | - -- given_co :: F work_args ~ rhs
|
|
3294 | - -- inert_co :: F inert_args ~ rhs
|
|
3295 | - -- the_co :: F work_args ~ F inert_args
|
|
3296 | - |
|
3297 | - do_one _ _ = return ()
|
|
3298 | - |
|
3299 | -improveWantedLocalFunEqs
|
|
3300 | - :: [EqCt] -- Inert items (Given and Wanted)
|
|
3301 | - -> TyCon -> [TcType] -> CtEvidence -> Xi -- Work item (Wanted)
|
|
3302 | - -> TcS Bool -- True <=> some unifications
|
|
3303 | --- Emit improvement equalities for a Wanted constraint, by comparing
|
|
3304 | --- the current work item with inert CFunEqs (both Given and Wanted)
|
|
3305 | --- E.g. x + y ~ z, x + y' ~ z => [W] y ~ y'
|
|
3306 | ---
|
|
3307 | --- See Note [FunDep and implicit parameter reactions]
|
|
3308 | -improveWantedLocalFunEqs funeqs_for_tc fam_tc args work_ev rhs
|
|
3309 | - | null improvement_eqns
|
|
3310 | - = return False
|
|
3311 | - | otherwise
|
|
3312 | - = do { traceTcS "interactFunEq improvements: " $
|
|
3313 | - vcat [ text "Eqns:" <+> ppr improvement_eqns
|
|
3314 | - , text "Candidates:" <+> ppr funeqs_for_tc ]
|
|
3315 | - ; unifyAndEmitFunDepWanteds work_ev improvement_eqns }
|
|
3316 | - where
|
|
3317 | - work_loc = ctEvLoc work_ev
|
|
3318 | - work_pred = ctEvPred work_ev
|
|
3319 | - fam_inj_info = tyConInjectivityInfo fam_tc
|
|
3320 | - |
|
3321 | - --------------------
|
|
3322 | - improvement_eqns :: [FunDepEqn (CtLoc, RewriterSet)]
|
|
3323 | - improvement_eqns
|
|
3324 | - | Just ops <- isBuiltInSynFamTyCon_maybe fam_tc
|
|
3325 | - = -- Try built-in families, notably for arithmethic
|
|
3326 | - concatMap (do_one_built_in ops rhs) funeqs_for_tc
|
|
3327 | - |
|
3328 | - | Injective injective_args <- fam_inj_info
|
|
3329 | - = -- Try improvement from type families with injectivity annotations
|
|
3330 | - concatMap (do_one_injective injective_args rhs) funeqs_for_tc
|
|
3331 | - |
|
3332 | - | otherwise
|
|
3333 | - = []
|
|
3334 | - |
|
3335 | - --------------------
|
|
3336 | - do_one_built_in ops rhs (EqCt { eq_lhs = TyFamLHS _ iargs, eq_rhs = irhs, eq_ev = inert_ev })
|
|
3337 | - | irhs `tcEqType` rhs
|
|
3338 | - = mk_fd_eqns inert_ev (map snd $ tryInteractInertFam ops fam_tc args iargs)
|
|
3339 | - | otherwise
|
|
3340 | - = []
|
|
3341 | - do_one_built_in _ _ _ = pprPanic "interactFunEq 1" (ppr fam_tc) -- TyVarLHS
|
|
3342 | - |
|
3343 | - --------------------
|
|
3344 | - -- See Note [Type inference for type families with injectivity]
|
|
3345 | - do_one_injective inj_args rhs (EqCt { eq_lhs = TyFamLHS _ inert_args
|
|
3346 | - , eq_rhs = irhs, eq_ev = inert_ev })
|
|
3347 | - | rhs `tcEqType` irhs
|
|
3348 | - = mk_fd_eqns inert_ev $ mkInjectivityEqns inj_args args inert_args
|
|
3349 | - | otherwise
|
|
3350 | - = []
|
|
3351 | - |
|
3352 | - do_one_injective _ _ _ = pprPanic "interactFunEq 2" (ppr fam_tc) -- TyVarLHS
|
|
3353 | - |
|
3354 | - --------------------
|
|
3355 | - mk_fd_eqns :: CtEvidence -> [TypeEqn] -> [FunDepEqn (CtLoc, RewriterSet)]
|
|
3356 | - mk_fd_eqns inert_ev eqns
|
|
3357 | - | null eqns = []
|
|
3358 | - | otherwise = [ FDEqn { fd_qtvs = [], fd_eqs = eqns
|
|
3359 | - , fd_loc = (loc, inert_rewriters) } ]
|
|
3360 | - where
|
|
3361 | - initial_loc -- start with the location of the Wanted involved
|
|
3362 | - | isGiven work_ev = inert_loc
|
|
3363 | - | otherwise = work_loc
|
|
3364 | - eqn_orig = InjTFOrigin1 work_pred (ctLocOrigin work_loc) (ctLocSpan work_loc)
|
|
3365 | - inert_pred (ctLocOrigin inert_loc) (ctLocSpan inert_loc)
|
|
3366 | - eqn_loc = setCtLocOrigin initial_loc eqn_orig
|
|
3367 | - inert_pred = ctEvPred inert_ev
|
|
3368 | - inert_loc = ctEvLoc inert_ev
|
|
3369 | - inert_rewriters = ctEvRewriters inert_ev
|
|
3370 | - loc = eqn_loc { ctl_depth = ctl_depth inert_loc `maxSubGoalDepth`
|
|
3371 | - ctl_depth work_loc }
|
|
3372 | - |
|
3373 | -{- Note [Type inference for type families with injectivity]
|
|
3374 | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
3375 | -Suppose we have a type family with an injectivity annotation:
|
|
3376 | - type family F a b = r | r -> b
|
|
3377 | - |
|
3378 | -Then if we have an equality like F s1 t1 ~ F s2 t2,
|
|
3379 | -we can use the injectivity to get a new Wanted constraint on
|
|
3380 | -the injective argument
|
|
3381 | - [W] t1 ~ t2
|
|
3382 | - |
|
3383 | -That in turn can help GHC solve constraints that would otherwise require
|
|
3384 | -guessing. For example, consider the ambiguity check for
|
|
3385 | - f :: F Int b -> Int
|
|
3386 | -We get the constraint
|
|
3387 | - [W] F Int b ~ F Int beta
|
|
3388 | -where beta is a unification variable. Injectivity lets us pick beta ~ b.
|
|
3389 | - |
|
3390 | -Injectivity information is also used at the call sites. For example:
|
|
3391 | - g = f True
|
|
3392 | -gives rise to
|
|
3393 | - [W] F Int b ~ Bool
|
|
3394 | -from which we can derive b. This requires looking at the defining equations of
|
|
3395 | -a type family, ie. finding equation with a matching RHS (Bool in this example)
|
|
3396 | -and inferring values of type variables (b in this example) from the LHS patterns
|
|
3397 | -of the matching equation. For closed type families we have to perform
|
|
3398 | -additional apartness check for the selected equation to check that the selected
|
|
3399 | -is guaranteed to fire for given LHS arguments.
|
|
3400 | - |
|
3401 | -These new constraints are Wanted constraints, but we will not use the evidence.
|
|
3402 | -We could go further and offer evidence from decomposing injective type-function
|
|
3403 | -applications, but that would require new evidence forms, and an extension to
|
|
3404 | -FC, so we don't do that right now (Dec 14).
|
|
3405 | - |
|
3406 | -We generate these Wanteds in three places, depending on how we notice the
|
|
3407 | -injectivity.
|
|
3408 | - |
|
3409 | -1. When we have a [W] F tys1 ~ F tys2. This is handled in canEqCanLHS2, and
|
|
3410 | -described in Note [Decomposing type family applications] in GHC.Tc.Solver.Equality
|
|
3411 | - |
|
3412 | -2. When we have [W] F tys1 ~ T and [W] F tys2 ~ T. Note that neither of these
|
|
3413 | -constraints rewrites the other, as they have different LHSs. This is done
|
|
3414 | -in improveLocalFunEqs, called during the interactWithInertsStage.
|
|
3415 | - |
|
3416 | -3. When we have [W] F tys ~ T and an equation for F that looks like F tys' = T.
|
|
3417 | -This is done in improve_top_fun_eqs, called from the top-level reactions stage.
|
|
3418 | - |
|
3419 | -See also Note [Injective type families] in GHC.Core.TyCon
|
|
3420 | - |
|
3421 | -Note [Cache-caused loops]
|
|
3422 | -~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
3423 | -It is very dangerous to cache a rewritten wanted family equation as 'solved' in our
|
|
3424 | -solved cache (which is the default behaviour or xCtEvidence), because the interaction
|
|
3425 | -may not be contributing towards a solution. Here is an example:
|
|
3426 | - |
|
3427 | -Initial inert set:
|
|
3428 | - [W] g1 : F a ~ beta1
|
|
3429 | -Work item:
|
|
3430 | - [W] g2 : F a ~ beta2
|
|
3431 | -The work item will react with the inert yielding the _same_ inert set plus:
|
|
3432 | - (i) Will set g2 := g1 `cast` g3
|
|
3433 | - (ii) Will add to our solved cache that [S] g2 : F a ~ beta2
|
|
3434 | - (iii) Will emit [W] g3 : beta1 ~ beta2
|
|
3435 | -Now, the g3 work item will be spontaneously solved to [G] g3 : beta1 ~ beta2
|
|
3436 | -and then it will react the item in the inert ([W] g1 : F a ~ beta1). So it
|
|
3437 | -will set
|
|
3438 | - g1 := g ; sym g3
|
|
3439 | -and what is g? Well it would ideally be a new goal of type (F a ~ beta2) but
|
|
3440 | -remember that we have this in our solved cache, and it is ... g2! In short we
|
|
3441 | -created the evidence loop:
|
|
3442 | - |
|
3443 | - g2 := g1 ; g3
|
|
3444 | - g3 := refl
|
|
3445 | - g1 := g2 ; sym g3
|
|
3446 | - |
|
3447 | -To avoid this situation we do not cache as solved any workitems (or inert)
|
|
3448 | -which did not really made a 'step' towards proving some goal. Solved's are
|
|
3449 | -just an optimization so we don't lose anything in terms of completeness of
|
|
3450 | -solving.
|
|
3451 | --} |
... | ... | @@ -4,7 +4,8 @@ |
4 | 4 | -- | Solving Class constraints CDictCan
|
5 | 5 | module GHC.Tc.Solver.FunDeps (
|
6 | 6 | unifyAndEmitFunDepWanteds,
|
7 | - doDictFunDepImprovement,
|
|
7 | + tryDictFunDeps,
|
|
8 | + tryEqFunDeps
|
|
8 | 9 | ) where
|
9 | 10 | |
10 | 11 | import GHC.Prelude
|
... | ... | @@ -12,25 +13,34 @@ import GHC.Prelude |
12 | 13 | import {-# SOURCE #-} GHC.Tc.Solver.Solve( solveSimpleWanteds )
|
13 | 14 | |
14 | 15 | import GHC.Tc.Instance.FunDeps
|
15 | -import GHC.Tc.Types.Evidence
|
|
16 | -import GHC.Tc.Types.Constraint
|
|
17 | -import GHC.Tc.Types.CtLoc
|
|
18 | -import GHC.Tc.Types.Origin
|
|
19 | 16 | import GHC.Tc.Solver.InertSet
|
20 | 17 | import GHC.Tc.Solver.Monad
|
21 | 18 | import GHC.Tc.Solver.Types
|
22 | 19 | import GHC.Tc.Utils.TcType
|
23 | 20 | import GHC.Tc.Utils.Unify( UnifyEnv(..) )
|
24 | 21 | import GHC.Tc.Utils.Monad as TcM
|
22 | +import GHC.Tc.Types.Evidence
|
|
23 | +import GHC.Tc.Types.Constraint
|
|
24 | +import GHC.Tc.Types.CtLoc
|
|
25 | +import GHC.Tc.Types.Origin
|
|
25 | 26 | |
26 | 27 | import GHC.Core.Type
|
27 | -import GHC.Core.InstEnv ( ClsInst(..) )
|
|
28 | -import GHC.Core.Coercion.Axiom( TypeEqn )
|
|
29 | - |
|
28 | +import GHC.Core.FamInstEnv
|
|
29 | +import GHC.Core.Coercion
|
|
30 | +import GHC.Core.Predicate( EqRel(..) )
|
|
31 | +import GHC.Core.TyCon
|
|
32 | +import GHC.Core.Unify( tcUnifyTyForInjectivity )
|
|
33 | +import GHC.Core.InstEnv( ClsInst(..) )
|
|
34 | +import GHC.Core.Coercion.Axiom
|
|
35 | + |
|
36 | +import GHC.Builtin.Types.Literals( tryInteractTopFam, tryInteractInertFam )
|
|
30 | 37 | import GHC.Types.Name
|
31 | 38 | import GHC.Types.Var.Set
|
39 | +import GHC.Types.Var.Env
|
|
32 | 40 | |
33 | 41 | import GHC.Utils.Outputable
|
42 | +import GHC.Utils.Panic
|
|
43 | +import GHC.Utils.Misc( filterOut )
|
|
34 | 44 | |
35 | 45 | import GHC.Data.Bag
|
36 | 46 | import GHC.Data.Pair
|
... | ... | @@ -41,7 +51,7 @@ import Control.Monad |
41 | 51 | |
42 | 52 | {- *********************************************************************
|
43 | 53 | * *
|
44 | -* Functional dependencies, instantiation of equations
|
|
54 | +* Functional dependencies for dictionaries
|
|
45 | 55 | * *
|
46 | 56 | ************************************************************************
|
47 | 57 | |
... | ... | @@ -296,24 +306,24 @@ as the fundeps. |
296 | 306 | #7875 is a case in point.
|
297 | 307 | -}
|
298 | 308 | |
299 | -doDictFunDepImprovement :: DictCt -> SolverStage ()
|
|
300 | --- (doDictFunDepImprovement inst_envs cts)
|
|
309 | +tryDictFunDeps :: DictCt -> SolverStage ()
|
|
310 | +-- (tryDictFunDeps inst_envs cts)
|
|
301 | 311 | -- * Generate the fundeps from interacting the
|
302 | 312 | -- top-level `inst_envs` with the constraints `cts`
|
303 | 313 | -- * Do the unifications and return any unsolved constraints
|
304 | 314 | -- See Note [Fundeps with instances, and equality orientation]
|
305 | 315 | |
306 | --- doLocalFunDepImprovement does StartAgain if there
|
|
316 | +-- doLocalFunDeps does StartAgain if there
|
|
307 | 317 | -- are any fundeps: see (DFL1) in Note [Do fundeps last]
|
308 | 318 | |
309 | -doDictFunDepImprovement dict_ct
|
|
310 | - = do { doDictFunDepImprovementLocal dict_ct
|
|
311 | - ; doDictFunDepImprovementTop dict_ct }
|
|
319 | +tryDictFunDeps dict_ct
|
|
320 | + = do { tryDictFunDepsLocal dict_ct
|
|
321 | + ; tryDictFunDepsTop dict_ct }
|
|
312 | 322 | |
313 | -doDictFunDepImprovementLocal :: DictCt -> SolverStage ()
|
|
323 | +tryDictFunDepsLocal :: DictCt -> SolverStage ()
|
|
314 | 324 | -- Using functional dependencies, interact the DictCt with the
|
315 | 325 | -- inert Givens and Wanteds, to produce new equalities
|
316 | -doDictFunDepImprovementLocal dict_ct@(DictCt { di_cls = cls, di_ev = work_ev })
|
|
326 | +tryDictFunDepsLocal dict_ct@(DictCt { di_cls = cls, di_ev = work_ev })
|
|
317 | 327 | | isGiven work_ev
|
318 | 328 | = -- If work_ev is Given, there could in principle be some inert Wanteds
|
319 | 329 | -- but in practice there never are because we solve Givens first
|
... | ... | @@ -323,11 +333,11 @@ doDictFunDepImprovementLocal dict_ct@(DictCt { di_cls = cls, di_ev = work_ev }) |
323 | 333 | = Stage $
|
324 | 334 | do { inerts <- getInertCans
|
325 | 335 | |
326 | - ; traceTcS "doDictFunDepImprovementLocal {" (ppr dict_ct)
|
|
336 | + ; traceTcS "tryDictFunDepsLocal {" (ppr dict_ct)
|
|
327 | 337 | ; imp <- solveFunDeps $
|
328 | 338 | foldM do_interaction emptyCts $
|
329 | 339 | findDictsByClass (inert_dicts inerts) cls
|
330 | - ; traceTcS "doDictFunDepImprovementLocal }" (text "imp =" <+> ppr imp)
|
|
340 | + ; traceTcS "tryDictFunDepsLocal }" (text "imp =" <+> ppr imp)
|
|
331 | 341 | |
332 | 342 | ; if imp then startAgainWith (CDictCan dict_ct)
|
333 | 343 | else continueWith () }
|
... | ... | @@ -350,7 +360,7 @@ doDictFunDepImprovementLocal dict_ct@(DictCt { di_cls = cls, di_ev = work_ev }) |
350 | 360 | improveFromAnother (deriv_loc, inert_rewriters)
|
351 | 361 | inert_pred work_pred
|
352 | 362 | |
353 | - ; traceTcS "doDictFunDepImprovementLocal item" $
|
|
363 | + ; traceTcS "tryDictFunDepsLocal item" $
|
|
354 | 364 | vcat [ ppr work_ev, ppr new_eqs2 ]
|
355 | 365 | |
356 | 366 | ; return (new_eqs1 `unionBags` new_eqs2) }
|
... | ... | @@ -369,17 +379,17 @@ doDictFunDepImprovementLocal dict_ct@(DictCt { di_cls = cls, di_ev = work_ev }) |
369 | 379 | (ctLocOrigin inert_loc)
|
370 | 380 | (ctLocSpan inert_loc)
|
371 | 381 | |
372 | -doDictFunDepImprovementTop :: DictCt -> SolverStage ()
|
|
373 | -doDictFunDepImprovementTop dict_ct@(DictCt { di_ev = ev, di_cls = cls, di_tys = xis })
|
|
382 | +tryDictFunDepsTop :: DictCt -> SolverStage ()
|
|
383 | +tryDictFunDepsTop dict_ct@(DictCt { di_ev = ev, di_cls = cls, di_tys = xis })
|
|
374 | 384 | = Stage $
|
375 | 385 | do { inst_envs <- getInstEnvs
|
376 | 386 | |
377 | - ; traceTcS "doDictFunDepImprovementTop {" (ppr dict_ct)
|
|
387 | + ; traceTcS "tryDictFunDepsTop {" (ppr dict_ct)
|
|
378 | 388 | ; let eqns :: [FunDepEqn (CtLoc, RewriterSet)]
|
379 | 389 | eqns = improveFromInstEnv inst_envs mk_ct_loc cls xis
|
380 | 390 | ; imp <- solveFunDeps $
|
381 | 391 | unifyFunDepWanteds_new ev eqns
|
382 | - ; traceTcS "doDictFunDepImprovementTop }" (text "imp =" <+> ppr imp)
|
|
392 | + ; traceTcS "tryDictFunDepsTop }" (text "imp =" <+> ppr imp)
|
|
383 | 393 | |
384 | 394 | ; if imp then startAgainWith (CDictCan dict_ct)
|
385 | 395 | else continueWith () }
|
... | ... | @@ -469,6 +479,464 @@ The bottom line: since we have no evidence for them, we should ignore Given/Give |
469 | 479 | and Given/instance fundeps entirely.
|
470 | 480 | -}
|
471 | 481 | |
482 | + |
|
483 | + |
|
484 | +{-
|
|
485 | +**********************************************************************
|
|
486 | +* *
|
|
487 | + Functional dependencies for type families
|
|
488 | +* *
|
|
489 | +**********************************************************************
|
|
490 | + |
|
491 | +Note [Reverse order of fundep equations]
|
|
492 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
493 | +Consider this scenario (from dependent/should_fail/T13135_simple):
|
|
494 | + |
|
495 | + type Sig :: Type -> Type
|
|
496 | + data Sig a = SigFun a (Sig a)
|
|
497 | + |
|
498 | + type SmartFun :: forall (t :: Type). Sig t -> Type
|
|
499 | + type family SmartFun sig = r | r -> sig where
|
|
500 | + SmartFun @Type (SigFun @Type a sig) = a -> SmartFun @Type sig
|
|
501 | + |
|
502 | + [W] SmartFun @kappa sigma ~ (Int -> Bool)
|
|
503 | + |
|
504 | +The injectivity of SmartFun allows us to produce two new equalities:
|
|
505 | + |
|
506 | + [W] w1 :: Type ~ kappa
|
|
507 | + [W] w2 :: SigFun @Type Int beta ~ sigma
|
|
508 | + |
|
509 | +for some fresh (beta :: SigType). The second Wanted here is actually
|
|
510 | +heterogeneous: the LHS has type Sig Type while the RHS has type Sig kappa.
|
|
511 | +Of course, if we solve the first wanted first, the second becomes homogeneous.
|
|
512 | + |
|
513 | +When looking for injectivity-inspired equalities, we work left-to-right,
|
|
514 | +producing the two equalities in the order written above. However, these
|
|
515 | +equalities are then passed into wrapUnifierTcS, which will fail, adding these
|
|
516 | +to the work list. However, crucially, the work list operates like a *stack*.
|
|
517 | +So, because we add w1 and then w2, we process w2 first. This is silly: solving
|
|
518 | +w1 would unlock w2. So we make sure to add equalities to the work
|
|
519 | +list in left-to-right order, which requires a few key calls to 'reverse'.
|
|
520 | + |
|
521 | +This treatment is also used for class-based functional dependencies, although
|
|
522 | +we do not have a program yet known to exhibit a loop there. It just seems
|
|
523 | +like the right thing to do.
|
|
524 | + |
|
525 | +When this was originally conceived, it was necessary to avoid a loop in T13135.
|
|
526 | +That loop is now avoided by continuing with the kind equality (not the type
|
|
527 | +equality) in canEqCanLHSHetero (see Note [Equalities with heterogeneous kinds]).
|
|
528 | +However, the idea of working left-to-right still seems worthwhile, and so the calls
|
|
529 | +to 'reverse' remain.
|
|
530 | + |
|
531 | +Note [Improvement orientation]
|
|
532 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
533 | +See also Note [Fundeps with instances, and equality orientation], which describes
|
|
534 | +the Exact Same Problem, with the same solution, but for functional dependencies.
|
|
535 | + |
|
536 | +A very delicate point is the orientation of equalities
|
|
537 | +arising from injectivity improvement (#12522). Suppose we have
|
|
538 | + type family F x = t | t -> x
|
|
539 | + type instance F (a, Int) = (Int, G a)
|
|
540 | +where G is injective; and wanted constraints
|
|
541 | + |
|
542 | + [W] F (alpha, beta) ~ (Int, <some type>)
|
|
543 | + |
|
544 | +The injectivity will give rise to constraints
|
|
545 | + |
|
546 | + [W] gamma1 ~ alpha
|
|
547 | + [W] Int ~ beta
|
|
548 | + |
|
549 | +The fresh unification variable gamma1 comes from the fact that we
|
|
550 | +can only do "partial improvement" here; see Section 5.2 of
|
|
551 | +"Injective type families for Haskell" (HS'15).
|
|
552 | + |
|
553 | +Now, it's very important to orient the equations this way round,
|
|
554 | +so that the fresh unification variable will be eliminated in
|
|
555 | +favour of alpha. If we instead had
|
|
556 | + [W] alpha ~ gamma1
|
|
557 | +then we would unify alpha := gamma1; and kick out the wanted
|
|
558 | +constraint. But when we substitute it back in, it'd look like
|
|
559 | + [W] F (gamma1, beta) ~ fuv
|
|
560 | +and exactly the same thing would happen again! Infinite loop.
|
|
561 | + |
|
562 | +---> ToDo: all this fragility has gone away! Fix the Note! <---
|
|
563 | + |
|
564 | +This all seems fragile, and it might seem more robust to avoid
|
|
565 | +introducing gamma1 in the first place, in the case where the
|
|
566 | +actual argument (alpha, beta) partly matches the improvement
|
|
567 | +template. But that's a bit tricky, esp when we remember that the
|
|
568 | +kinds much match too; so it's easier to let the normal machinery
|
|
569 | +handle it. Instead we are careful to orient the new
|
|
570 | +equality with the template on the left. Delicate, but it works.
|
|
571 | + |
|
572 | +-}
|
|
573 | + |
|
574 | +--------------------
|
|
575 | +tryEqFunDeps :: EqCt -> SolverStage ()
|
|
576 | +tryEqFunDeps work_item@(EqCt { eq_lhs = lhs, eq_eq_rel = eq_rel })
|
|
577 | + | NomEq <- eq_rel
|
|
578 | + , TyFamLHS tc args <- lhs
|
|
579 | + = do { improveLocalFunEqs tc args work_item
|
|
580 | + ; improveTopFunEqs tc args work_item }
|
|
581 | + | otherwise
|
|
582 | + = nopStage ()
|
|
583 | + |
|
584 | +--------------------
|
|
585 | +improveTopFunEqs :: TyCon -> [TcType] -> EqCt -> SolverStage ()
|
|
586 | +-- TyCon is definitely a type family
|
|
587 | +-- See Note [FunDep and implicit parameter reactions]
|
|
588 | +improveTopFunEqs fam_tc args eq_ct@(EqCt { eq_ev = ev, eq_rhs = rhs_ty })
|
|
589 | + = Stage $
|
|
590 | + do { imp <- if isGiven ev
|
|
591 | + then improveGivenTopFunEqs fam_tc args ev rhs_ty
|
|
592 | + else improveWantedTopFunEqs fam_tc args ev rhs_ty
|
|
593 | + ; if imp then startAgainWith (CEqCan eq_ct)
|
|
594 | + else continueWith () }
|
|
595 | + |
|
596 | +improveGivenTopFunEqs :: TyCon -> [TcType] -> CtEvidence -> Xi -> TcS Bool
|
|
597 | +-- TyCon is definitely a type family
|
|
598 | +-- Work-item is a Given
|
|
599 | +improveGivenTopFunEqs fam_tc args ev rhs_ty
|
|
600 | + | Just ops <- isBuiltInSynFamTyCon_maybe fam_tc
|
|
601 | + = do { traceTcS "improveGivenTopFunEqs" (ppr fam_tc <+> ppr args $$ ppr ev $$ ppr rhs_ty)
|
|
602 | + ; emitNewGivens (ctEvLoc ev) $
|
|
603 | + [ (Nominal, new_co)
|
|
604 | + | (ax, _) <- tryInteractTopFam ops fam_tc args rhs_ty
|
|
605 | + , let new_co = mkAxiomCo ax [given_co] ]
|
|
606 | + ; return False } -- False: no unifications
|
|
607 | + | otherwise
|
|
608 | + = return False
|
|
609 | + where
|
|
610 | + given_co :: Coercion = ctEvCoercion ev
|
|
611 | + |
|
612 | +improveWantedTopFunEqs :: TyCon -> [TcType] -> CtEvidence -> Xi -> TcS Bool
|
|
613 | +-- TyCon is definitely a type family
|
|
614 | +-- Work-item is a Wanted
|
|
615 | +improveWantedTopFunEqs fam_tc args ev rhs_ty
|
|
616 | + = do { eqns <- improve_wanted_top_fun_eqs fam_tc args rhs_ty
|
|
617 | + ; traceTcS "improveTopFunEqs" (vcat [ text "lhs:" <+> ppr fam_tc <+> ppr args
|
|
618 | + , text "rhs:" <+> ppr rhs_ty
|
|
619 | + , text "eqns:" <+> ppr eqns ])
|
|
620 | + ; unifyFunDeps ev Nominal $ \uenv ->
|
|
621 | + uPairsTcM (bump_depth uenv) (reverse eqns) }
|
|
622 | + -- Missing that `reverse` causes T13135 and T13135_simple to loop.
|
|
623 | + -- See Note [Reverse order of fundep equations]
|
|
624 | + |
|
625 | + where
|
|
626 | + bump_depth env = env { u_loc = bumpCtLocDepth (u_loc env) }
|
|
627 | + -- ToDo: this location is wrong; it should be FunDepOrigin2
|
|
628 | + -- See #14778
|
|
629 | + |
|
630 | +improve_wanted_top_fun_eqs :: TyCon -> [TcType] -> Xi
|
|
631 | + -> TcS [TypeEqn]
|
|
632 | +-- TyCon is definitely a type family
|
|
633 | +improve_wanted_top_fun_eqs fam_tc lhs_tys rhs_ty
|
|
634 | + | Just ops <- isBuiltInSynFamTyCon_maybe fam_tc
|
|
635 | + = return (map snd $ tryInteractTopFam ops fam_tc lhs_tys rhs_ty)
|
|
636 | + |
|
637 | + -- ToDo: use ideas in #23162 for closed type families; injectivity only for open
|
|
638 | + |
|
639 | + -- See Note [Type inference for type families with injectivity]
|
|
640 | + -- Open, so look for inj
|
|
641 | + | Injective inj_args <- tyConInjectivityInfo fam_tc
|
|
642 | + = do { fam_envs <- getFamInstEnvs
|
|
643 | + ; top_eqns <- improve_injective_wanted_top fam_envs inj_args fam_tc lhs_tys rhs_ty
|
|
644 | + ; let local_eqns = improve_injective_wanted_famfam inj_args fam_tc lhs_tys rhs_ty
|
|
645 | + ; traceTcS "improve_wanted_top_fun_eqs" $
|
|
646 | + vcat [ ppr fam_tc, text "local_eqns" <+> ppr local_eqns, text "top_eqns" <+> ppr top_eqns ]
|
|
647 | + -- xxx ToDo: this does both local and top => bug?
|
|
648 | + ; return (local_eqns ++ top_eqns) }
|
|
649 | + |
|
650 | + | otherwise -- No injectivity
|
|
651 | + = return []
|
|
652 | + |
|
653 | +improve_injective_wanted_top :: FamInstEnvs -> [Bool] -> TyCon -> [TcType] -> Xi -> TcS [TypeEqn]
|
|
654 | +-- Interact with top-level instance declarations
|
|
655 | +-- See Section 5.2 in the Injective Type Families paper
|
|
656 | +improve_injective_wanted_top fam_envs inj_args fam_tc lhs_tys rhs_ty
|
|
657 | + = concatMapM do_one branches
|
|
658 | + where
|
|
659 | + branches :: [CoAxBranch]
|
|
660 | + branches | isOpenTypeFamilyTyCon fam_tc
|
|
661 | + , let fam_insts = lookupFamInstEnvByTyCon fam_envs fam_tc
|
|
662 | + = concatMap (fromBranches . coAxiomBranches . fi_axiom) fam_insts
|
|
663 | + |
|
664 | + | Just ax <- isClosedSynFamilyTyConWithAxiom_maybe fam_tc
|
|
665 | + = fromBranches (coAxiomBranches ax)
|
|
666 | + |
|
667 | + | otherwise
|
|
668 | + = []
|
|
669 | + |
|
670 | + do_one :: CoAxBranch -> TcS [TypeEqn]
|
|
671 | + do_one branch@(CoAxBranch { cab_tvs = branch_tvs, cab_lhs = branch_lhs_tys, cab_rhs = branch_rhs })
|
|
672 | + | let in_scope1 = in_scope `extendInScopeSetList` branch_tvs
|
|
673 | + , Just subst <- tcUnifyTyForInjectivity False in_scope1 branch_rhs rhs_ty
|
|
674 | + -- False: matching, not unifying
|
|
675 | + = do { let inSubst tv = tv `elemVarEnv` getTvSubstEnv subst
|
|
676 | + unsubstTvs = filterOut inSubst branch_tvs
|
|
677 | + -- The order of unsubstTvs is important; it must be
|
|
678 | + -- in telescope order e.g. (k:*) (a:k)
|
|
679 | + |
|
680 | + ; (_subst_tvs, subst1) <- instFlexiX subst unsubstTvs
|
|
681 | + -- If the current substitution bind [k -> *], and
|
|
682 | + -- one of the un-substituted tyvars is (a::k), we'd better
|
|
683 | + -- be sure to apply the current substitution to a's kind.
|
|
684 | + -- Hence instFlexiX. #13135 was an example.
|
|
685 | + |
|
686 | + ; traceTcS "improve_inj_top" $
|
|
687 | + vcat [ text "branch_rhs" <+> ppr branch_rhs
|
|
688 | + , text "rhs_ty" <+> ppr rhs_ty
|
|
689 | + , text "subst" <+> ppr subst
|
|
690 | + , text "subst1" <+> ppr subst1 ]
|
|
691 | + ; if apartnessCheck (substTys subst1 branch_lhs_tys) branch
|
|
692 | + then do { traceTcS "improv_inj_top1" (ppr branch_lhs_tys)
|
|
693 | + ; return (mkInjectivityEqns inj_args (map (substTy subst1) branch_lhs_tys) lhs_tys) }
|
|
694 | + -- NB: The fresh unification variables (from unsubstTvs) are on the left
|
|
695 | + -- See Note [Improvement orientation]
|
|
696 | + else do { traceTcS "improve_inj_top2" empty; return [] } }
|
|
697 | + | otherwise
|
|
698 | + = do { traceTcS "improve_inj_top:fail" (ppr branch_rhs $$ ppr rhs_ty $$ ppr in_scope $$ ppr branch_tvs)
|
|
699 | + ; return [] }
|
|
700 | + |
|
701 | + in_scope = mkInScopeSet (tyCoVarsOfType rhs_ty)
|
|
702 | + |
|
703 | + |
|
704 | +improve_injective_wanted_famfam :: [Bool] -> TyCon -> [TcType] -> Xi -> [TypeEqn]
|
|
705 | +-- Interact with itself, specifically F s1 s2 ~ F t1 t2
|
|
706 | +improve_injective_wanted_famfam inj_args fam_tc lhs_tys rhs_ty
|
|
707 | + | Just (tc, rhs_tys) <- tcSplitTyConApp_maybe rhs_ty
|
|
708 | + , tc == fam_tc
|
|
709 | + = mkInjectivityEqns inj_args lhs_tys rhs_tys
|
|
710 | + | otherwise
|
|
711 | + = []
|
|
712 | + |
|
713 | +mkInjectivityEqns :: [Bool] -> [TcType] -> [TcType] -> [TypeEqn]
|
|
714 | +-- When F s1 s2 s3 ~ F t1 t2 t3, and F has injectivity info [True,False,True]
|
|
715 | +-- return the equations [Pair s1 t1, Pair s3 t3]
|
|
716 | +mkInjectivityEqns inj_args lhs_args rhs_args
|
|
717 | + = [ Pair lhs_arg rhs_arg | (True, lhs_arg, rhs_arg) <- zip3 inj_args lhs_args rhs_args ]
|
|
718 | + |
|
719 | +---------------------------------------------
|
|
720 | +improveLocalFunEqs :: TyCon -> [TcType] -> EqCt -- F args ~ rhs
|
|
721 | + -> SolverStage ()
|
|
722 | +-- Emit equalities from interaction between two equalities
|
|
723 | +improveLocalFunEqs fam_tc args eq_ct@(EqCt { eq_ev = work_ev, eq_rhs = rhs })
|
|
724 | + = Stage $
|
|
725 | + do { inerts <- getInertCans
|
|
726 | + ; let my_funeqs = get_my_funeqs inerts
|
|
727 | + ; imp <- if isGiven work_ev
|
|
728 | + then improveGivenLocalFunEqs my_funeqs fam_tc args work_ev rhs
|
|
729 | + else improveWantedLocalFunEqs my_funeqs fam_tc args work_ev rhs
|
|
730 | + ; if imp then startAgainWith (CEqCan eq_ct)
|
|
731 | + else continueWith () }
|
|
732 | + where
|
|
733 | + get_my_funeqs :: InertCans -> [EqCt] -- Mixture of Given and Wanted
|
|
734 | + get_my_funeqs (IC { inert_funeqs = funeqs })
|
|
735 | + = [ funeq_ct | equal_ct_list <- findFunEqsByTyCon funeqs fam_tc
|
|
736 | + , funeq_ct <- equal_ct_list
|
|
737 | + , NomEq == eq_eq_rel funeq_ct ]
|
|
738 | + -- Representational equalities don't interact
|
|
739 | + -- with type family dependencies
|
|
740 | + |
|
741 | +improveGivenLocalFunEqs :: [EqCt] -- Inert items, mixture of Given and Wanted
|
|
742 | + -> TyCon -> [TcType] -> CtEvidence -> Xi -- Work item (Given)
|
|
743 | + -> TcS Bool -- Always False (no unifications)
|
|
744 | +-- Emit equalities from interaction between two Given type-family equalities
|
|
745 | +-- e.g. (x+y1~z, x+y2~z) => (y1 ~ y2)
|
|
746 | +improveGivenLocalFunEqs funeqs_for_tc fam_tc work_args work_ev work_rhs
|
|
747 | + | Just ops <- isBuiltInSynFamTyCon_maybe fam_tc
|
|
748 | + = do { mapM_ (do_one ops) funeqs_for_tc
|
|
749 | + ; return False } -- False: no unifications
|
|
750 | + | otherwise
|
|
751 | + = return False
|
|
752 | + where
|
|
753 | + given_co :: Coercion = ctEvCoercion work_ev
|
|
754 | + |
|
755 | + do_one :: BuiltInSynFamily -> EqCt -> TcS ()
|
|
756 | + -- Used only work-item is Given
|
|
757 | + do_one ops EqCt { eq_ev = inert_ev, eq_lhs = inert_lhs, eq_rhs = inert_rhs }
|
|
758 | + | isGiven inert_ev -- Given/Given interaction
|
|
759 | + , TyFamLHS _ inert_args <- inert_lhs -- Inert item is F inert_args ~ inert_rhs
|
|
760 | + , work_rhs `tcEqType` inert_rhs -- Both RHSs are the same
|
|
761 | + , -- So we have work_ev : F work_args ~ rhs
|
|
762 | + -- inert_ev : F inert_args ~ rhs
|
|
763 | + let pairs :: [(CoAxiomRule, TypeEqn)]
|
|
764 | + pairs = tryInteractInertFam ops fam_tc work_args inert_args
|
|
765 | + , not (null pairs)
|
|
766 | + = do { traceTcS "improveGivenLocalFunEqs" (vcat[ ppr fam_tc <+> ppr work_args
|
|
767 | + , text "work_ev" <+> ppr work_ev
|
|
768 | + , text "inert_ev" <+> ppr inert_ev
|
|
769 | + , ppr work_rhs
|
|
770 | + , ppr pairs ])
|
|
771 | + ; emitNewGivens (ctEvLoc inert_ev) (map mk_ax_co pairs) }
|
|
772 | + -- This CtLoc for the new Givens doesn't reflect the
|
|
773 | + -- fact that it's a combination of Givens, but I don't
|
|
774 | + -- this that matters.
|
|
775 | + where
|
|
776 | + inert_co = ctEvCoercion inert_ev
|
|
777 | + mk_ax_co (ax,_) = (Nominal, mkAxiomCo ax [combined_co])
|
|
778 | + where
|
|
779 | + combined_co = given_co `mkTransCo` mkSymCo inert_co
|
|
780 | + -- given_co :: F work_args ~ rhs
|
|
781 | + -- inert_co :: F inert_args ~ rhs
|
|
782 | + -- the_co :: F work_args ~ F inert_args
|
|
783 | + |
|
784 | + do_one _ _ = return ()
|
|
785 | + |
|
786 | +improveWantedLocalFunEqs
|
|
787 | + :: [EqCt] -- Inert items (Given and Wanted)
|
|
788 | + -> TyCon -> [TcType] -> CtEvidence -> Xi -- Work item (Wanted)
|
|
789 | + -> TcS Bool -- True <=> some unifications
|
|
790 | +-- Emit improvement equalities for a Wanted constraint, by comparing
|
|
791 | +-- the current work item with inert CFunEqs (both Given and Wanted)
|
|
792 | +-- E.g. x + y ~ z, x + y' ~ z => [W] y ~ y'
|
|
793 | +--
|
|
794 | +-- See Note [FunDep and implicit parameter reactions]
|
|
795 | +improveWantedLocalFunEqs funeqs_for_tc fam_tc args work_ev rhs
|
|
796 | + | null improvement_eqns
|
|
797 | + = return False
|
|
798 | + | otherwise
|
|
799 | + = do { traceTcS "interactFunEq improvements: " $
|
|
800 | + vcat [ text "Eqns:" <+> ppr improvement_eqns
|
|
801 | + , text "Candidates:" <+> ppr funeqs_for_tc ]
|
|
802 | + ; unifyAndEmitFunDepWanteds work_ev improvement_eqns }
|
|
803 | + where
|
|
804 | + work_loc = ctEvLoc work_ev
|
|
805 | + work_pred = ctEvPred work_ev
|
|
806 | + fam_inj_info = tyConInjectivityInfo fam_tc
|
|
807 | + |
|
808 | + --------------------
|
|
809 | + improvement_eqns :: [FunDepEqn (CtLoc, RewriterSet)]
|
|
810 | + improvement_eqns
|
|
811 | + | Just ops <- isBuiltInSynFamTyCon_maybe fam_tc
|
|
812 | + = -- Try built-in families, notably for arithmethic
|
|
813 | + concatMap (do_one_built_in ops rhs) funeqs_for_tc
|
|
814 | + |
|
815 | + | Injective injective_args <- fam_inj_info
|
|
816 | + = -- Try improvement from type families with injectivity annotations
|
|
817 | + concatMap (do_one_injective injective_args rhs) funeqs_for_tc
|
|
818 | + |
|
819 | + | otherwise
|
|
820 | + = []
|
|
821 | + |
|
822 | + --------------------
|
|
823 | + do_one_built_in ops rhs (EqCt { eq_lhs = TyFamLHS _ iargs, eq_rhs = irhs, eq_ev = inert_ev })
|
|
824 | + | irhs `tcEqType` rhs
|
|
825 | + = mk_fd_eqns inert_ev (map snd $ tryInteractInertFam ops fam_tc args iargs)
|
|
826 | + | otherwise
|
|
827 | + = []
|
|
828 | + do_one_built_in _ _ _ = pprPanic "interactFunEq 1" (ppr fam_tc) -- TyVarLHS
|
|
829 | + |
|
830 | + --------------------
|
|
831 | + -- See Note [Type inference for type families with injectivity]
|
|
832 | + do_one_injective inj_args rhs (EqCt { eq_lhs = TyFamLHS _ inert_args
|
|
833 | + , eq_rhs = irhs, eq_ev = inert_ev })
|
|
834 | + | rhs `tcEqType` irhs
|
|
835 | + = mk_fd_eqns inert_ev $ mkInjectivityEqns inj_args args inert_args
|
|
836 | + | otherwise
|
|
837 | + = []
|
|
838 | + |
|
839 | + do_one_injective _ _ _ = pprPanic "interactFunEq 2" (ppr fam_tc) -- TyVarLHS
|
|
840 | + |
|
841 | + --------------------
|
|
842 | + mk_fd_eqns :: CtEvidence -> [TypeEqn] -> [FunDepEqn (CtLoc, RewriterSet)]
|
|
843 | + mk_fd_eqns inert_ev eqns
|
|
844 | + | null eqns = []
|
|
845 | + | otherwise = [ FDEqn { fd_qtvs = [], fd_eqs = eqns
|
|
846 | + , fd_loc = (loc, inert_rewriters) } ]
|
|
847 | + where
|
|
848 | + initial_loc -- start with the location of the Wanted involved
|
|
849 | + | isGiven work_ev = inert_loc
|
|
850 | + | otherwise = work_loc
|
|
851 | + eqn_orig = InjTFOrigin1 work_pred (ctLocOrigin work_loc) (ctLocSpan work_loc)
|
|
852 | + inert_pred (ctLocOrigin inert_loc) (ctLocSpan inert_loc)
|
|
853 | + eqn_loc = setCtLocOrigin initial_loc eqn_orig
|
|
854 | + inert_pred = ctEvPred inert_ev
|
|
855 | + inert_loc = ctEvLoc inert_ev
|
|
856 | + inert_rewriters = ctEvRewriters inert_ev
|
|
857 | + loc = eqn_loc { ctl_depth = ctl_depth inert_loc `maxSubGoalDepth`
|
|
858 | + ctl_depth work_loc }
|
|
859 | + |
|
860 | +{- Note [Type inference for type families with injectivity]
|
|
861 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
862 | +Suppose we have a type family with an injectivity annotation:
|
|
863 | + type family F a b = r | r -> b
|
|
864 | + |
|
865 | +Then if we have an equality like F s1 t1 ~ F s2 t2,
|
|
866 | +we can use the injectivity to get a new Wanted constraint on
|
|
867 | +the injective argument
|
|
868 | + [W] t1 ~ t2
|
|
869 | + |
|
870 | +That in turn can help GHC solve constraints that would otherwise require
|
|
871 | +guessing. For example, consider the ambiguity check for
|
|
872 | + f :: F Int b -> Int
|
|
873 | +We get the constraint
|
|
874 | + [W] F Int b ~ F Int beta
|
|
875 | +where beta is a unification variable. Injectivity lets us pick beta ~ b.
|
|
876 | + |
|
877 | +Injectivity information is also used at the call sites. For example:
|
|
878 | + g = f True
|
|
879 | +gives rise to
|
|
880 | + [W] F Int b ~ Bool
|
|
881 | +from which we can derive b. This requires looking at the defining equations of
|
|
882 | +a type family, ie. finding equation with a matching RHS (Bool in this example)
|
|
883 | +and inferring values of type variables (b in this example) from the LHS patterns
|
|
884 | +of the matching equation. For closed type families we have to perform
|
|
885 | +additional apartness check for the selected equation to check that the selected
|
|
886 | +is guaranteed to fire for given LHS arguments.
|
|
887 | + |
|
888 | +These new constraints are Wanted constraints, but we will not use the evidence.
|
|
889 | +We could go further and offer evidence from decomposing injective type-function
|
|
890 | +applications, but that would require new evidence forms, and an extension to
|
|
891 | +FC, so we don't do that right now (Dec 14).
|
|
892 | + |
|
893 | +We generate these Wanteds in three places, depending on how we notice the
|
|
894 | +injectivity.
|
|
895 | + |
|
896 | +1. When we have a [W] F tys1 ~ F tys2. This is handled in canEqCanLHS2, and
|
|
897 | +described in Note [Decomposing type family applications] in GHC.Tc.Solver.Equality
|
|
898 | + |
|
899 | +2. When we have [W] F tys1 ~ T and [W] F tys2 ~ T. Note that neither of these
|
|
900 | +constraints rewrites the other, as they have different LHSs. This is done
|
|
901 | +in improveLocalFunEqs, called during the interactWithInertsStage.
|
|
902 | + |
|
903 | +3. When we have [W] F tys ~ T and an equation for F that looks like F tys' = T.
|
|
904 | +This is done in improve_top_fun_eqs, called from the top-level reactions stage.
|
|
905 | + |
|
906 | +See also Note [Injective type families] in GHC.Core.TyCon
|
|
907 | + |
|
908 | +Note [Cache-caused loops]
|
|
909 | +~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
910 | +It is very dangerous to cache a rewritten wanted family equation as 'solved' in our
|
|
911 | +solved cache (which is the default behaviour or xCtEvidence), because the interaction
|
|
912 | +may not be contributing towards a solution. Here is an example:
|
|
913 | + |
|
914 | +Initial inert set:
|
|
915 | + [W] g1 : F a ~ beta1
|
|
916 | +Work item:
|
|
917 | + [W] g2 : F a ~ beta2
|
|
918 | +The work item will react with the inert yielding the _same_ inert set plus:
|
|
919 | + (i) Will set g2 := g1 `cast` g3
|
|
920 | + (ii) Will add to our solved cache that [S] g2 : F a ~ beta2
|
|
921 | + (iii) Will emit [W] g3 : beta1 ~ beta2
|
|
922 | +Now, the g3 work item will be spontaneously solved to [G] g3 : beta1 ~ beta2
|
|
923 | +and then it will react the item in the inert ([W] g1 : F a ~ beta1). So it
|
|
924 | +will set
|
|
925 | + g1 := g ; sym g3
|
|
926 | +and what is g? Well it would ideally be a new goal of type (F a ~ beta2) but
|
|
927 | +remember that we have this in our solved cache, and it is ... g2! In short we
|
|
928 | +created the evidence loop:
|
|
929 | + |
|
930 | + g2 := g1 ; g3
|
|
931 | + g3 := refl
|
|
932 | + g1 := g2 ; sym g3
|
|
933 | + |
|
934 | +To avoid this situation we do not cache as solved any workitems (or inert)
|
|
935 | +which did not really made a 'step' towards proving some goal. Solved's are
|
|
936 | +just an optimization so we don't lose anything in terms of completeness of
|
|
937 | +solving.
|
|
938 | +-}
|
|
939 | + |
|
472 | 940 | {-
|
473 | 941 | ************************************************************************
|
474 | 942 | * *
|
... | ... | @@ -67,9 +67,6 @@ module GHC.Tc.Solver.Monad ( |
67 | 67 | getTcEvTyCoVars, getTcEvBindsMap, setTcEvBindsMap,
|
68 | 68 | tcLookupClass, tcLookupId, tcLookupTyCon,
|
69 | 69 | |
70 | - getUnifiedRef,
|
|
71 | - |
|
72 | - |
|
73 | 70 | -- Inerts
|
74 | 71 | updInertSet, updInertCans,
|
75 | 72 | getHasGivenEqs, setInertCans,
|
... | ... | @@ -84,7 +81,7 @@ module GHC.Tc.Solver.Monad ( |
84 | 81 | lookupInertDict,
|
85 | 82 | |
86 | 83 | -- The Model
|
87 | - kickOutAfterUnification, kickOutRewritable,
|
|
84 | + recordUnification, recordUnifications, kickOutRewritable,
|
|
88 | 85 | |
89 | 86 | -- Inert Safe Haskell safe-overlap failures
|
90 | 87 | insertSafeOverlapFailureTcS,
|
... | ... | @@ -212,8 +209,6 @@ import Control.Monad |
212 | 209 | import Data.Foldable hiding ( foldr1 )
|
213 | 210 | import Data.IORef
|
214 | 211 | import Data.List ( mapAccumL )
|
215 | -import Data.List.NonEmpty ( nonEmpty )
|
|
216 | -import qualified Data.List.NonEmpty as NE
|
|
217 | 212 | import GHC.Types.SrcLoc
|
218 | 213 | import GHC.Rename.Env
|
219 | 214 | import GHC.LanguageExtensions as LangExt
|
... | ... | @@ -450,33 +445,6 @@ kickOutRewritable ko_spec new_fr |
450 | 445 | , text "kicked_out =" <+> ppr kicked_out
|
451 | 446 | , text "Residual inerts =" <+> ppr ics' ]) } }
|
452 | 447 | |
453 | -kickOutAfterUnification :: [TcTyVar] -> TcS ()
|
|
454 | -kickOutAfterUnification tv_list
|
|
455 | - = case nonEmpty tv_list of
|
|
456 | - Nothing -> return ()
|
|
457 | - Just tvs -> do { traceTcS "kickOutAfterUnification" (ppr min_tv_lvl $$ ppr tv_list)
|
|
458 | - ; setUnificationFlagTo min_tv_lvl }
|
|
459 | - where
|
|
460 | - min_tv_lvl = foldr1 minTcLevel (NE.map tcTyVarLevel tvs)
|
|
461 | - |
|
462 | -{-
|
|
463 | - { let tv_set = mkVarSet tv_list
|
|
464 | - |
|
465 | - ; n_kicked <- kickOutRewritable (KOAfterUnify tv_set) (Given, NomEq)
|
|
466 | - -- Given because the tv := xi is given; NomEq because
|
|
467 | - -- only nominal equalities are solved by unification
|
|
468 | - |
|
469 | - -- Set the unification flag if we have done outer unifications
|
|
470 | - -- that might affect an earlier implication constraint
|
|
471 | - ; let min_tv_lvl = foldr1 minTcLevel (NE.map tcTyVarLevel tvs)
|
|
472 | - ; ambient_lvl <- getTcLevel
|
|
473 | - ; when (ambient_lvl `strictlyDeeperThan` min_tv_lvl) $
|
|
474 | - setUnificationFlagTo min_tv_lvl
|
|
475 | - |
|
476 | - ; traceTcS "kickOutAfterUnification" (ppr tvs $$ text "n_kicked =" <+> ppr n_kicked)
|
|
477 | - ; return n_kicked }
|
|
478 | --}
|
|
479 | - |
|
480 | 448 | kickOutAfterFillingCoercionHole :: CoercionHole -> TcS ()
|
481 | 449 | -- See Wrinkle (URW2) in Note [Unify only if the rewriter set is empty]
|
482 | 450 | -- in GHC.Tc.Solver.Equality
|
... | ... | @@ -940,11 +908,6 @@ data TcSEnv |
940 | 908 | = TcSEnv {
|
941 | 909 | tcs_ev_binds :: EvBindsVar,
|
942 | 910 | |
943 | - tcs_unified :: IORef Int,
|
|
944 | - -- The number of unification variables we have filled
|
|
945 | - -- The important thing is whether it is non-zero, so it
|
|
946 | - -- could equally well be a Bool instead of an Int.
|
|
947 | - |
|
948 | 911 | tcs_unif_lvl :: IORef (Maybe TcLevel),
|
949 | 912 | -- The Unification Level Flag
|
950 | 913 | -- Outermost level at which we have unified a meta tyvar
|
... | ... | @@ -1131,8 +1094,7 @@ runTcSWithEvBinds' :: TcSMode |
1131 | 1094 | -> TcS a
|
1132 | 1095 | -> TcM a
|
1133 | 1096 | runTcSWithEvBinds' mode ev_binds_var thing_inside
|
1134 | - = do { unified_var <- TcM.newTcRef 0
|
|
1135 | - ; step_count <- TcM.newTcRef 0
|
|
1097 | + = do { step_count <- TcM.newTcRef 0
|
|
1136 | 1098 | |
1137 | 1099 | -- Make a fresh, empty inert set
|
1138 | 1100 | -- Subtle point: see (TGE6) in Note [Tracking Given equalities]
|
... | ... | @@ -1143,7 +1105,6 @@ runTcSWithEvBinds' mode ev_binds_var thing_inside |
1143 | 1105 | ; wl_var <- TcM.newTcRef emptyWorkList
|
1144 | 1106 | ; unif_lvl_var <- TcM.newTcRef Nothing
|
1145 | 1107 | ; let env = TcSEnv { tcs_ev_binds = ev_binds_var
|
1146 | - , tcs_unified = unified_var
|
|
1147 | 1108 | , tcs_unif_lvl = unif_lvl_var
|
1148 | 1109 | , tcs_count = step_count
|
1149 | 1110 | , tcs_inerts = inert_var
|
... | ... | @@ -1354,9 +1315,6 @@ setTcSMode :: TcSMode -> TcS a -> TcS a |
1354 | 1315 | setTcSMode mode thing_inside
|
1355 | 1316 | = TcS (\env -> unTcS thing_inside (env { tcs_mode = mode }))
|
1356 | 1317 | |
1357 | -getUnifiedRef :: TcS (IORef Int)
|
|
1358 | -getUnifiedRef = TcS (return . tcs_unified)
|
|
1359 | - |
|
1360 | 1318 | -- Getter of inerts and worklist
|
1361 | 1319 | getInertSetRef :: TcS (IORef InertSet)
|
1362 | 1320 | getInertSetRef = TcS (return . tcs_inerts)
|
... | ... | @@ -1817,13 +1775,11 @@ produced the same Derived constraint.) |
1817 | 1775 | |
1818 | 1776 | unifyTyVar :: TcTyVar -> TcType -> TcS ()
|
1819 | 1777 | -- Unify a meta-tyvar with a type
|
1820 | --- We keep track of how many unifications have happened in tcs_unified,
|
|
1821 | ---
|
|
1822 | 1778 | -- We should never unify the same variable twice!
|
1823 | 1779 | unifyTyVar tv ty
|
1824 | 1780 | = assertPpr (isMetaTyVar tv) (ppr tv) $
|
1825 | 1781 | do { liftZonkTcS (TcM.writeMetaTyVar tv ty) -- Produces a trace message
|
1826 | - ; setUnificationFlagTo (tcTyVarLevel tv) }
|
|
1782 | + ; recordUnification tv }
|
|
1827 | 1783 | |
1828 | 1784 | reportUnifications :: TcS a -> TcS (Bool, a)
|
1829 | 1785 | -- Record whether any unifications are done by thing_inside
|
... | ... | @@ -1887,6 +1843,18 @@ getUnificationFlag |
1887 | 1843 | -> do { TcM.writeTcRef ref Nothing
|
1888 | 1844 | ; return True } }
|
1889 | 1845 | |
1846 | +recordUnification :: TcTyVar -> TcS ()
|
|
1847 | +recordUnification tv = setUnificationFlagTo (tcTyVarLevel tv)
|
|
1848 | + |
|
1849 | +recordUnifications :: [TcTyVar] -> TcS ()
|
|
1850 | +recordUnifications tvs
|
|
1851 | + = case tvs of
|
|
1852 | + [] -> return ()
|
|
1853 | + (tv:tvs) -> do { traceTcS "recordUnifications" (ppr min_tv_lvl $$ ppr tvs)
|
|
1854 | + ; setUnificationFlagTo min_tv_lvl }
|
|
1855 | + where
|
|
1856 | + min_tv_lvl = foldr (minTcLevel . tcTyVarLevel) (tcTyVarLevel tv) tvs
|
|
1857 | + |
|
1890 | 1858 | setUnificationFlagTo :: TcLevel -> TcS ()
|
1891 | 1859 | -- (setUnificationFlag i) sets the unification level to (Just i)
|
1892 | 1860 | -- unless it already is (Just j) where j <= i
|
... | ... | @@ -2251,8 +2219,8 @@ unifyForAllBody :: CtEvidence -> Role -> (UnifyEnv -> TcM a) |
2251 | 2219 | unifyForAllBody ev role unify_body
|
2252 | 2220 | = do { (res, cts, unified) <- wrapUnifierX ev role unify_body
|
2253 | 2221 | |
2254 | - -- Kick out any inert constraint that we have unified
|
|
2255 | - ; kickOutAfterUnification unified
|
|
2222 | + -- Record the unificaions we have done
|
|
2223 | + ; recordUnifications unified
|
|
2256 | 2224 | |
2257 | 2225 | ; return (res, cts) }
|
2258 | 2226 | |
... | ... | @@ -2271,6 +2239,9 @@ wrapUnifierTcS :: CtEvidence -> Role |
2271 | 2239 | wrapUnifierTcS ev role do_unifications
|
2272 | 2240 | = do { (res, cts, unified) <- wrapUnifierX ev role do_unifications
|
2273 | 2241 | |
2242 | + -- Record the unificaions we have done
|
|
2243 | + ; recordUnifications unified
|
|
2244 | + |
|
2274 | 2245 | -- Emit the deferred constraints
|
2275 | 2246 | -- See Note [Work-list ordering] in GHC.Tc.Solved.Equality
|
2276 | 2247 | --
|
... | ... | @@ -2280,17 +2251,13 @@ wrapUnifierTcS ev role do_unifications |
2280 | 2251 | ; unless (isEmptyBag cts) $
|
2281 | 2252 | updWorkListTcS (extendWorkListChildEqs ev cts)
|
2282 | 2253 | |
2283 | - -- And kick out any inert constraint that we have unified
|
|
2284 | - ; kickOutAfterUnification unified
|
|
2285 | - |
|
2286 | 2254 | ; return (res, cts, unified) }
|
2287 | 2255 | |
2288 | 2256 | wrapUnifierX :: CtEvidence -> Role
|
2289 | 2257 | -> (UnifyEnv -> TcM a) -- Some calls to uType
|
2290 | 2258 | -> TcS (a, Bag Ct, [TcTyVar])
|
2291 | 2259 | wrapUnifierX ev role do_unifications
|
2292 | - = do { unif_count_ref <- getUnifiedRef
|
|
2293 | - ; given_eq_lvl <- getInnermostGivenEqLevel
|
|
2260 | + = do { given_eq_lvl <- getInnermostGivenEqLevel
|
|
2294 | 2261 | ; wrapTcS $
|
2295 | 2262 | do { defer_ref <- TcM.newTcRef emptyBag
|
2296 | 2263 | ; unified_ref <- TcM.newTcRef []
|
... | ... | @@ -2308,12 +2275,6 @@ wrapUnifierX ev role do_unifications |
2308 | 2275 | |
2309 | 2276 | ; cts <- TcM.readTcRef defer_ref
|
2310 | 2277 | ; unified <- TcM.readTcRef unified_ref
|
2311 | - |
|
2312 | - -- Don't forget to update the count of variables
|
|
2313 | - -- unified, lest we forget to iterate (#24146)
|
|
2314 | - ; unless (null unified) $
|
|
2315 | - TcM.updTcRef unif_count_ref (+ (length unified))
|
|
2316 | - |
|
2317 | 2278 | ; return (res, cts, unified) } }
|
2318 | 2279 | |
2319 | 2280 |