[commit: ghc] ghc-8.2: Really fix Trac #14158 (13cd53d)

git at git.haskell.org git at git.haskell.org
Tue Sep 19 21:10:41 UTC 2017


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

On branch  : ghc-8.2
Link       : http://ghc.haskell.org/trac/ghc/changeset/13cd53df15ab38a29c5dfcbdd916ae2ada6ff979/ghc

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

commit 13cd53df15ab38a29c5dfcbdd916ae2ada6ff979
Author: Simon Peyton Jones <simonpj at microsoft.com>
Date:   Wed Aug 30 16:19:37 2017 +0100

    Really fix Trac #14158
    
    I dug more into how #14158 started working. I temporarily reverted the
    patch that "fixed" it, namely
    
        commit a6c448b403dbe8720178ca82100f34baedb1f47e
        Author: Simon Peyton Jones <simonpj at microsoft.com>
        Date:   Mon Aug 28 17:33:59 2017 +0100
    
        Small refactor of getRuntimeRep
    
    Sure enough, there was a real bug, described in the new
    TcExpr Note [Visible type application zonk]
    
    In general, syntactic substituion should be kind-preserving!
    Maybe we should check that invariant...
    
    (cherry picked from commit 2c133b67df374c73bc8069cefd7d57e1d2a14fc3)


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

13cd53df15ab38a29c5dfcbdd916ae2ada6ff979
 compiler/typecheck/TcExpr.hs                       | 44 +++++++++++++++++++++-
 compiler/types/Type.hs                             |  1 +
 testsuite/tests/typecheck/should_compile/T14158.hs |  7 ++++
 testsuite/tests/typecheck/should_compile/all.T     |  1 +
 4 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/compiler/typecheck/TcExpr.hs b/compiler/typecheck/TcExpr.hs
index 6e2f0eb..8e65e61 100644
--- a/compiler/typecheck/TcExpr.hs
+++ b/compiler/typecheck/TcExpr.hs
@@ -63,7 +63,7 @@ import PrelNames
 import DynFlags
 import SrcLoc
 import Util
-import VarEnv  ( emptyTidyEnv )
+import VarEnv  ( emptyTidyEnv, mkInScopeSet )
 import ListSetOps
 import Maybes
 import Outputable
@@ -1236,7 +1236,18 @@ tcArgs fun orig_fun_ty fun_orig orig_args herald
                                 , ppr inner_ty, pprTyVar tv
                                 , ppr vis ]) )
                     ; ty_arg <- tcHsTypeApp hs_ty_arg kind
-                    ; let insted_ty = substTyWithUnchecked [tv] [ty_arg] inner_ty
+
+                    ; inner_ty <- zonkTcType inner_ty
+                          -- See Note [Visible type application zonk]
+
+                    ; let in_scope  = mkInScopeSet (tyCoVarsOfTypes [upsilon_ty, ty_arg])
+                          insted_ty = substTyWithInScope in_scope [tv] [ty_arg] inner_ty
+                                      -- NB: tv and ty_arg have the same kind, so this
+                                      --     substitution is kind-respecting
+                    ; traceTc "VTA" (vcat [ppr tv, ppr kind
+                                          , ppr ty_arg
+                                          , ppr (typeKind ty_arg)
+                                          , ppr insted_ty ])
                     ; (inner_wrap, args', res_ty)
                         <- go acc_args (n+1) insted_ty args
                    -- inner_wrap :: insted_ty "->" (map typeOf args') -> res_ty
@@ -1268,6 +1279,35 @@ tcArgs fun orig_fun_ty fun_orig orig_args herald
                text "Cannot apply expression of type" <+> quotes (ppr ty) $$
                text "to a visible type argument" <+> quotes (ppr arg) }
 
+{- Note [Visible type application zonk]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* Substitutions should be kind-preserving, so we need kind(tv) = kind(ty_arg).
+
+* tcHsTypeApp only guarantees that
+    - ty_arg is zonked
+    - kind(zonk(tv)) = kind(ty_arg)
+  (checkExpectedKind zonks as it goes).
+
+So we must zonk inner_ty as well, to guarantee consistency between zonk(tv)
+and inner_ty.  Otherwise we can build an ill-kinded type.  An example was
+Trac #14158, where we had:
+   id :: forall k. forall (cat :: k -> k -> *). forall (a :: k). cat a a
+and we had the visible type application
+  id @(->)
+
+* We instantiated k := kappa, yielding
+    forall (cat :: kappa -> kappa -> *). forall (a :: kappa). cat a a
+* Then we called tcHsTypeApp (->) with expected kind (kappa -> kappa -> *).
+* That instantiated (->) as ((->) q1 q1), and unified kappa := q1,
+  Here q1 :: RuntimeRep
+* Now we substitute
+     cat  :->  (->) q1 q1 :: TYPE q1 -> TYPE q1 -> *
+  but we must first zonk the inner_ty to get
+      forall (a :: TYPE q1). cat a a
+  so that the result of substitution is well-kinded
+  Failing to do so led to Trac #14158.
+-}
+
 ----------------
 tcArg :: LHsExpr Name                    -- The function (for error messages)
       -> LHsExpr Name                    -- Actual arguments
diff --git a/compiler/types/Type.hs b/compiler/types/Type.hs
index 1400ff7..23ff47d 100644
--- a/compiler/types/Type.hs
+++ b/compiler/types/Type.hs
@@ -178,6 +178,7 @@ module Type (
         substTyUnchecked, substTysUnchecked, substThetaUnchecked,
         substTyWithUnchecked,
         substCoUnchecked, substCoWithUnchecked,
+        substTyWithInScope,
         substTyVarBndr, substTyVar, substTyVars,
         cloneTyVarBndr, cloneTyVarBndrs, lookupTyVar,
 
diff --git a/testsuite/tests/typecheck/should_compile/T14158.hs b/testsuite/tests/typecheck/should_compile/T14158.hs
new file mode 100644
index 0000000..88bb82e
--- /dev/null
+++ b/testsuite/tests/typecheck/should_compile/T14158.hs
@@ -0,0 +1,7 @@
+{-# LANGUAGE TypeApplications #-}
+
+module T14158 where
+
+import qualified Control.Category as Cat
+
+foo = (Cat.id @(->) >>=)
diff --git a/testsuite/tests/typecheck/should_compile/all.T b/testsuite/tests/typecheck/should_compile/all.T
index 6671291..d718ba3 100644
--- a/testsuite/tests/typecheck/should_compile/all.T
+++ b/testsuite/tests/typecheck/should_compile/all.T
@@ -563,3 +563,4 @@ test('T13915b', normal, compile, [''])
 test('T13984', normal, compile, [''])
 test('T14128', normal, multimod_compile, ['T14128Main', '-v0'])
 test('T14154', normal, compile, [''])
+test('T14158', normal, compile, [''])



More information about the ghc-commits mailing list