[Git][ghc/ghc][wip/T18126] 2 commits: wibbles ql

Simon Peyton Jones gitlab at gitlab.haskell.org
Mon Sep 14 14:31:36 UTC 2020



Simon Peyton Jones pushed to branch wip/T18126 at Glasgow Haskell Compiler / GHC


Commits:
7572a47e by Simon Peyton Jones at 2020-09-14T15:30:36+01:00
wibbles ql

- - - - -
9f5ec175 by Simon Peyton Jones at 2020-09-14T15:31:00+01:00
wibbles generalisation patch

- - - - -


5 changed files:

- compiler/GHC/Tc/Gen/App.hs
- compiler/GHC/Tc/Solver.hs
- compiler/GHC/Tc/Solver/Canonical.hs
- compiler/GHC/Tc/Utils/Unify.hs
- docs/users_guide/ghci.rst


Changes:

=====================================
compiler/GHC/Tc/Gen/App.hs
=====================================
@@ -33,6 +33,7 @@ import GHC.Core.TyCon
 import GHC.Core.TyCo.Rep
 import GHC.Core.TyCo.Ppr
 import GHC.Core.TyCo.Subst (substTyWithInScope)
+import GHC.Core.TyCo.FVs( shallowTyCoVarsOfType )
 import GHC.Core.Type
 import GHC.Tc.Types.Evidence
 import GHC.Types.Var.Set
@@ -852,31 +853,69 @@ qlUnify delta ty1 ty2
                                   ; go_flexi bvs kappa ty2 } }
 
     ----------------
-    -- ToDo: what about other magic in Unify.metaTyVarUpdateOK?
     go_flexi (_,bvs2) kappa ty2  -- ty2 is zonked
