Vladislav Zavialov pushed to branch wip/int-index/rta-patsyn at Glasgow Haskell Compiler / GHC Commits: 82063234 by Vladislav Zavialov at 2026-08-07T06:14:29+03:00 Discard type arguments in tcPatToExpr (#27440, #27583) The builder expression of an implicitly bidirectional pattern synonym must not mention types written in the RHS: * Invisible type arguments led to a panic (#27440) * Required type arguments failed with out-of-scope variables (#27583) Both are now discarded, following the precedent established by pattern signatures (#9867). Discarding type arguments takes some care: a type pattern cannot be told from a value pattern by syntax alone, as the `type` keyword may be omitted. Consider: data T a b c where MkT :: forall a. forall b c -> a -> T a b c pattern P :: x -> T x y z pattern P x = MkT @a (type b) c x In P's right-hand side, `@a` and `type b` are clearly type arguments, but what about `c` and `x`? We can only tell by matching the patterns against MkT's type. So tcPatToExpr now runs in TcM and matches the arguments against the constructor's TyVarBinders using zipPatsBndrs, which is made public for this purpose. The resulting builder is $bP x = MkT _ _ x. See Note [Discarding types in the builder expression]. Test cases: T27440a T27440b T27440c T27440d T27440e T27583a T27583b T27583c T27583d T27583e T27583f T27583g Metric Increase: LinkableUsage02 Metric Decrease: T27336 Assisted-by: Claude Opus 5 - - - - - 23 changed files: - + changelog.d/T27440 - + changelog.d/T27583 - compiler/GHC/Tc/Gen/Pat.hs - compiler/GHC/Tc/TyCl/PatSyn.hs - + testsuite/tests/patsyn/should_compile/T27440a.hs - + testsuite/tests/patsyn/should_compile/T27440b.hs - + testsuite/tests/patsyn/should_compile/T27440c.hs - testsuite/tests/patsyn/should_compile/all.T - + testsuite/tests/patsyn/should_fail/T27440d.hs - + testsuite/tests/patsyn/should_fail/T27440d.stderr - testsuite/tests/patsyn/should_fail/all.T - + testsuite/tests/vdq-rta/should_compile/T27583a.hs - + testsuite/tests/vdq-rta/should_compile/T27583b.hs - + testsuite/tests/vdq-rta/should_compile/T27583c.hs - + testsuite/tests/vdq-rta/should_compile/T27583d.hs - + testsuite/tests/vdq-rta/should_compile/T27583e.hs - + testsuite/tests/vdq-rta/should_compile/T27583g.hs - testsuite/tests/vdq-rta/should_compile/all.T - + testsuite/tests/vdq-rta/should_fail/T27440e.hs - + testsuite/tests/vdq-rta/should_fail/T27440e.stderr - + testsuite/tests/vdq-rta/should_fail/T27583f.hs - + testsuite/tests/vdq-rta/should_fail/T27583f.stderr - testsuite/tests/vdq-rta/should_fail/all.T Changes: ===================================== changelog.d/T27440 ===================================== @@ -0,0 +1,8 @@ +section: compiler +issues: #27440 +mrs: !16434 +synopsis: + Fix a panic on ``@ty`` in a pattern synonym RHS +description: + An invisible type argument (``@ty``) in the right-hand side of an implicitly + bidirectional pattern synonym no longer causes a panic. ===================================== changelog.d/T27583 ===================================== @@ -0,0 +1,9 @@ +section: compiler +issues: #27583 +mrs: !16434 +synopsis: + Fix spurious out-of-scope errors from ``type ty`` in a pattern synonym RHS +description: + A required type argument with an explicit namespace specifier (``type ty``) + in the right-hand side of an implicitly bidirectional pattern synonym no + longer reports variables bound by the pattern as out of scope. ===================================== compiler/GHC/Tc/Gen/Pat.hs ===================================== @@ -16,6 +16,7 @@ module GHC.Tc.Gen.Pat , tcCheckPat, tcCheckPat_O, tcInferPat , tcMatchPats , addDataConStupidTheta + , zipPatsBndrs ) where @@ -1727,7 +1728,7 @@ split_con_ty_args :: LexicalFixity -- How to wrap value arguments , [(HsTyPat GhcRn, TyVar)] -- Existentials , HsConPatDetails GhcRn ) -- Value arguments split_con_ty_args fixity con_like arg_pats = do - (bndr_ty_arg_prs, value_args) <- zip_pats_bndrs arg_pats (conLikeUserTyVarBinders con_like) + (bndr_ty_arg_prs, value_args) <- zipPatsBndrs arg_pats (conLikeUserTyVarBinders con_like) return $ if null ex_tvs -- Short cut common case then (bndr_ty_arg_prs, [], mk_details fixity value_args) else let (ex_prs, univ_prs) = partition is_existential bndr_ty_arg_prs @@ -1743,24 +1744,75 @@ split_con_ty_args fixity con_like arg_pats = do -- InfixCon becomes PrefixCon if there are fewer than 2 value arguments. -- Test case: T25127_infix -zip_pats_bndrs :: [LPat GhcRn] -> [TyVarBinder] -> TcM ([(HsTyPat GhcRn, TyVar)], [LPat GhcRn]) -zip_pats_bndrs (L loc pat : pats) (Bndr tv vis : tvbs) +-- | Line the arguments of a 'ConPat' up against the 'TyVarBinder's of its +-- 'ConLike', returning the type arguments with the binders they instantiate, +-- and the remaining value arguments. +-- +-- See Note [Zipping ConPat arguments with TyVarBinders] +-- +-- Precondition: 'check_con_pat_arity' has passed for these arguments, so that +-- we never run out of patterns while a required binder remains. +zipPatsBndrs :: [LPat GhcRn] -> [TyVarBinder] -> TcM ([(HsTyPat GhcRn, TyVar)], [LPat GhcRn]) +zipPatsBndrs (L loc pat : pats) (Bndr tv vis : tvbs) | isVisibleForAllTyFlag vis = do { tp <- setSrcSpanA loc $ pat_to_type_pat pat - ; (prs, pats') <- zip_pats_bndrs pats tvbs + ; (prs, pats') <- zipPatsBndrs pats tvbs ; return ((tp, tv) : prs, pats') } | InvisPat pat_spec tp <- pat , Invisible spec <- vis , pat_spec == spec - = do { (prs, pats') <- zip_pats_bndrs pats tvbs + = do { (prs, pats') <- zipPatsBndrs pats tvbs ; return ((tp, tv):prs, pats') } -zip_pats_bndrs pats (Bndr _ vis : tvbs) - -- zip_pats_bndrs [] (Bndr _ Required : tvbs) +zipPatsBndrs pats (Bndr _ vis : tvbs) + -- zipPatsBndrs [] (Bndr _ Required : tvbs) -- is ruled out by the arity check in splitConTyArgs, -- so we can assume (isInvisibleForAllTyFlag vis) = do { massert (isInvisibleForAllTyFlag vis) - ; zip_pats_bndrs pats tvbs } -zip_pats_bndrs pats [] = return ([], pats) + ; zipPatsBndrs pats tvbs } +zipPatsBndrs pats [] = return ([], pats) + +{- Note [Zipping ConPat arguments with TyVarBinders] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The zipPatsBndrs function allows us to line up the arguments of a constructor +pattern `MkT p1 p2 ... pn` with the TyVarBinders of MkT's type. Consider + + MkT :: forall a b. forall c d -> a -> T a b c d + +Then, in a pattern match `MkT @s (type t) p q`, we have the following +correspondence: + + * pattern `@s` with the TyVarBinder `forall a.` + * no pattern with the TyVarBinder `forall b.` + * pattern `type t` with the TyVarBinder `forall c ->` + * pattern `p` with the TyVarBinder `forall d ->` + * pattern `q` is the one remaining value argument + +Note how `p` and `q` are exactly alike, and only the TyVarBinder can tell us +that `p` is a required type argument rather than a value argument. + +So the call (zipPatsBndrs pats tvbs) with the inputs + + pats = [@s, type t, p, q] + tvbs = [Bndr a Spec, Bndr b Spec, Bndr c Req, Bndr d Req] + +produces the following (ty_pats, val_pats) outputs: + + ty_pats = [(s, a), (t, c), (p, d)] + val_pats = [q] -- remaining value arguments + +Note that the ty_pats components are stripped: the type patterns have lost the +`@` or the `type` herald, and the binders have been reduced to their TyVars. + +This is currently used in two ways: + +1. In tcDataConPat/tcPatSynPat (via splitConTyArgs) to pass the type arguments + onto tcConTyArgs and the value arguments onto tcConValArgs. + See Note [Type applications in patterns] for more details. + +2. In tcPatToExpr, to discard the type arguments in the RHS of an implicitly + bidirectional pattern synonym, keeping only the value arguments. + See Note [Discarding types in the builder expression] in GHC.Tc.TyCl.PatSyn. +-} tcConTyArgs :: Subst -> PatEnv -> [(HsTyPat GhcRn, TyVar)] -> TcM a -> TcM a ===================================== compiler/GHC/Tc/TyCl/PatSyn.hs ===================================== @@ -940,11 +940,9 @@ tcPatSynBuilderBind prag_fn (PSB { psb_id = ps_lname@(L loc ps_name) | isUnidirectional dir = return [] - | Left why <- mb_match_group -- Can't invert the pattern - = setSrcSpan (getLocA lpat) $ failWithTc $ TcRnPatSynInvalidRhs ps_name lpat args why - - | Right match_group <- mb_match_group -- Bidirectional - = do { patsyn <- tcLookupPatSyn ps_name + | otherwise -- Bidirectional + = do { match_group <- get_match_group + ; patsyn <- tcLookupPatSyn ps_name ; case patSynBuilder patsyn of { Nothing -> return [] ; -- This case happens if we found a type error in the @@ -985,10 +983,10 @@ tcPatSynBuilderBind prag_fn (PSB { psb_id = ps_lname@(L loc ps_name) ; return builder_binds } } } where - mb_match_group + get_match_group = case dir of - ExplicitBidirectional explicit_mg -> Right explicit_mg - ImplicitBidirectional -> fmap mk_mg (tcPatToExpr args lpat) + ExplicitBidirectional explicit_mg -> return explicit_mg + ImplicitBidirectional -> mk_mg <$> tcPatToExpr ps_name args lpat Unidirectional -> panic "tcPatSynBuilderBind" mk_mg :: LHsExpr GhcRn -> MatchGroup GhcRn (LHsExpr GhcRn) @@ -1032,44 +1030,53 @@ add_void need_dummy_arg ty | need_dummy_arg = mkVisFunTyMany unboxedUnitTy ty | otherwise = ty -tcPatToExpr :: [LocatedN Name] -> LPat GhcRn - -> Either PatSynInvalidRhsReason (LHsExpr GhcRn) +tcPatToExpr :: Name -> [LocatedN Name] -> LPat GhcRn -> TcM (LHsExpr GhcRn) -- Given a /pattern/, return an /expression/ that builds a value -- that matches the pattern. E.g. if the pattern is (Just [x]), -- the expression is (Just [x]). They look the same, but the -- input uses constructors from HsPat and the output uses constructors -- from HsExpr. -- --- Returns (Left r) if the pattern is not invertible, for reason r. +-- Fails with TcRnPatSynInvalidRhs if the pattern is not invertible. -- See Note [Builder for a bidirectional pattern synonym] -tcPatToExpr args pat = go pat +tcPatToExpr ps_name args pat = go pat where lhsVars = mkNameSet (map unLoc args) + invalidRhs :: PatSynInvalidRhsReason -> TcM a + invalidRhs why = setSrcSpan (getLocA pat) $ + failWithTc $ TcRnPatSynInvalidRhs ps_name pat args why + -- Make a prefix con for prefix and infix patterns for simplicity mkPrefixConExpr :: LocatedN (WithUserRdr Name) -> [LPat GhcRn] - -> Either PatSynInvalidRhsReason (HsExpr GhcRn) - mkPrefixConExpr lcon@(L loc _) pats - = do { exprs <- mapM go pats + -> TcM (HsExpr GhcRn) + mkPrefixConExpr lcon@(L loc con_name) pats + = do { con_like <- tcLookupConLike con_name + ; let tvbs = conLikeUserTyVarBinders con_like + ; (_ty_pats, val_pats) <- zipPatsBndrs pats tvbs + -- Type arguments _ty_pats are discarded, just like the SigPat's type. + -- See Note [Discarding types in the builder expression] + ; let ty_exprs = [wildCardTyArg | tvb <- tvbs, isVisibleForAllTyBinder tvb] + -- Placeholders `_` for the discarded required type arguments. + ; val_exprs <- mapM go val_pats ; let con = L (l2l loc) (HsVar noExtField lcon) - ; return (unLoc $ mkHsApps con exprs) - } + ; return (unLoc $ mkHsApps con (ty_exprs ++ val_exprs)) } mkRecordConExpr :: LocatedN (WithUserRdr Name) -> HsRecFields GhcRn (LPat GhcRn) - -> Either PatSynInvalidRhsReason (HsExpr GhcRn) + -> TcM (HsExpr GhcRn) mkRecordConExpr con (HsRecFields x fields dd) = do { exprFields <- mapM go' fields ; return (RecordCon noExtField con (HsRecFields x exprFields dd)) } - go' :: LHsRecField GhcRn (LPat GhcRn) -> Either PatSynInvalidRhsReason (LHsRecField GhcRn (LHsExpr GhcRn)) + go' :: LHsRecField GhcRn (LPat GhcRn) -> TcM (LHsRecField GhcRn (LHsExpr GhcRn)) go' (L l rf) = L l <$> traverse go rf - go :: LPat GhcRn -> Either PatSynInvalidRhsReason (LHsExpr GhcRn) + go :: LPat GhcRn -> TcM (LHsExpr GhcRn) go (L loc p) = L loc <$> go1 p - go1 :: Pat GhcRn -> Either PatSynInvalidRhsReason (HsExpr GhcRn) + go1 :: Pat GhcRn -> TcM (HsExpr GhcRn) go1 (ConPat NoExtField con info) = case info of PrefixCon _ ps -> mkPrefixConExpr con ps @@ -1077,13 +1084,13 @@ tcPatToExpr args pat = go pat RecCon _ fields -> mkRecordConExpr con fields go1 (SigPat _ pat _) = go1 (unLoc pat) - -- See Note [Type signatures and the builder expression] + -- See Note [Discarding types in the builder expression] go1 (VarPat _ (L l var)) | var `elemNameSet` lhsVars = return $ mkHsVar (L l var) | otherwise - = Left (PatSynUnboundVar var) + = invalidRhs (PatSynUnboundVar var) go1 (ParPat _ pat) = fmap (HsPar noExtField) (go pat) go1 (ListPat _ pats) = do { exprs <- mapM go pats @@ -1104,10 +1111,7 @@ tcPatToExpr args pat = go pat | otherwise = return $ HsOverLit noExtField n go1 (SplicePat (HsUntypedSpliceTop _ pat) _) = go1 pat go1 (SplicePat (HsUntypedSpliceNested _) _) = panic "tcPatToExpr: invalid nested splice" - go1 (EmbTyPat _ tp) = return $ HsEmbTy noExtField (hstp_to_hswc tp) - where hstp_to_hswc :: HsTyPat GhcRn -> LHsWcType GhcRn - hstp_to_hswc (HsTP { hstp_ext = HsTPRn { hstp_nwcs = wcs }, hstp_body = hs_ty }) - = HsWC { hswc_ext = wcs, hswc_body = hs_ty } + go1 (EmbTyPat _ _tp) = panic "tcPatToExpr: invalid type pattern" go1 (InvisPat _ _tp) = panic "tcPatToExpr: invalid invisible pattern" go1 (XPat (HsPatExpanded _ pat))= go1 pat @@ -1131,7 +1135,11 @@ tcPatToExpr args pat = go pat go1 p@(NPlusKPat {}) = notInvertible p go1 p@(OrPat {}) = notInvertible p - notInvertible p = Left (PatSynNotInvertible p) + notInvertible p = invalidRhs (PatSynNotInvertible p) + +-- See Note [Discarding types in the builder expression] +wildCardTyArg :: LHsExpr GhcRn +wildCardTyArg = wrapGenSpan (HsHole (HoleVar (wrapGenSpan unnamedHoleRdrName))) {- Note [Builder for a bidirectional pattern synonym] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1203,9 +1211,17 @@ one could write a nonsensical function like or g (K (Just True) False) = ... -Note [Type signatures and the builder expression] +Note [Discarding types in the builder expression] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The RHS of an implicitly bidirectional pattern synonym may mention types in +three ways: a pattern signature (p :: ty), an invisible type argument (@ty), +and a required type argument (type ty). Required type arguments may be obscured +by the omission of the `type` keyword. + +A type may /bind/ variables when it occurs in a pattern, and those binders have +no counterpart in the builder's scope, so tcPatToExpr must not carry them over. Consider + pattern L x = Left x :: Either [a] [b] In tc{Infer/Check}PatSynDecl we will check that the pattern has the @@ -1223,6 +1239,71 @@ latter; #9867.) No, the job of the signature is done, so when converting the pattern to an expression (for the builder RHS) we simply discard the signature. +The same reasoning applies to the other two forms, but the way we discard +them differs. Which form an argument takes is not apparent from the pattern +alone: in + + pattern P x = MkT a x + +'a' looks like an ordinary variable pattern, and only the TyVarBinders in +MkT's type say that it stands in a required type argument position. We get +those binders from the typechecked ConLike, via conLikeUserTyVarBinders, so +mkPrefixConExpr must look the constructor up before it can walk the arguments. +It then lines them up against the binders with zipPatsBndrs, as described +in Note [Zipping ConPat arguments with TyVarBinders] in GHC.Tc.Gen.Pat. + +Each argument is then treated accordingly: + +* Invisible type arguments (@ty) are dropped from the argument list + altogether. Given + + pattern Q x = MkT @a x + + the builder is $bQ x = MkT x. Dropping is safe because the argument + instantiates either a universal, which the expected type of the builder + already pins down, or an existential, which cannot take a concrete type + in a pattern anyway. Improper handling of type arguments led to #27440. + +* Required type arguments cannot be dropped, as that would change the syntactic + arity of the application. Instead, we replace them with wildcards `_`, the + equivalent of @_ for invisible type arguments. Given + + pattern R x = MkT (type a) x + pattern P x = MkT a x + + the builders are $bR x = MkT _ x and $bP x = MkT _ x, and the wildcard is + solved from the expected type. Retaining the type would mention a binder that + is not in scope in the builder (#27583). + +This reasoning holds when the RHS is a data constructor. Two caveats: + +* With a helper pattern synonym we can construct an example where discarding + the type argument rejects an otherwise valid program: + + pattern Q :: forall a. Show a => Int -> S -- 'a' is ambiguous + pattern P n = Q @Bool n -- rejected: $bP n = Q n, ambiguous 'a' + + The example introduces an ambiguous type variable occurring in a class + constraint. Such a variable serves no purpose, so we do not expect to + encounter this problem in practice. The workaround is to declare P + explicitly bidirectional and write the builder by hand. + +* A required type argument that binds a variable yields a suboptimal error + message: we fail to solve the wildcard, where we would rather report that 'a' + is not bound on the LHS. + + data S where MkS :: forall a -> Show a => Int -> S + pattern P n = MkS a n -- $bP n = MkS _ n, ambiguous wildcard + + Mind you, the program is rejected either way: it is not possible to bind 'a' on + the LHS until pattern synonyms support RequiredTypeArguments (#23704) or + TypeAbstractions (#27642). + +We will have to revisit this design once we do add support for those extensions +in pattern synonym declarations (#23704, #27642). When type variables can be +bound on the LHS, the builder has a scope for them, and discarding every type in +the RHS is no longer the obvious thing to do. + Note [Record PatSyn Desugaring] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It is important that prov_theta comes before req_theta as this ordering is used ===================================== testsuite/tests/patsyn/should_compile/T27440a.hs ===================================== @@ -0,0 +1,12 @@ +{-# LANGUAGE DataKinds, PatternSynonyms, TypeAbstractions #-} +module T27440a where + +import Data.Kind (Type) + +newtype Lit = Lit { litName :: String } + +type LitOfValue :: Bool -> Type +newtype LitOfValue v = LitOfValue { underlyingLit :: Lit } + +pattern FalseLit :: Lit -> LitOfValue False +pattern FalseLit a = LitOfValue @False a ===================================== testsuite/tests/patsyn/should_compile/T27440b.hs ===================================== @@ -0,0 +1,7 @@ +{-# LANGUAGE PatternSynonyms, TypeAbstractions #-} +module T27440b where + +data T a = MkT a + +pattern P :: a -> T a +pattern P x = MkT @a x ===================================== testsuite/tests/patsyn/should_compile/T27440c.hs ===================================== @@ -0,0 +1,7 @@ +{-# LANGUAGE ExistentialQuantification, PatternSynonyms, TypeAbstractions #-} +module T27440c where + +data S = forall a. Show a => MkS a + +pattern P :: () => Show a => a -> S +pattern P x = MkS @a x ===================================== testsuite/tests/patsyn/should_compile/all.T ===================================== @@ -90,3 +90,7 @@ test('T23038', normal, compile_fail, ['']) test('T22328', normal, compile, ['']) test('T26331', normal, compile, ['']) test('T26331a', normal, compile, ['']) + +test('T27440a', normal, compile, ['']) +test('T27440b', normal, compile, ['']) +test('T27440c', normal, compile, ['']) ===================================== testsuite/tests/patsyn/should_fail/T27440d.hs ===================================== @@ -0,0 +1,7 @@ +{-# LANGUAGE ExistentialQuantification, PatternSynonyms, TypeAbstractions #-} +module T27440d where + +data S = forall a. Show a => MkS a + +pattern P :: Show a => a -> S +pattern P x = MkS @a x ===================================== testsuite/tests/patsyn/should_fail/T27440d.stderr ===================================== @@ -0,0 +1,12 @@ +T27440d.hs:7:22: error: [GHC-25897] + • Couldn't match expected type ‘a’ with actual type ‘a1’ + ‘a1’ is a rigid type variable bound by + a pattern with constructor: MkS :: forall a. Show a => a -> S, + in a pattern synonym declaration + at T27440d.hs:7:15-22 + ‘a’ is a rigid type variable bound by + the signature for pattern synonym ‘P’ + at T27440d.hs:6:14-29 + • In the declaration for pattern synonym ‘P’ + • Relevant bindings include x :: a1 (bound at T27440d.hs:7:22) + ===================================== testsuite/tests/patsyn/should_fail/all.T ===================================== @@ -55,3 +55,5 @@ test('patsyn_where_fail1', normal, compile_fail, ['']) test('patsyn_where_fail2', normal, compile_fail, ['']) test('patsyn_where_fail3', normal, compile_fail, ['']) test('patsyn_where_fail4', normal, compile_fail, ['']) + +test('T27440d', normal, compile_fail, ['']) ===================================== testsuite/tests/vdq-rta/should_compile/T27583a.hs ===================================== @@ -0,0 +1,8 @@ +{-# LANGUAGE GADTs, RequiredTypeArguments, PatternSynonyms #-} +module T27583a where + +data T a where + MkT :: forall a -> T a + +pattern P :: T a +pattern P = MkT (type a) ===================================== testsuite/tests/vdq-rta/should_compile/T27583b.hs ===================================== @@ -0,0 +1,8 @@ +{-# LANGUAGE GADTs, RequiredTypeArguments, PatternSynonyms #-} +module T27583b where + +data T a where + MkT :: forall a -> T a + +pattern P :: T a +pattern P = MkT a ===================================== testsuite/tests/vdq-rta/should_compile/T27583c.hs ===================================== @@ -0,0 +1,8 @@ +{-# LANGUAGE GADTs, RequiredTypeArguments, PatternSynonyms #-} +module T27583c where + +data T a where + MkT :: forall a -> T a + +pattern P :: T Int +pattern P = MkT (type Int) ===================================== testsuite/tests/vdq-rta/should_compile/T27583d.hs ===================================== @@ -0,0 +1,21 @@ +{-# LANGUAGE GADTs, RequiredTypeArguments, PatternSynonyms #-} +module T27583d where + +data T a where + MkT :: forall a -> a -> T a + +-- A required type argument is checked against the signature, with or without +-- the 'type' herald. The variable/wildcard patterns x, _, (type x), (type _) +-- can't mismatch the signature. Concrete types are in T27583e and T27583f. + +pattern P1 :: Int -> T Int +pattern P1 n = MkT x n + +pattern P2 :: Int -> T Int +pattern P2 n = MkT (type x) n + +pattern P3 :: Int -> T Int +pattern P3 n = MkT _ n + +pattern P4 :: Int -> T Int +pattern P4 n = MkT (type _) n ===================================== testsuite/tests/vdq-rta/should_compile/T27583e.hs ===================================== @@ -0,0 +1,21 @@ +{-# LANGUAGE GADTs, RequiredTypeArguments, PatternSynonyms #-} +module T27583e where + +data T a where + MkT :: forall a -> a -> T a + +-- A required type argument is checked against the signature, with or without +-- the 'type' herald. Here the type written in that position agrees with the +-- signature. T27583f is the same four patterns with a type that does not. + +pattern P1 :: Int -> T Int +pattern P1 n = MkT Int n + +pattern P2 :: Int -> T Int +pattern P2 n = MkT (type Int) n + +pattern P3 :: Maybe Int -> T (Maybe Int) +pattern P3 n = MkT (Maybe Int) n + +pattern P4 :: Maybe Int -> T (Maybe Int) +pattern P4 n = MkT (type (Maybe Int)) n ===================================== testsuite/tests/vdq-rta/should_compile/T27583g.hs ===================================== @@ -0,0 +1,14 @@ +{-# LANGUAGE GADTs, RequiredTypeArguments, PatternSynonyms, TypeAbstractions #-} +module T27583g where + +data T a b c where + MkT :: forall a. forall b c -> a -> T a b c + +-- Check all argument variants in a constructor pattern at once: the invisible +-- type argument `@a`, the required type argument `type b` with the herald, the +-- required type argument `c` without the herald, and the value argument `x`. +-- +-- The resulting builder is $bP x = MkT _ _ x. + +pattern P :: x -> T x y z +pattern P x = MkT @a (type b) c x ===================================== testsuite/tests/vdq-rta/should_compile/all.T ===================================== @@ -39,3 +39,10 @@ test('T23738_th', req_th, compile, ['']) test('T24159_viewpat', normal, compile, ['']) test('T24159_type_syntax', normal, compile, ['']) test('T24159_th_type_syntax', req_th, compile, ['']) + +test('T27583a', normal, compile, ['']) +test('T27583b', normal, compile, ['']) +test('T27583c', normal, compile, ['']) +test('T27583d', normal, compile, ['']) +test('T27583e', normal, compile, ['']) +test('T27583g', normal, compile, ['']) ===================================== testsuite/tests/vdq-rta/should_fail/T27440e.hs ===================================== @@ -0,0 +1,8 @@ +{-# LANGUAGE GADTs, RequiredTypeArguments, PatternSynonyms, TypeAbstractions #-} +module T27440e where + +data T a where + MkT :: forall a -> T a + +pattern P :: a -> T a +pattern P x = MkT @a x ===================================== testsuite/tests/vdq-rta/should_fail/T27440e.stderr ===================================== @@ -0,0 +1,5 @@ +T27440e.hs:8:19: error: [GHC-88754] + • Ill-formed type pattern: @a + • In the pattern: MkT @a x + In the declaration for pattern synonym ‘P’ + ===================================== testsuite/tests/vdq-rta/should_fail/T27583f.hs ===================================== @@ -0,0 +1,21 @@ +{-# LANGUAGE GADTs, RequiredTypeArguments, PatternSynonyms #-} +module T27583f where + +data T a where + MkT :: forall a -> a -> T a + +-- A required type argument is checked against the signature, with or without +-- the 'type' herald. Here the type written in that position does not agree +-- with the signature. T27583e is the same four patterns with a type that does. + +pattern P1 :: Int -> T Int +pattern P1 n = MkT Bool n + +pattern P2 :: Int -> T Int +pattern P2 n = MkT (type Bool) n + +pattern P3 :: Maybe Int -> T (Maybe Int) +pattern P3 n = MkT (Maybe Bool) n + +pattern P4 :: Maybe Int -> T (Maybe Int) +pattern P4 n = MkT (type (Maybe Bool)) n ===================================== testsuite/tests/vdq-rta/should_fail/T27583f.stderr ===================================== @@ -0,0 +1,24 @@ +T27583f.hs:12:16: error: [GHC-83865] + • Couldn't match expected type ‘Int’ with actual type ‘Bool’ + • In the pattern: MkT Bool n + In the declaration for pattern synonym ‘P1’ + +T27583f.hs:15:16: error: [GHC-83865] + • Couldn't match expected type ‘Int’ with actual type ‘Bool’ + • In the pattern: MkT (type Bool) n + In the declaration for pattern synonym ‘P2’ + +T27583f.hs:18:16: error: [GHC-83865] + • Couldn't match type ‘Bool’ with ‘Int’ + Expected: Maybe Int + Actual: Maybe Bool + • In the pattern: MkT (Maybe Bool) n + In the declaration for pattern synonym ‘P3’ + +T27583f.hs:21:16: error: [GHC-83865] + • Couldn't match type ‘Bool’ with ‘Int’ + Expected: Maybe Int + Actual: Maybe Bool + • In the pattern: MkT (type (Maybe Bool)) n + In the declaration for pattern synonym ‘P4’ + ===================================== testsuite/tests/vdq-rta/should_fail/all.T ===================================== @@ -32,3 +32,6 @@ test('T24159_type_syntax_tc_fail', normal, compile_fail, ['']) test('T24159_type_syntax_th_fail', normal, ghci_script, ['T24159_type_syntax_th_fail.script']) test('T25127_fail_th_quote', normal, compile_fail, ['']) test('T25127_fail_arity', normal, compile_fail, ['']) + +test('T27440e', normal, compile_fail, ['']) +test('T27583f', normal, compile_fail, ['']) View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/820632344faff832e67cfd162bf9422c... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/820632344faff832e67cfd162bf9422c... You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
participants (1)
-
Vladislav Zavialov (@int-index)