[Git][ghc/ghc][wip/T19847] Improve treatment of type applications in patterns

Simon Peyton Jones (@simonpj) gitlab at gitlab.haskell.org
Sat Jan 28 23:18:10 UTC 2023



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


Commits:
5271af95 by Simon Peyton Jones at 2023-01-28T23:18:52+00:00
Improve treatment of type applications in patterns

This patch fixes a subtle bug in the typechecking of type
applications in patterns, e.g.
   f (MkT @Int @a x y) = ...

See Note [Type applications in patterns] in GHC.Tc.Gen.Pat.

This fixes #19847

- - - - -


6 changed files:

- compiler/GHC/Tc/Gen/Pat.hs
- + testsuite/tests/gadt/T19847.hs
- + testsuite/tests/gadt/T19847a.hs
- + testsuite/tests/gadt/T19847a.stderr
- + testsuite/tests/gadt/T19847b.hs
- testsuite/tests/gadt/all.T


Changes:

=====================================
compiler/GHC/Tc/Gen/Pat.hs
=====================================
@@ -72,9 +72,12 @@ import Control.Arrow  ( second )
 import Control.Monad
 import GHC.Data.FastString
 import qualified Data.List.NonEmpty as NE
+
 import GHC.Data.List.SetOps ( getNth )
 import Language.Haskell.Syntax.Basic (FieldLabelString(..))
 
+import Data.List( partition )
+
 {-
 ************************************************************************
 *                                                                      *
@@ -315,6 +318,11 @@ type Checker inp out =  forall r.
                               , r    -- Result of thing inside
                               )
 
+tcMultiple_ :: Checker inp () -> PatEnv -> [inp] -> TcM r -> TcM r
+tcMultiple_ tc_pat penv args thing_inside
+  = do { (_, res) <- tcMultiple tc_pat penv args thing_inside
+       ; return res }
+
 tcMultiple :: Checker inp out -> Checker [inp] [out]
 tcMultiple tc_pat penv args thing_inside
   = do  { err_ctxt <- getErrCtxt
@@ -861,10 +869,10 @@ tcConPat :: PatEnv -> LocatedN Name
 tcConPat penv con_lname@(L _ con_name) pat_ty arg_pats thing_inside
   = do  { con_like <- tcLookupConLike con_name
         ; case con_like of
-            RealDataCon data_con -> tcDataConPat penv con_lname data_con
-                                                 pat_ty arg_pats thing_inside
-            PatSynCon pat_syn -> tcPatSynPat penv con_lname pat_syn
-                                             pat_ty arg_pats thing_inside
+            RealDataCon data_con -> tcDataConPat con_lname data_con pat_ty
+                                                 penv arg_pats thing_inside
+            PatSynCon pat_syn -> tcPatSynPat con_lname pat_syn pat_ty
+                                             penv arg_pats thing_inside
         }
 
 -- Warn when pattern matching on a GADT or a pattern synonym
@@ -880,12 +888,11 @@ warnMonoLocalBinds
            -- In #20485 this was made into a warning.
        }
 
-tcDataConPat :: PatEnv -> LocatedN Name -> DataCon
+tcDataConPat :: LocatedN Name -> DataCon
              -> Scaled ExpSigmaTypeFRR        -- Type of the pattern
