diff options
author | Richard Eisenberg <rae@richarde.dev> | 2020-11-25 15:22:16 -0500 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2020-12-01 19:57:41 -0500 |
commit | 8bb52d9186655134e3e06b4dc003e060379f5417 (patch) | |
tree | cf62438a5f5b3587fe666d72d77561201253306a /compiler/GHC/Tc/Utils/Unify.hs | |
parent | 0dd45d0adbade7eaae973b09b4d0ff1acb1479b8 (diff) | |
download | haskell-8bb52d9186655134e3e06b4dc003e060379f5417.tar.gz |
Remove flattening variables
This patch redesigns the flattener to simplify type family applications
directly instead of using flattening meta-variables and skolems. The key new
innovation is the CanEqLHS type and the new CEqCan constraint (Ct). A CanEqLHS
is either a type variable or exactly-saturated type family application; either
can now be rewritten using a CEqCan constraint in the inert set.
Because the flattener no longer reduces all type family applications to
variables, there was some performance degradation if a lengthy type family
application is now flattened over and over (not making progress). To
compensate, this patch contains some extra optimizations in the flattener,
leading to a number of performance improvements.
Close #18875.
Close #18910.
There are many extra parts of the compiler that had to be affected in writing
this patch:
* The family-application cache (formerly the flat-cache) sometimes stores
coercions built from Given inerts. When these inerts get kicked out, we must
kick out from the cache as well. (This was, I believe, true previously, but
somehow never caused trouble.) Kicking out from the cache requires adding a
filterTM function to TrieMap.
* This patch obviates the need to distinguish "blocking" coercion holes from
non-blocking ones (which, previously, arose from CFunEqCans). There is thus
some simplification around coercion holes.
* Extra commentary throughout parts of the code I read through, to preserve
the knowledge I gained while working.
* A change in the pure unifier around unifying skolems with other types.
Unifying a skolem now leads to SurelyApart, not MaybeApart, as documented
in Note [Binding when looking up instances] in GHC.Core.InstEnv.
* Some more use of MCoercion where appropriate.
* Previously, class-instance lookup automatically noticed that e.g. C Int was
a "unifier" to a target [W] C (F Bool), because the F Bool was flattened to
a variable. Now, a little more care must be taken around checking for
unifying instances.
* Previously, tcSplitTyConApp_maybe would split (Eq a => a). This is silly,
because (=>) is not a tycon in Haskell. Fixed now, but there are some
knock-on changes in e.g. TrieMap code and in the canonicaliser.
* New function anyFreeVarsOf{Type,Co} to check whether a free variable
satisfies a certain predicate.
* Type synonyms now remember whether or not they are "forgetful"; a forgetful
synonym drops at least one argument. This is useful when flattening; see
flattenView.
* The pattern-match completeness checker invokes the solver. This invocation
might need to look through newtypes when checking representational equality.
Thus, the desugarer needs to keep track of the in-scope variables to know
what newtype constructors are in scope. I bet this bug was around before but
never noticed.
* Extra-constraints wildcards are no longer simplified before printing.
See Note [Do not simplify ConstraintHoles] in GHC.Tc.Solver.
* Whether or not there are Given equalities has become slightly subtler.
See the new HasGivenEqs datatype.
* Note [Type variable cycles in Givens] in GHC.Tc.Solver.Canonical
explains a significant new wrinkle in the new approach.
* See Note [What might match later?] in GHC.Tc.Solver.Interact, which
explains the fix to #18910.
* The inert_count field of InertCans wasn't actually used, so I removed
it.
Though I (Richard) did the implementation, Simon PJ was very involved
in design and review.
This updates the Haddock submodule to avoid #18932 by adding
a type signature.
-------------------------
Metric Decrease:
T12227
T5030
T9872a
T9872b
T9872c
Metric Increase:
T9872d
-------------------------
Diffstat (limited to 'compiler/GHC/Tc/Utils/Unify.hs')
-rw-r--r-- | compiler/GHC/Tc/Utils/Unify.hs | 283 |
1 files changed, 142 insertions, 141 deletions
diff --git a/compiler/GHC/Tc/Utils/Unify.hs b/compiler/GHC/Tc/Utils/Unify.hs index 4b0a5f8fdd..3529f598f8 100644 --- a/compiler/GHC/Tc/Utils/Unify.hs +++ b/compiler/GHC/Tc/Utils/Unify.hs @@ -1,5 +1,6 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE DeriveFunctor #-} +{-# LANGUAGE MultiWayIf #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TupleSections #-} @@ -36,7 +37,8 @@ module GHC.Tc.Utils.Unify ( matchExpectedFunKind, matchActualFunTySigma, matchActualFunTysRho, - metaTyVarUpdateOK, occCheckForErrors, MetaTyVarUpdateResult(..) + metaTyVarUpdateOK, occCheckForErrors, MetaTyVarUpdateResult(..), + checkTyVarEq, checkTyFamEq, checkTypeEq, AreTypeFamiliesOK(..) ) where @@ -73,6 +75,7 @@ import GHC.Utils.Misc import GHC.Utils.Outputable as Outputable import GHC.Utils.Panic +import GHC.Exts ( inline ) import Control.Monad import Control.Arrow ( second ) @@ -949,7 +952,7 @@ buildTvImplication skol_info skol_tvs tclvl wanted ; return (implic { ic_tclvl = tclvl , ic_skols = skol_tvs - , ic_no_eqs = True + , ic_given_eqs = NoGivenEqs , ic_wanted = wanted , ic_binds = ev_binds , ic_info = skol_info }) } @@ -1431,7 +1434,8 @@ uUnfilledVar2 origin t_or_k swapped tv1 ty2 where go dflags cur_lvl | canSolveByUnification cur_lvl tv1 ty2 - , MTVU_OK ty2' <- metaTyVarUpdateOK dflags tv1 ty2 + -- See Note [Prevent unification with type families] about the NoTypeFamilies: + , MTVU_OK ty2' <- metaTyVarUpdateOK dflags NoTypeFamilies tv1 ty2 = do { co_k <- uType KindLevel kind_origin (tcTypeKind ty2') (tyVarKind tv1) ; traceTc "uUnfilledVar2 ok" $ vcat [ ppr tv1 <+> dcolon <+> ppr (tyVarKind tv1) @@ -1498,20 +1502,19 @@ lhsPriority tv RuntimeUnk -> 0 SkolemTv {} -> 0 MetaTv { mtv_info = info } -> case info of - FlatSkolTv -> 1 - TyVarTv -> 2 - TauTv -> 3 - FlatMetaTv -> 4 - RuntimeUnkTv -> 5 + CycleBreakerTv -> 0 + TyVarTv -> 1 + TauTv -> 2 + RuntimeUnkTv -> 3 {- Note [TyVar/TyVar orientation] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Given (a ~ b), should we orient the CTyEqCan as (a~b) or (b~a)? +Given (a ~ b), should we orient the CEqCan as (a~b) or (b~a)? This is a surprisingly tricky question! This is invariant (TyEq:TV). -The question is answered by swapOverTyVars, which is use +The question is answered by swapOverTyVars, which is used - in the eager unifier, in GHC.Tc.Utils.Unify.uUnfilledVar1 - - in the constraint solver, in GHC.Tc.Solver.Canonical.canEqTyVarHomo + - in the constraint solver, in GHC.Tc.Solver.Canonical.canEqCanLHS2 First note: only swap if you have to! See Note [Avoid unnecessary swaps] @@ -1531,25 +1534,23 @@ So we look for a positive reason to swap, using a three-step test: looks for meta tyvars on the left Tie-breaking rules for MetaTvs: - - FlatMetaTv = 4: always put on the left. - See Note [Fmv Orientation Invariant] + - CycleBreakerTv: This is essentially a stand-in for another type; + it's untouchable and should have the same priority as a skolem: 0. - NB: FlatMetaTvs always have the current level, never an - outer one. So nothing can be deeper than a FlatMetaTv. + - TyVarTv: These can unify only with another tyvar, but we can't unify + a TyVarTv with a TauTv, because then the TyVarTv could (transitively) + get a non-tyvar type. So give these a low priority: 1. - - TauTv = 3: if we have tyv_tv ~ tau_tv, - put tau_tv on the left because there are fewer - restrictions on updating TauTvs. Or to say it another - way, then we won't lose the TyVarTv flag + - TauTv: This is the common case; we want these on the left so that they + can be written to: 2. - - TyVarTv = 2: remember, flat-skols are *only* updated by - the unflattener, never unified, so TyVarTvs come next - - - FlatSkolTv = 1: put on the left in preference to a SkolemTv. - See Note [Eliminate flat-skols] + - RuntimeUnkTv: These aren't really meta-variables used in type inference, + but just a convenience in the implementation of the GHCi debugger. + Eagerly write to these: 3. See Note [RuntimeUnkTv] in + GHC.Runtime.Heap.Inspect. * Names. If the level and priority comparisons are all - equal, try to eliminate a TyVars with a System Name in + equal, try to eliminate a TyVar with a System Name in favour of ones with a Name derived from a user type signature * Age. At one point in the past we tried to break any remaining @@ -1602,64 +1603,6 @@ Wanteds and Givens, but either way, deepest wins! Simple. See #15009 for an further analysis of why "deepest on the left" is a good plan. -Note [Fmv Orientation Invariant] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * We always orient a constraint - fmv ~ alpha - with fmv on the left, even if alpha is - a touchable unification variable - -Reason: doing it the other way round would unify alpha:=fmv, but that -really doesn't add any info to alpha. But a later constraint alpha ~ -Int might unlock everything. Comment:9 of #12526 gives a detailed -example. - -WARNING: I've gone to and fro on this one several times. -I'm now pretty sure that unifying alpha:=fmv is a bad idea! -So orienting with fmvs on the left is a good thing. - -This example comes from IndTypesPerfMerge. (Others include -T10226, T10009.) - From the ambiguity check for - f :: (F a ~ a) => a - we get: - [G] F a ~ a - [WD] F alpha ~ alpha, alpha ~ a - - From Givens we get - [G] F a ~ fsk, fsk ~ a - - Now if we flatten we get - [WD] alpha ~ fmv, F alpha ~ fmv, alpha ~ a - - Now, if we unified alpha := fmv, we'd get - [WD] F fmv ~ fmv, [WD] fmv ~ a - And now we are stuck. - -So instead the Fmv Orientation Invariant puts the fmv on the -left, giving - [WD] fmv ~ alpha, [WD] F alpha ~ fmv, [WD] alpha ~ a - - Now we get alpha:=a, and everything works out - -Note [Eliminate flat-skols] -~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Suppose we have [G] Num (F [a]) -then we flatten to - [G] Num fsk - [G] F [a] ~ fsk -where fsk is a flatten-skolem (FlatSkolTv). Suppose we have - type instance F [a] = a -then we'll reduce the second constraint to - [G] a ~ fsk -and then replace all uses of 'a' with fsk. That's bad because -in error messages instead of saying 'a' we'll say (F [a]). In all -places, including those where the programmer wrote 'a' in the first -place. Very confusing! See #7862. - -Solution: re-orient a~fsk to fsk~a, so that we preferentially eliminate -the fsk. - Note [Avoid unnecessary swaps] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If we swap without actually improving matters, we can get an infinite loop. @@ -1734,8 +1677,11 @@ It would be lovely in the future to revisit this problem and remove this extra, unnecessary check. But we retain it for now as it seems to work better in practice. -Note [Refactoring hazard: checkTauTvUpdate] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Revisited in Nov '20, along with removing flattening variables. Problem +is still present, and the solution (NoTypeFamilies) is still the same. + +Note [Refactoring hazard: metaTyVarUpdateOK] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ I (Richard E.) have a sad story about refactoring this code, retained here to prevent others (or a future me!) from falling into the same traps. @@ -1957,7 +1903,7 @@ occCheckForErrors :: DynFlags -> TcTyVar -> Type -> MetaTyVarUpdateResult () -- a) the given variable occurs in the given type. -- b) there is a forall in the type (unless we have -XImpredicativeTypes) occCheckForErrors dflags tv ty - = case mtvu_check dflags True tv ty of + = case checkTyVarEq dflags YesTypeFamilies tv ty of MTVU_OK _ -> MTVU_OK () MTVU_Bad -> MTVU_Bad MTVU_HoleBlocker -> MTVU_HoleBlocker @@ -1966,16 +1912,24 @@ occCheckForErrors dflags tv ty Just _ -> MTVU_OK () ---------------- +data AreTypeFamiliesOK = YesTypeFamilies + | NoTypeFamilies + deriving Eq + +instance Outputable AreTypeFamiliesOK where + ppr YesTypeFamilies = text "YesTypeFamilies" + ppr NoTypeFamilies = text "NoTypeFamilies" + metaTyVarUpdateOK :: DynFlags + -> AreTypeFamiliesOK -- allow type families in RHS? -> TcTyVar -- tv :: k1 -> TcType -- ty :: k2 -> MetaTyVarUpdateResult TcType -- possibly-expanded ty -- (metaTyVarUpdateOK tv ty) -- Checks that the equality tv~ty is OK to be used to rewrite --- other equalities. Equivalently, checks the conditions for CTyEqCan +-- other equalities. Equivalently, checks the conditions for CEqCan -- (a) that tv doesn't occur in ty (occurs check) --- (b) that ty does not have any foralls --- (in the impredicative case), or type functions +-- (b) that ty does not have any foralls or (perhaps) type functions -- (c) that ty does not have any blocking coercion holes -- See Note [Equalities with incompatible kinds] in "GHC.Tc.Solver.Canonical" -- @@ -2000,12 +1954,10 @@ metaTyVarUpdateOK :: DynFlags -- we return Nothing, leaving it to the later constraint simplifier to -- sort matters out. -- --- See Note [Refactoring hazard: checkTauTvUpdate] +-- See Note [Refactoring hazard: metaTyVarUpdateOK] -metaTyVarUpdateOK dflags tv ty - = case mtvu_check dflags False tv ty of - -- False <=> type families not ok - -- See Note [Prevent unification with type families] +metaTyVarUpdateOK dflags ty_fam_ok tv ty + = case checkTyVarEq dflags ty_fam_ok tv ty of MTVU_OK _ -> MTVU_OK ty MTVU_Bad -> MTVU_Bad -- forall, predicate, type function MTVU_HoleBlocker -> MTVU_HoleBlocker -- coercion hole @@ -2013,20 +1965,40 @@ metaTyVarUpdateOK dflags tv ty Just expanded_ty -> MTVU_OK expanded_ty Nothing -> MTVU_Occurs -mtvu_check :: DynFlags -> Bool -> TcTyVar -> TcType -> MetaTyVarUpdateResult () --- Checks the invariants for CTyEqCan. In particular: +checkTyVarEq :: DynFlags -> AreTypeFamiliesOK -> TcTyVar -> TcType -> MetaTyVarUpdateResult () +checkTyVarEq dflags ty_fam_ok tv ty + = inline checkTypeEq dflags ty_fam_ok (TyVarLHS tv) ty + -- inline checkTypeEq so that the `case`s over the CanEqLHS get blasted away + +checkTyFamEq :: DynFlags + -> TyCon -- type function + -> [TcType] -- args, exactly saturated + -> TcType -- RHS + -> MetaTyVarUpdateResult () +checkTyFamEq dflags fun_tc fun_args ty + = inline checkTypeEq dflags YesTypeFamilies (TyFamLHS fun_tc fun_args) ty + -- inline checkTypeEq so that the `case`s over the CanEqLHS get blasted away + +checkTypeEq :: DynFlags -> AreTypeFamiliesOK -> CanEqLHS -> TcType + -> MetaTyVarUpdateResult () +-- Checks the invariants for CEqCan. In particular: -- (a) a forall type (forall a. blah) -- (b) a predicate type (c => ty) -- (c) a type family; see Note [Prevent unification with type families] -- (d) a blocking coercion hole --- (e) an occurrence of the type variable (occurs check) +-- (e) an occurrence of the LHS (occurs check) -- -- For (a), (b), and (c) we check only the top level of the type, NOT -- inside the kinds of variables it mentions. For (d) we look deeply --- in coercions, and for (e) we do look in the kinds of course. - -mtvu_check dflags ty_fam_ok tv ty - = fast_check ty +-- in coercions when the LHS is a tyvar (but skip coercions for type family +-- LHSs), and for (e) see Note [CEqCan occurs check] in GHC.Tc.Types.Constraint. +-- +-- checkTypeEq is called from +-- * checkTyFamEq, checkTyVarEq (which inline it to specialise away the +-- case-analysis on 'lhs' +-- * checkEqCanLHSFinish, which does not know the form of 'lhs' +checkTypeEq dflags ty_fam_ok lhs ty + = go ty where ok :: MetaTyVarUpdateResult () ok = MTVU_OK () @@ -2035,53 +2007,82 @@ mtvu_check dflags ty_fam_ok tv ty -- unification variables that can unify with a polytype -- or a TyCon that would usually be disallowed by bad_tc -- See Note [RuntimeUnkTv] in GHC.Runtime.Heap.Inspect - ghci_tv = case tcTyVarDetails tv of - MetaTv { mtv_info = RuntimeUnkTv } -> True - _ -> False - - fast_check :: TcType -> MetaTyVarUpdateResult () - fast_check (TyVarTy tv') - | tv == tv' = MTVU_Occurs - | otherwise = fast_check_occ (tyVarKind tv') - -- See Note [Occurrence checking: look inside kinds] - -- in GHC.Core.Type - - fast_check (TyConApp tc tys) - | bad_tc tc, not ghci_tv = MTVU_Bad - | otherwise = mapM fast_check tys >> ok - fast_check (LitTy {}) = ok - fast_check (FunTy{ft_af = af, ft_mult = w, ft_arg = a, ft_res = r}) + ghci_tv + | TyVarLHS tv <- lhs + , MetaTv { mtv_info = RuntimeUnkTv } <- tcTyVarDetails tv + = True + + | otherwise + = False + + go :: TcType -> MetaTyVarUpdateResult () + go (TyVarTy tv') = go_tv tv' + go (TyConApp tc tys) = go_tc tc tys + go (LitTy {}) = ok + go (FunTy{ft_af = af, ft_mult = w, ft_arg = a, ft_res = r}) | InvisArg <- af , not ghci_tv = MTVU_Bad - | otherwise = fast_check w >> fast_check a >> fast_check r - fast_check (AppTy fun arg) = fast_check fun >> fast_check arg - fast_check (CastTy ty co) = fast_check ty >> fast_check_co co - fast_check (CoercionTy co) = fast_check_co co - fast_check (ForAllTy (Bndr tv' _) ty) + | otherwise = go w >> go a >> go r + go (AppTy fun arg) = go fun >> go arg + go (CastTy ty co) = go ty >> go_co co + go (CoercionTy co) = go_co co + go (ForAllTy (Bndr tv' _) ty) | not ghci_tv = MTVU_Bad - | tv == tv' = ok - | otherwise = do { fast_check_occ (tyVarKind tv') - ; fast_check_occ ty } - -- Under a forall we look only for occurrences of - -- the type variable + | otherwise = case lhs of + TyVarLHS tv | tv == tv' -> ok + | otherwise -> do { go_occ tv (tyVarKind tv') + ; go ty } + _ -> go ty + + go_tv :: TcTyVar -> MetaTyVarUpdateResult () + -- this slightly peculiar way of defining this means + -- we don't have to evaluate this `case` at every variable + -- occurrence + go_tv = case lhs of + TyVarLHS tv -> \ tv' -> if tv == tv' + then MTVU_Occurs + else go_occ tv (tyVarKind tv') + TyFamLHS {} -> \ _tv' -> ok + -- See Note [Occurrence checking: look inside kinds] in GHC.Core.Type -- For kinds, we only do an occurs check; we do not worry -- about type families or foralls -- See Note [Checking for foralls] - fast_check_occ k | tv `elemVarSet` tyCoVarsOfType k = MTVU_Occurs - | otherwise = ok + go_occ tv k | tv `elemVarSet` tyCoVarsOfType k = MTVU_Occurs + | otherwise = ok + + go_tc :: TyCon -> [TcType] -> MetaTyVarUpdateResult () + -- this slightly peculiar way of defining this means + -- we don't have to evaluate this `case` at every tyconapp + go_tc = case lhs of + TyVarLHS {} -> \ tc tys -> + if | good_tc tc -> mapM go tys >> ok + | otherwise -> MTVU_Bad + TyFamLHS fam_tc fam_args -> \ tc tys -> + if | tcEqTyConApps fam_tc fam_args tc tys -> MTVU_Occurs + | good_tc tc -> mapM go tys >> ok + | otherwise -> MTVU_Bad + -- no bother about impredicativity in coercions, as they're -- inferred - fast_check_co co | not (gopt Opt_DeferTypeErrors dflags) - , badCoercionHoleCo co = MTVU_HoleBlocker - -- Wrinkle (4b) in "GHC.Tc.Solver.Canonical" Note [Equalities with incompatible kinds] - - | tv `elemVarSet` tyCoVarsOfCo co = MTVU_Occurs - | otherwise = ok - - bad_tc :: TyCon -> Bool - bad_tc tc - | not (isTauTyCon tc) = True - | not (ty_fam_ok || isFamFreeTyCon tc) = True - | otherwise = False + go_co co | not (gopt Opt_DeferTypeErrors dflags) + , hasCoercionHoleCo co + = MTVU_HoleBlocker -- Wrinkle (2) in GHC.Tc.Solver.Canonical + -- See GHC.Tc.Solver.Canonical Note [Equalities with incompatible kinds] + -- Wrinkle (2) about this case in general, Wrinkle (4b) about the check for + -- deferred type errors. + + | TyVarLHS tv <- lhs + , tv `elemVarSet` tyCoVarsOfCo co + = MTVU_Occurs + + -- Don't check coercions for type families; see commentary at top of function + | otherwise + = ok + + good_tc :: TyCon -> Bool + good_tc + | ghci_tv = \ _tc -> True + | otherwise = \ tc -> isTauTyCon tc && + (ty_fam_ok == YesTypeFamilies || isFamFreeTyCon tc) |