-      | ty2_tvs `intersectsVarSet` bvs2   -- We really only need shallow here
-      = return ()   -- Can't instantiate a delta-var
-                    -- to a forall-bound variable
-
-      | kappa `elemVarSet` ty2_tvs
-      = return ()   -- Occurs-check
-
-      | otherwise
-      = do { -- Unify the kinds
-             -- c.f. Note [Equalities with incompatible kinds] in Solver.Canonical
-           ; co <- unifyKind (Just (ppr ty2)) ty2_kind kappa_kind
+      | -- See Note [Actual unification in qlUnify]
+        let ty2_tvs = shallowTyCoVarsOfType ty2
+      , not (ty2_tvs `intersectsVarSet` bvs2)
+          -- Can't instantiate a delta-varto a forall-bound variable
+      , Just ty2' <- occCheckExpand [kappa] ty2
+          -- Passes the occurs check
+      = do { co <- unifyKind (Just (ppr ty2)) ty2_kind kappa_kind
+                   -- unifyKind: see Note [Actual unification in qlUnify]
 
            ; traceTc "qlUnify:update" $
              vcat [ hang (ppr kappa <+> dcolon <+> ppr kappa_kind)
                        2 (text ":=" <+> ppr ty2 <+> dcolon <+> ppr ty2_kind)
                  , text "co:" <+> ppr co ]
            ; writeMetaTyVar kappa (mkCastTy ty2 co) }
+
+      | otherwise
+      = return ()   -- Occurs-check or forall-bound varialbe
       where
-        ty2_tvs    = tyCoVarsOfType ty2
         ty2_kind   = typeKind ty2
         kappa_kind = tyVarKind kappa
 
 
+{- Note [Actual unification in qlUnify]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+In qlUnify, if we find (kappa ~ ty), we are going to update kappa := ty.
+That is the entire point of qlUnify!   Wrinkles
+
+* We must not unify with anything bound by an enclosing forall; e.g.
+    (forall a. kappa -> Int) ~ forall a. a -> Int)
+  That's tracked by the 'bvs' arg of 'go'.
+
+* We must not make an occurs-check; we use occCheckExpand for that.
+
+* metaTyVarUpdateOK also checks for various other things, including
+  - foralls, and predicate types, which we want to allow here
+  - blocking coercion holes
+  - type families
+  But after some thought we believe that none of these are relevant
+  here.
+
+* What if kappa and ty have different kinds?  We solve that problem by
+  calling unifyKind, producing a coercion perhaps emitting some deferred
+  equality constraints.  That is /different/ from the approach we use in
+  the main constraint solver for herterogeneous equalities; see Note
+  [Equalities with incompatible kinds] in Solver.Canonical
+
+  Why different? Because:
+  - We can't use qlUnify to solve the kind constraint because qlUnify
+    won't unify ordinary (non-instantiation) unification variables.
+    (It would have to worry about lots of things like untouchability
+    if it did.)
+  - qlUnify can't give up if the kinds look un-equal because that would
+    mean that it might succeed some times (when the eager unifier
+    has already unified those kinds) but not others -- order
+    dependence.
+  - We can't use the ordinary unifier/constraint solver instead,
+    because it doesn't unify polykinds, and has all kinds of other
+    magic.  qlUnify is very focused.
+
+  TL;DR Calling unifyKind seems like the lesser evil.
+  -}
+
 {- *********************************************************************
 *                                                                      *
               Guardedness


=====================================
compiler/GHC/Tc/Solver.hs
=====================================
@@ -161,6 +161,9 @@ pushLevelAndSolveEqualities :: SkolemInfo -> [TcTyVar] -> TcM a -> TcM a
 -- Push level, and solve all resulting equalities
 -- If there are any unsolved equalities, report them
 -- and fail (in the monad)
+--
+-- Panics if we solve any non-equality constraints.  (In runTCSEqualities
+-- we use an error thunk for the evidence bindings.)
 pushLevelAndSolveEqualities skol_info skol_tvs thing_inside
   = do { (tclvl, wanted, res) <- pushLevelAndSolveEqualitiesX
                                       "pushLevelAndSolveEqualities" thing_inside
@@ -172,6 +175,9 @@ pushLevelAndSolveEqualitiesX :: String -> TcM a
 -- Push the level, gather equality constraints, and then solve them.
 -- Returns any remaining unsolved equalities.
 -- Does not report errors.
+--
+-- Panics if we solve any non-equality constraints.  (In runTCSEqualities
+-- we use an error thunk for the evidence bindings.)
 pushLevelAndSolveEqualitiesX callsite thing_inside
   = do { traceTc "pushLevelAndSolveEqualitiesX {" (text "Called from" <+> text callsite)
        ; (tclvl, (wanted, res))
@@ -187,6 +193,9 @@ pushLevelAndSolveEqualitiesX callsite thing_inside
 -- constraints we can and re-emitting constraints that we can't.
 -- Use this variant only when we'll get another crack at it later
 -- See Note [Failure in local type signatures]
+--
+-- Panics if we solve any non-equality constraints.  (In runTCSEqualities
+-- we use an error thunk for the evidence bindings.)
 solveEqualities :: String -> TcM a -> TcM a
 solveEqualities callsite thing_inside
   = do { traceTc "solveEqualities {" (text "Called from" <+> text callsite)


=====================================
compiler/GHC/Tc/Solver/Canonical.hs
=====================================
@@ -2144,7 +2144,7 @@ k2 and use this to cast. To wit, from
 
   [X] (tv :: k1) ~ (rhs :: k2)
 
-we go to
+(where [X] is [G], [W], or [D]), we go to
 
   [noDerived X] co :: k2 ~ k1
   [X]           (tv :: k1) ~ ((rhs |> co) :: k1)
@@ -2154,6 +2154,9 @@ where
   noDerived G = G
   noDerived _ = W
 
+For Wanted/Derived, the [X] constraint is "blocked" (not CTyEqCan, is CIrred)
+until the k1~k2 constraint solved: Wrinkle (2).
+
 Wrinkles:
 
  (1) The noDerived step is because Derived equalities have no evidence.
@@ -2166,7 +2169,7 @@ Wrinkles:
        [W] (tv :: k1) ~ ((rhs |> co) :: k1)
      as canonical in the inert set. In particular, we must not unify tv.
      If we did, the Wanted becomes a Given (effectively), and then can
-     rewrite other Wanteds. But that's bad: See Note [Wanteds to not rewrite Wanteds]
+     rewrite other Wanteds. But that's bad: See Note [Wanteds do not rewrite Wanteds]
      in GHC.Tc.Types.Constraint. The problem is about poor error messages. See #11198 for
      tales of destruction.
 


=====================================
compiler/GHC/Tc/Utils/Unify.hs
=====================================
@@ -14,7 +14,7 @@
 module GHC.Tc.Utils.Unify (
   -- Full-blown subsumption
   tcWrapResult, tcWrapResultO, tcWrapResultMono,
-  tcSkolemise, tcSkolemiseScoped, tcSkolemiseAlways, tcSkolemiseET,
+  tcSkolemise, tcSkolemiseScoped, tcSkolemiseET,
   tcSubType, tcSubTypeSigma, tcSubTypePat,
   tcSubMult,
   checkConstraints, checkTvConstraints,
@@ -93,6 +93,9 @@ matchActualFunTySigma
                                    -- Both are used only for error messages)
   -> TcRhoType                     -- Type to analyse: a TcRhoType
   -> TcM (HsWrapper, Scaled TcSigmaType, TcSigmaType)
+-- The /argument/ is a RhoType
+-- The /result/   is an (uninstantiated) SigmaType
+--
 -- See Note [matchActualFunTy error handling] for the first three arguments
 
 -- If   (wrap, arg_ty, res_ty) = matchActualFunTySigma ... fun_ty
@@ -826,10 +829,11 @@ to checkConstraints.
 
 tcSkolemiseScoped is very similar, but differs in two ways:
 
-* It deals specially with just the outer forall, bringing those
-  type variables into lexical scope.  To my surprise, I found that
-  doing this regardless (in tcSkolemise) caused a non-trivial (1%-ish)
-  perf hit on the compiler.
+* It deals specially with just the outer forall, bringing those type
+  variables into lexical scope.  To my surprise, I found that doing
+  this unconditionally in tcSkolemise (i.e. doing it even if we don't
+  need to bring the variables into lexical scope, which is harmless)
+  caused a non-trivial (1%-ish) perf hit on the compiler.
 
 * It always calls checkConstraints, even if there are no skolem
   variables at all.  Reason: there might be nested deferred errors
@@ -837,11 +841,13 @@ tcSkolemiseScoped is very similar, but differs in two ways:
   See Note [When to build an implication] below.
 -}
 
-tcSkolemise, tcSkolemiseScoped, tcSkolemiseAlways
+tcSkolemise, tcSkolemiseScoped
     :: UserTypeCtxt -> TcSigmaType
     -> (TcType -> TcM result)
     -> TcM (HsWrapper, result)
         -- ^ The wrapper has type: spec_ty ~> expected_ty
+-- See Note [Skolemisation] for the differences between
+-- tcSkolemiseScoped and tcSkolemise
 
 tcSkolemiseScoped ctxt expected_ty thing_inside
   = do { (wrap, tv_prs, given, rho_ty) <- topSkolemise expected_ty
@@ -860,9 +866,6 @@ tcSkolemise ctxt expected_ty thing_inside
   = do { res <- thing_inside expected_ty
        ; return (idHsWrapper, res) }
   | otherwise
-  = tcSkolemiseAlways ctxt expected_ty thing_inside
-
-tcSkolemiseAlways ctxt expected_ty thing_inside
   = do  { (wrap, tv_prs, given, rho_ty) <- topSkolemise expected_ty
 
         ; let skol_tvs  = map snd tv_prs
@@ -1946,7 +1949,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 preCheck dflags True tv ty of
+  = case mtvu_check dflags True tv ty of
       MTVU_OK _        -> MTVU_OK ()
       MTVU_Bad         -> MTVU_Bad
       MTVU_HoleBlocker -> MTVU_HoleBlocker
@@ -1960,13 +1963,20 @@ metaTyVarUpdateOK :: DynFlags
                   -> TcType              -- ty :: k2
                   -> MetaTyVarUpdateResult TcType        -- possibly-expanded ty
 -- (metaTyVarUpdateOK tv ty)
--- We are about to update the meta-tyvar tv with ty
--- Check (a) that tv doesn't occur in ty (occurs check)
+-- Checks that the equality tv~ty is OK to be used to rewrite
+-- other equalities.  Equivalently, checks the conditions for CTyEqCan
+--       (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
 --       (c) that ty does not have any blocking coercion holes
 --           See Note [Equalities with incompatible kinds] in "GHC.Tc.Solver.Canonical"
 --
+-- Used in two places:
+--   - In the eager unifier: uUnfilledVar2
+--   - In the canonicaliser: GHC.Tc.Solver.Canonical.canEqTyVar2
+-- Note that in the latter case tv is not necessarily a meta-tyvar,
+-- despite the name of this function.
+
 -- We have two possible outcomes:
 -- (1) Return the type to update the type variable with,
 --        [we know the update is ok]
@@ -1985,7 +1995,7 @@ metaTyVarUpdateOK :: DynFlags
 -- See Note [Refactoring hazard: checkTauTvUpdate]
 
 metaTyVarUpdateOK dflags tv ty
-  = case preCheck dflags False tv ty of
+  = case mtvu_check dflags False tv ty of
          -- False <=> type families not ok
          -- See Note [Prevent unification with type families]
       MTVU_OK _        -> MTVU_OK ty
@@ -1995,8 +2005,8 @@ metaTyVarUpdateOK dflags tv ty
                             Just expanded_ty -> MTVU_OK expanded_ty
                             Nothing          -> MTVU_Occurs
 
-preCheck :: DynFlags -> Bool -> TcTyVar -> TcType -> MetaTyVarUpdateResult ()
--- A quick check for
+mtvu_check :: DynFlags -> Bool -> TcTyVar -> TcType -> MetaTyVarUpdateResult ()
+-- Checks the invariants for CTyEqCan.   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]
@@ -2007,7 +2017,7 @@ preCheck :: DynFlags -> Bool -> TcTyVar -> TcType -> MetaTyVarUpdateResult ()
 -- 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.
 
-preCheck dflags ty_fam_ok tv ty
+mtvu_check dflags ty_fam_ok tv ty
   = fast_check ty
   where
     ok :: MetaTyVarUpdateResult ()


=====================================
docs/users_guide/ghci.rst
=====================================
@@ -2968,7 +2968,7 @@ commonly used commands.
 
     Infers and prints the type of ⟨expression⟩.  For polymorphic types
     it instantiates the 'inferred' forall quantifiers (but not the
-    'specified' ones), solves constraints, and re-generalises.
+    'specified' ones; see :ref:`inferred-vs-specified`), solves constraints, and re-generalises.
 
     .. code-block:: none
 



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/126c219a502d2565d4d381a70ee3f464bce73a94...9f5ec17529213e447e708622289f2c32bb6b0739

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/126c219a502d2565d4d381a70ee3f464bce73a94...9f5ec17529213e447e708622289f2c32bb6b0739
You're receiving this email because of your account on gitlab.haskell.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20200914/75caf53f/attachment-0001.html>


More information about the ghc-commits mailing list