-             -> HsConPatDetails GhcRn -> TcM a
-             -> TcM (Pat GhcTc, a)
-tcDataConPat penv (L con_span con_name) data_con pat_ty_scaled
-             arg_pats thing_inside
+             -> Checker (HsConPatDetails GhcRn) (Pat GhcTc)
+tcDataConPat (L con_span con_name) data_con pat_ty_scaled
+             penv arg_pats thing_inside
   = do  { let tycon = dataConTyCon data_con
                   -- For data families this is the representation tycon
               (univ_tvs, ex_tvs, eq_spec, theta, arg_tys, _)
@@ -921,21 +928,15 @@ tcDataConPat penv (L con_span con_name) data_con pat_ty_scaled
                      -- Why "super"? See Note [Binding when looking up instances]
                      -- in GHC.Core.InstEnv.
 
-        ; let arg_tys' = substScaledTys tenv arg_tys
-              pat_mult = scaledMult pat_ty_scaled
+        ; let arg_tys'       = substScaledTys tenv arg_tys
+              pat_mult       = scaledMult pat_ty_scaled
               arg_tys_scaled = map (scaleScaled pat_mult) arg_tys'
+              con_like       = RealDataCon data_con
 
         -- This check is necessary to uphold the invariant that 'tcConArgs'
         -- is given argument types with a fixed runtime representation.
         -- See test case T20363.
-        ; zipWithM_
-            ( \ i arg_sty ->
-              hasFixedRuntimeRep_syntactic
-                (FRRDataConPatArg data_con i)
-                (scaledThing arg_sty)
-            )
-            [1..]
-            arg_tys'
+        ; checkFixedRuntimeRep data_con arg_tys'
 
         ; traceTc "tcConPat" (vcat [ text "con_name:" <+> ppr con_name
                                    , text "univ_tvs:" <+> pprTyVars univ_tvs
@@ -947,11 +948,15 @@ tcDataConPat penv (L con_span con_name) data_con pat_ty_scaled
                                    , text "pat_ty:" <+> ppr pat_ty
                                    , text "arg_tys':" <+> ppr arg_tys'
                                    , text "arg_pats" <+> ppr arg_pats ])
+
+        ; (univ_ty_args, ex_ty_args) <- splitConTyArgs con_like arg_pats
+
         ; if null ex_tvs && null eq_spec && null theta
           then do { -- The common case; no class bindings etc
                     -- (see Note [Arrows and patterns])
-                    (arg_pats', res) <- tcConArgs (RealDataCon data_con) arg_tys_scaled
-                                                  tenv penv arg_pats thing_inside
+                    (arg_pats', res) <- tcConTyArgs tenv penv univ_ty_args $
+                                        tcConValArgs con_like arg_tys_scaled
+                                                     penv arg_pats thing_inside
                   ; let res_pat = ConPat { pat_con = header
                                          , pat_args = arg_pats'
                                          , pat_con_ext = ConPatTc
@@ -974,8 +979,11 @@ tcDataConPat penv (L con_span con_name) data_con pat_ty_scaled
 
         ; given <- newEvVars theta'
         ; (ev_binds, (arg_pats', res))
-             <- checkConstraints (getSkolemInfo skol_info) ex_tvs' given $
-                tcConArgs (RealDataCon data_con) arg_tys_scaled tenv penv arg_pats thing_inside
+             <- -- See Note [Type applications in patterns] (W4)
+                tcConTyArgs tenv penv univ_ty_args                       $
+                checkConstraints (getSkolemInfo skol_info) ex_tvs' given $
+                tcConTyArgs tenv penv ex_ty_args                         $
+                tcConValArgs con_like arg_tys_scaled penv arg_pats thing_inside
 
         ; let res_pat = ConPat
                 { pat_con   = header
@@ -991,11 +999,10 @@ tcDataConPat penv (L con_span con_name) data_con pat_ty_scaled
         ; return (mkHsWrapPat wrap res_pat pat_ty, res)
         } }
 
-tcPatSynPat :: PatEnv -> LocatedN Name -> PatSyn
+tcPatSynPat :: LocatedN Name -> PatSyn
             -> Scaled ExpSigmaType         -- ^ Type of the pattern
-            -> HsConPatDetails GhcRn -> TcM a
-            -> TcM (Pat GhcTc, a)
-tcPatSynPat penv (L con_span con_name) pat_syn pat_ty arg_pats thing_inside
+            -> Checker (HsConPatDetails GhcRn) (Pat GhcTc)
+tcPatSynPat (L con_span con_name) pat_syn pat_ty penv arg_pats thing_inside
   = do  { let (univ_tvs, req_theta, ex_tvs, prov_theta, arg_tys, ty) = patSynSig pat_syn
 
         ; (subst, univ_tvs') <- newMetaTyVars univ_tvs
@@ -1018,13 +1025,17 @@ tcPatSynPat penv (L con_span con_name) pat_syn pat_ty arg_pats thing_inside
               arg_tys_scaled = map (scaleScaled pat_mult) arg_tys'
               prov_theta' = substTheta tenv prov_theta
               req_theta'  = substTheta tenv req_theta
+              con_like    = PatSynCon pat_syn
 
         ; when (any isEqPred prov_theta) warnMonoLocalBinds
 
         ; mult_wrap <- checkManyPattern pat_ty
             -- See Note [Wrapper returned from tcSubMult] in GHC.Tc.Utils.Unify.
 
+        ; (univ_ty_args, ex_ty_args) <- splitConTyArgs con_like arg_pats
+
         ; wrap <- tc_sub_type penv (scaledThing pat_ty) ty'
+
         ; traceTc "tcPatSynPat" (ppr pat_syn $$
                                  ppr pat_ty $$
                                  ppr ty' $$
@@ -1033,9 +1044,6 @@ tcPatSynPat penv (L con_span con_name) pat_syn pat_ty arg_pats thing_inside
                                  ppr req_theta' $$
                                  ppr arg_tys')
 
-        ; prov_dicts' <- newEvVars prov_theta'
-
-
         ; req_wrap <- instCall (OccurrenceOf con_name) (mkTyVarTys univ_tvs') req_theta'
                       -- Origin (OccurrenceOf con_name):
                       -- see Note [Call-stack tracing of pattern synonyms]
@@ -1055,11 +1063,15 @@ tcPatSynPat penv (L con_span con_name) pat_syn pat_ty arg_pats thing_inside
                  , text "bad_arg_tys:" <+> ppr bad_arg_tys ]
 
         ; traceTc "checkConstraints {" Outputable.empty
+        ; prov_dicts' <- newEvVars prov_theta'
         ; (ev_binds, (arg_pats', res))
-             <- checkConstraints (getSkolemInfo skol_info) ex_tvs' prov_dicts' $
-                tcConArgs (PatSynCon pat_syn) arg_tys_scaled tenv penv arg_pats thing_inside
-
+             <- -- See Note [Type applications in patterns] (W4)
+                tcConTyArgs tenv penv univ_ty_args                             $
+                checkConstraints (getSkolemInfo skol_info) ex_tvs' prov_dicts' $
+                tcConTyArgs tenv penv ex_ty_args                               $
+                tcConValArgs con_like arg_tys_scaled penv arg_pats thing_inside
         ; traceTc "checkConstraints }" (ppr ev_binds)
+
         ; let res_pat = ConPat { pat_con   = L con_span $ PatSynCon pat_syn
                                , pat_args  = arg_pats'
                                , pat_con_ext = ConPatTc
@@ -1073,6 +1085,14 @@ tcPatSynPat penv (L con_span con_name) pat_syn pat_ty arg_pats thing_inside
         ; pat_ty <- readExpType (scaledThing pat_ty)
         ; return (mkHsWrapPat (wrap <.> mult_wrap) res_pat pat_ty, res) }
 
+checkFixedRuntimeRep :: DataCon -> [Scaled TcSigmaTypeFRR] -> TcM ()
+checkFixedRuntimeRep data_con arg_tys
+  = zipWithM_ check_one [1..] arg_tys
+  where
+    check_one i arg_ty = hasFixedRuntimeRep_syntactic
+                            (FRRDataConPatArg data_con i)
+                            (scaledThing arg_ty)
+
 {- Note [Call-stack tracing of pattern synonyms]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Consider
@@ -1187,84 +1207,126 @@ Suppose (coi, tys) = matchExpectedConType data_tc pat_ty
    error messages; it's a purely internal thing
 -}
 
-{-
-Note [Typechecking type applications in patterns]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-How should we typecheck type applications in patterns, such as
+{- Note [Type applications in patterns]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Type applications in patterns are enabled by -XTypeAbstractions.
+For example:
    f :: Either (Maybe a) [b] -> blah
    f (Left @x @[y] (v::Maybe x)) = blah
 
-It's quite straightforward, and very similar to the treatment of
-pattern signatures.
+How should we typecheck them?  The basic plan is pretty simple, and is
+all done in tcConTyArg. For each type argument:
+
+* Step 1:
+    * bind the newly-in-scope type variables (here `x` or `y`) to
+      unification variables, say `x0` or `y0`
 
-* Step 1: bind the newly-in-scope type variables x and y to fresh
-  unification variables, say x0 and y0.
+    * typecheck the type argument, `@x` or `@[y]` to get the
+      types `x0` or `[y0]`.
 
-* Step 2: typecheck those type arguments, @x and @[y], to get the
-  types x0 and [y0].
+    This step is done by `tcHsPatSigType`, similar to the way we
+    deal with pattern signatures.
 
-* Step 3: Unify those types with the type arguments we expect,
-  in this case (Maybe a) and [b].  These unifications will
-  (perhaps after the constraint solver has done its work)
+* Step 2: Unify those types with the type arguments we expect from
+  the context, in this case (Maybe a) and [b].  These unifications
+  will (perhaps after the constraint solver has done its work)
   unify   x0 := Maybe a
           y0 := b
   Thus we learn that x stands for (Maybe a) and y for b.
 
-Wrinkles:
-
-* Surprisingly, we can discard the coercions arising from
-  these unifications.  The *only* thing the unification does is
-  to side-effect those unification variables, so that we know
-  what type x and y stand for; and cause an error if the equality
-  is not soluble.  It's a bit like a constraint arising
-  from a functional dependency, where we don't use the evidence.
-
-* Exactly the same works for existential arguments
-     data T where
-        MkT :: a -> a -> T
-     f :: T -> blah
-     f (MkT @x v w) = ...
-   Here we create a fresh unification variable x0 for x, and
-   unify it with the fresh existential variable bound by the pattern.
-
-* Note that both here and in pattern signatures the unification may
-  not even end up unifying the variable.  For example
-     type S a b = a
-     f :: Maybe a -> Bool
-     f (Just @(S a b) x) = True :: b
-   In Step 3 we will unify (S a0 b0 ~ a), which succeeds, but has no
-   effect on the unification variable b0, to which 'b' is bound.
-   Later, in the RHS, we find that b0 must be Bool, and unify it there.
-   All is fine.
+* Step 3: Extend the lexical context to bind `x` to `x0` and
+  `y` to `y0`, and typecheck the body of the pattern match.
+
+However there are several quite tricky wrinkles.
+
+(W1) Surprisingly, we can discard the coercions arising from
+     these unifications.  The *only* thing the unification does is
+     to side-effect those unification variables, so that we know
+     what type x and y stand for; and cause an error if the equality
+     is not soluble.  It's a bit like a constraint arising
+     from a functional dependency, where we don't use the evidence.
+
+(W2) Note that both here and in pattern signatures the unification may
+     not even end up unifying the variable.  For example
+       type S a b = a
+       f :: Maybe a -> Bool
+       f (Just @(S a b) x) = True :: b
+     In Step 2 we will unify (S a0 b0 ~ a), which succeeds, but has no
+     effect on the unification variable b0, to which 'b' is bound.
+     Later, in the RHS, we find that b0 must be Bool, and unify it there.
+     All is fine.
+
+(W3) The order of the arguments to the /data constructor/ may differ from
+     the order of the arguments to the /type constructor/. Example
+         data T a b where { MkT :: forall c d. (c,d) -> T d c }
+         f :: T Int Bool -> blah
+         f (MkT @x @y p) = ...
+     The /first/ type argument to `MkT`, namely `@x` corresponds to the
+     /second/ argument to `T` in the type `T Int Bool`.  So `x` is bound
+     to `Bool` -- not to `Int`!.  That is why splitConTyArgs uses
+     conLikeUserTyVarBinders to match up with the user-supplied type arguments
+     in the pattern, not dataConUnivTyVars/dataConExTyVars.
+
+(W4) A similar story works for existentials, but it is subtly different
+     (#19847).  Consider
+         data T a where { MkT :: forall a b. a -> b -> T a }
+         f :: T Int -> blah
+         f (MkT @x @y v w) = blah
+     Here we create a fresh unification variables x0,y0 for x,y and
+     unify x0~Int, y0~b, where b is the fresh existential variable bound by
+     the pattern. But
+       * (x0~Int) must be /outside/ the implication constraint
+       * (y0~b)   must be /inside/ it
+     Thus:
+         x0~Int,  (forall[2] a. (x0 ~ a, ...constraints-from-blah...))
+
+     We need (x0~Int) /outside/ so that it can influence the type of the
+     pattern in an inferred setting, e.g.
+         g :: T _ -> blah
+         g (MkT @Int @y v w) = blah
+     Here we want to infer `g` to have type `T Int -> blah`. If the
+     (x0~Int) was inside the implication, and the the constructor bound
+     equality constraints, `x0` would be untouchable. This was the root
+     cause of #19847.
+
+     We need (y0~b) to be /inside/ the implication, so that `b` is in
+     scope.  Also we may need the equalites to prove the implication
+     Example   data T a where
+                 MkT :: forall p q. T (p,q)
+               f :: T (Int,Bool) -> blah
+               f (MkT @Int @Bool) = ...
+     We get the implication
+        forall[2] p q. (p,q)~(Int,Bool) => (p ~ Int, q ~ Bool, ...)
+     where the Given comes from the GADT match, while (p~Int, q~Bool)
+     comes from matching the type arguments.
+
+     Wow.  That's all quite subtle! See the long discussion on #19847.  We
+     must treat universal and existential arguments separately, even though
+     they are all mixed up (W3).  The function splitConTyArgs separates the
+     universals from existentials; and we build the implication between
+     typechecking the two sets:
+           tcConTyArgs ... univ_ty_args    $
+           checkConstraints ...            $
+           tcConTyArgs ... ex_ty_args      $
+           ..typecheck body..
+     You can see this code shape in tcDataConPat and tcPatSynPat.
+
+     Where pattern synonyms are involved, this two-level split may not be
+     enough.  See #22328 for the story.
 -}
 
-tcConArgs :: ConLike
-          -> [Scaled TcSigmaTypeFRR]
-          -> Subst            -- Instantiating substitution for constructor type
-          -> Checker (HsConPatDetails GhcRn) (HsConPatDetails GhcTc)
-tcConArgs con_like arg_tys tenv penv con_args thing_inside = case con_args of
+tcConValArgs :: ConLike
+             -> [Scaled TcSigmaTypeFRR]
+             -> Checker (HsConPatDetails GhcRn) (HsConPatDetails GhcTc)
+tcConValArgs con_like arg_tys penv con_args thing_inside = case con_args of
   PrefixCon type_args arg_pats -> do
+        -- NB: type_args already dealt with
+        -- See Note [Type applications in patterns]
         { checkTc (con_arity == no_of_args)     -- Check correct arity
                   (arityErr (text "constructor") con_like con_arity no_of_args)
 
-              -- forgetting to filter out inferred binders led to #20443
-        ; let con_spec_binders = filter ((== SpecifiedSpec) . binderFlag) $
-                                 conLikeUserTyVarBinders con_like
-        ; checkTc (type_args `leLength` con_spec_binders)
-                  (TcRnTooManyTyArgsInConPattern con_like (length con_spec_binders) (length type_args))
-
         ; let pats_w_tys = zipEqual "tcConArgs" arg_pats arg_tys
-        ; (type_args', (arg_pats', res))
-            <- tcMultiple tcConTyArg penv type_args $
-               tcMultiple tcConArg penv pats_w_tys thing_inside
-
-          -- This unification is straight from Figure 7 of
-          -- "Type Variables in Patterns", Haskell'18
-        ; _ <- zipWithM (unifyType Nothing) type_args' (substTyVars tenv $
-                                                        binderVars con_spec_binders)
-          -- OK to drop coercions here. These unifications are all about
-          -- guiding inference based on a user-written type annotation
-          -- See Note [Typechecking type applications in patterns]
+        ; (arg_pats', res) <- tcMultiple tcConArg penv pats_w_tys thing_inside
 
         ; return (PrefixCon type_args arg_pats', res) }
     where
@@ -1321,23 +1383,63 @@ tcConArgs con_like arg_tys tenv penv con_args thing_inside = case con_args of
           -- dataConFieldLabels will be empty (and each field in the pattern
           -- will generate an error below).
 
-tcConTyArg :: Checker (HsConPatTyArg GhcRn) TcType
-tcConTyArg penv (HsConPatTyArg _ rn_ty) thing_inside
+
+splitConTyArgs :: ConLike -> HsConPatDetails GhcRn
+               -> TcM ( [(HsConPatTyArg GhcRn, TyVar)]    -- Universals
+                      , [(HsConPatTyArg GhcRn, TyVar)] )  -- Existentials
+-- See Note [Type applications in patterns] (W4)
+splitConTyArgs con_like (PrefixCon type_args _)
+  = do { checkTc (type_args `leLength` con_spec_bndrs)
+                 (TcRnTooManyTyArgsInConPattern con_like
+                          (length con_spec_bndrs) (length type_args))
+       ; if null ex_tvs
+         then return (bndr_ty_arg_prs, [])
+         else return (partition is_universal bndr_ty_arg_prs) }
+  where
+    ex_tvs = conLikeExTyCoVars con_like
+    con_spec_bndrs = [ tv | Bndr tv SpecifiedSpec <- conLikeUserTyVarBinders con_like ]
+        -- conLikUserTyVarBinders: see (W3) in
+        --    Note [Type applications in patterns]
+        -- SpecifiedSpec: forgetting to filter out inferred binders led to #20443
+
+    bndr_ty_arg_prs = type_args `zip` con_spec_bndrs
+                      -- The zip truncates to length(type_args)
+
+    is_universal (_, tv) = not (tv `elem` ex_tvs)
+
+splitConTyArgs _ _ = return ([], []) -- Only PrefixCon supports type arguments
+
+tcConTyArgs :: Subst -> PatEnv -> [(HsConPatTyArg GhcRn, TyVar)]
+            -> TcM a -> TcM a
+tcConTyArgs tenv penv prs thing_inside
+  = tcMultiple_ (tcConTyArg tenv) penv prs thing_inside
+
+tcConTyArg :: Subst -> Checker (HsConPatTyArg GhcRn, TyVar) ()
+tcConTyArg tenv penv (HsConPatTyArg _ rn_ty, con_tv) thing_inside
   = do { (sig_wcs, sig_ibs, arg_ty) <- tcHsPatSigType TypeAppCtxt HM_TyAppPat rn_ty AnyKind
                -- AnyKind is a bit suspect: it really should be the kind gotten
                -- from instantiating the constructor type. But this would be
                -- hard to get right, because earlier type patterns might influence
                -- the kinds of later patterns. In any case, it all gets checked
-               -- by the calls to unifyType in tcConArgs, which will also unify
-               -- kinds.
+               -- by the calls to unifyType below which unifies kinds
+
        ; case NE.nonEmpty sig_ibs of
            Just sig_ibs_ne | inPatBind penv ->
              addErr (TcRnCannotBindTyVarsInPatBind sig_ibs_ne)
            _ -> pure ()
+
+          -- This unification is straight from Figure 7 of
+          -- "Type Variables in Patterns", Haskell'18
+          -- OK to drop coercions here. These unifications are all about
+          -- guiding inference based on a user-written type annotation
+          -- See Note [Type applications in patterns] (W1)
+       ; _ <- unifyType Nothing arg_ty (substTyVar tenv con_tv)
+
        ; result <- tcExtendNameTyVarEnv sig_wcs $
                    tcExtendNameTyVarEnv sig_ibs $
                    thing_inside
-       ; return (arg_ty, result) }
+
+       ; return ((), result) }
 
 tcConArg :: Checker (LPat GhcRn, Scaled TcSigmaType) (LPat GhcTc)
 tcConArg penv (arg_pat, Scaled arg_mult arg_ty)


=====================================
testsuite/tests/gadt/T19847.hs
=====================================
@@ -0,0 +1,15 @@
+{-# LANGUAGE GADTs, PatternSynonyms, ViewPatterns, ScopedTypeVariables #-}
+
+module T19847 where
+
+import Data.Kind
+import Type.Reflection
+
+pattern Is :: forall (b :: Type) (a :: Type). Typeable b => (a ~ b) => TypeRep a
+pattern Is <- (eqTypeRep (typeRep @b) -> Just HRefl)
+  where Is = typeRep
+
+def :: TypeRep a -> a
+def x = case x of
+  Is @Int  -> 10
+  Is @Bool -> False


=====================================
testsuite/tests/gadt/T19847a.hs
=====================================
@@ -0,0 +1,14 @@
+{-# LANGUAGE LambdaCase, GADTs, ScopedTypeVariables, TypeAbstractions #-}
+
+module T19847a where
+
+data T a b c where
+  MkT :: forall c y x b. (x~y, c~[x], Ord x) => x -> y -> T (x,y) b c
+
+f :: forall b c. (T (Int,Int) b c -> Bool) -> (b,c)
+f = error "urk"
+
+h = f (\case { MkT @_ @_ @_ @Int p q -> True })
+-- Check that the @Int argument can affect
+-- the type at which `f` is instantiated
+-- So h :: forall c. (Int,c)


=====================================
testsuite/tests/gadt/T19847a.stderr
=====================================
@@ -0,0 +1,12 @@
+TYPE SIGNATURES
+  f :: forall b c. (T (Int, Int) b c -> Bool) -> (b, c)
+  h :: forall {c}. (Int, c)
+TYPE CONSTRUCTORS
+  data type T{4} :: forall {k}. * -> k -> * -> *
+    roles nominal nominal phantom nominal
+DATA CONSTRUCTORS
+  MkT :: forall {k} c y x (b :: k).
+         (x ~ y, c ~ [x], Ord x) =>
+         x -> y -> T (x, y) b c
+Dependent modules: []
+Dependent packages: [base-4.18.0.0]


=====================================
testsuite/tests/gadt/T19847b.hs
=====================================
@@ -0,0 +1,10 @@
+{-# LANGUAGE TypeAbstractions, GADTs #-}
+
+module T19847b where
+
+import Data.Kind
+
+data T (a :: Type) b where
+  MkT4 :: forall a b. b ~ a => T a b
+
+foo x = (case x of MkT4 @Bool ->  ()) :: ()


=====================================
testsuite/tests/gadt/all.T
=====================================
@@ -126,3 +126,6 @@ test('SynDataRec', normal, compile, [''])
 test('T20485', normal, compile, [''])
 test('T20485a', normal, compile, [''])
 test('T22235', normal, compile, [''])
+test('T19847', normal, compile, [''])
+test('T19847a', normal, compile, ['-ddump-types'])
+test('T19847b', normal, compile, [''])



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/5271af95a86362a506ff93ea4de9e938fc9fa8f4

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/5271af95a86362a506ff93ea4de9e938fc9fa8f4
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/20230128/8525096f/attachment-0001.html>


More information about the ghc-commits mailing list