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 |