[commit: ghc] wip/rae-new-coercible: Don't allow newtypes at top-level on RHS of R equalities. (1376c00)

git at git.haskell.org git at git.haskell.org
Tue Dec 2 20:44:05 UTC 2014


Repository : ssh://git@git.haskell.org/ghc

On branch  : wip/rae-new-coercible
Link       : http://ghc.haskell.org/trac/ghc/changeset/1376c00a6f719d596849349c6f6cff4455efe868/ghc

>---------------------------------------------------------------

commit 1376c00a6f719d596849349c6f6cff4455efe868
Author: Richard Eisenberg <eir at cis.upenn.edu>
Date:   Mon Dec 1 16:41:45 2014 -0500

    Don't allow newtypes at top-level on RHS of R equalities.


>---------------------------------------------------------------

1376c00a6f719d596849349c6f6cff4455efe868
 compiler/typecheck/TcCanonical.lhs | 76 +++++++++++++++++++++++++++++---------
 1 file changed, 58 insertions(+), 18 deletions(-)

diff --git a/compiler/typecheck/TcCanonical.lhs b/compiler/typecheck/TcCanonical.lhs
index 19b9975..e1e74cc 100644
--- a/compiler/typecheck/TcCanonical.lhs
+++ b/compiler/typecheck/TcCanonical.lhs
@@ -806,6 +806,26 @@ As this point we have an insoluble constraint, like Int~Bool.
    generating two (or more) insoluble fundep constraints from the same
    class constraint.
 
+Note [No top-level newtypes on RHS]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Suppose we're in this situation:
+
+ work item:  [W] c1 : a ~R b
+             [G] c2 : b ~R Id a
+
+where
+  newtype Id a = Id a
+
+Further, suppose flattening `a` doesn't do anything. Then, we'll flatten the
+RHS of c1 and have a new [W] c3 : a ~R Id a. If we just blindly proceed, we'll
+fail in canEqTyVar2 with an occurs-check. What we really need to do is to
+unwrap the `Id a` in the RHS. This is exactly analogous to the requirement for
+no top-level type families on the RHS of a nominal equality. The only
+annoyance is that the flattener doesn't do this work for us when flattening
+the RHS, so we have to catch this case here and then go back to the beginning
+of can_eq_nc. We know that this can't loop forever because we require that
+flattening the RHS actually made progress. (If it didn't, then we really
+*should* fail with an occurs-check!)
 
 \begin{code}
 canCFunEqCan :: CtEvidence 
@@ -845,24 +865,44 @@ canEqTyVar ev eq_rel swapped tv1 ty2 ps_ty2              -- ev :: tv ~ s2
        ; let fmode = mkFlattenEnv ev FM_FlattenAll  -- the FM_ param is ignored
        ; mb_yes <- flattenTyVarOuter fmode tv1
        ; case mb_yes of
-           Right (ty1, co1, _) -- co1 :: ty1 ~ tv1
-                     -> do { mb <- rewriteEqEvidence ev eq_rel swapped ty1 ps_ty2
-                                     co1 (mkTcReflCo (eqRelRole eq_rel) ps_ty2)
-                           ; traceTcS "canEqTyVar2" (vcat [ppr tv1, ppr ty2, ppr swapped, ppr ty1,
-                                                           ppUnless (isDerived ev) (ppr co1)])
-                           ; case mb of
-                               Stop ev s           -> return (Stop ev s)
-                               ContinueWith new_ev -> can_eq_nc new_ev eq_rel ty1 ty1 ty2 ps_ty2 }
-
-           Left tv1' -> do { -- FM_Avoid commented out: see Note [Lazy flattening] in TcFlatten
-                             -- let fmode = FE { fe_ev = ev, fe_mode = FM_Avoid tv1' True }
-                                 -- Flatten the RHS less vigorously, to avoid gratuitous flattening
-                                 -- True <=> xi2 should not itself be a type-function application
-                             let fmode = mkFlattenEnv ev FM_FlattenAll
-                           ; (xi2, co2) <- flatten fmode ps_ty2 -- co2 :: xi2 ~ ps_ty2
-                                           -- Use ps_ty2 to preserve type synonyms if poss
-                           ; dflags <- getDynFlags
-                           ; canEqTyVar2 dflags ev eq_rel swapped tv1' xi2 co2 } }
+           Right (ty1, co1, _) -> -- co1 :: ty1 ~ tv1
+             do { mb <- rewriteEqEvidence ev eq_rel swapped ty1 ps_ty2
+                          co1 (mkTcReflCo (eqRelRole eq_rel) ps_ty2)
+                ; traceTcS "canEqTyVar2" (vcat [ppr tv1, ppr ty2, ppr swapped, ppr ty1,
+                                                ppUnless (isDerived ev) (ppr co1)])
+                ; case mb of
+                    Stop ev s           -> return (Stop ev s)
+                    ContinueWith new_ev -> can_eq_nc new_ev eq_rel ty1 ty1 ty2 ps_ty2 }
+
+           Left tv1' ->
+             do { -- FM_Avoid commented out: see Note [Lazy flattening] in TcFlatten
+                  -- let fmode = FE { fe_ev = ev, fe_mode = FM_Avoid tv1' True }
+                  -- Flatten the RHS less vigorously, to avoid gratuitous flattening                 -- True <=> xi2 should not itself be a type-function application
+                  let fmode = mkFlattenEnv ev FM_FlattenAll
+                ; (xi2, co2) <- flatten fmode ps_ty2 -- co2 :: xi2 ~ ps_ty2
+                                -- Use ps_ty2 to preserve type synonyms if poss
+                ; traceTcS "canEqTyVar flat LHS"
+                           (vcat [ ppr tv1, ppr tv1', ppr ty2, ppr swapped,
+                                   ppr xi2 ])
+                ; dflags <- getDynFlags
+                ; case eq_rel of
+                    ReprEq   -- See Note [No top-level newtypes on RHS]
+                      | Just (tc2, _) <- tcSplitTyConApp_maybe xi2
+                      , isNewTyCon tc2
+                      , not (ps_ty2 `eqType` xi2)
+                      -> do { let xi1  = mkTyVarTy tv1'
+                                  role = eqRelRole eq_rel
+                            ; mb <- rewriteEqEvidence ev eq_rel swapped
+                                                      xi1 xi2
+                                                      (mkTcReflCo role xi1) co2
+                            ; traceTcS "canEqTyVar exposed newtype"
+                                       (vcat [ ppr tv1', ppr ps_ty2
+                                             , ppr xi2, ppr tc2 ])
+                            ; case mb of
+                                Stop ev s           -> return (Stop ev s)
+                                ContinueWith new_ev ->
+                                  can_eq_nc new_ev eq_rel xi1 xi1 xi2 xi2 }
+                    _ -> canEqTyVar2 dflags ev eq_rel swapped tv1' xi2 co2 } }
 
 canEqTyVar2 :: DynFlags
             -> CtEvidence   -- olhs ~ orhs (or, if swapped, orhs ~ olhs)



More information about the ghc-commits mailing list