Andrei Borzenkov pushed to branch wip/sand-witch/27423-gadt-parens at Glasgow Haskell Compiler / GHC
Commits:
-
3a32ebde
by Andrei Borzenkov at 2026-07-10T11:45:31+04:00
13 changed files:
- + changelog.d/allow-gadt-prefx-con-parens
- compiler/GHC/Hs/Decls.hs
- compiler/GHC/Hs/Type.hs
- − testsuite/tests/gadt/T14320.stderr
- testsuite/tests/gadt/T18191.hs
- testsuite/tests/gadt/T18191.stderr
- + testsuite/tests/gadt/T27423a.hs
- + testsuite/tests/gadt/T27423b.hs
- + testsuite/tests/gadt/T27423b.stderr
- testsuite/tests/gadt/all.T
- testsuite/tests/printer/Makefile
- + testsuite/tests/printer/T27423c.hs
- testsuite/tests/printer/all.T
Changes:
| 1 | +section: language
|
|
| 2 | +synopsis: Allow parentheses in prefix GADT constructor declarations, as specified
|
|
| 3 | + by GHC Proposal #402 "Stable GADT constructor syntax".
|
|
| 4 | +issues: #27423
|
|
| 5 | +mrs: !16321
|
|
| 6 | + |
|
| 7 | +description: {
|
|
| 8 | + Parenthesized types are now accepted in prefix GADT constructor declarations,
|
|
| 9 | + even when they contain explicit ``forall`` quantifiers. For example:
|
|
| 10 | + |
|
| 11 | + data T where
|
|
| 12 | + MkT :: (forall a. a -> b -> T)
|
|
| 13 | + |
|
| 14 | + This is equivalent to ``MkT :: forall {b}. (forall a. a -> b -> T)``, so the
|
|
| 15 | + forall-or-nothing rule continues to be respected.
|
|
| 16 | +} |
| ... | ... | @@ -910,13 +910,28 @@ pprConDecl (ConDeclGADT { con_names = cons |
| 910 | 910 | , con_res_ty = res_ty, con_modifiers = mods, con_doc = doc })
|
| 911 | 911 | = pprMaybeWithDoc doc $ pprLHsModifiers mods <+> ppr_con_names (toList cons) <+> dcolon
|
| 912 | 912 | <+> (sep [pprHsOuterSigTyVarBndrs outer_bndrs
|
| 913 | + <+> inner_bndrs_lguard
|
|
| 913 | 914 | <+> hsep (map pprHsForAllTelescope inner_bndrs)
|
| 914 | 915 | <+> pprLHsContext mcxt,
|
| 915 | - sep (ppr_args args ++ [ppr res_ty]) ])
|
|
| 916 | + sep (ppr_args args ++ [ppr res_ty]),
|
|
| 917 | + inner_bndrs_rguard ])
|
|
| 916 | 918 | where
|
| 917 | 919 | ppr_args (PrefixConGADT _ args) = map (pprHsConDeclFieldWith (\arr tyDoc -> tyDoc <+> pprHsModifiedFunArr arr)) args
|
| 918 | 920 | ppr_args (RecConGADT _ fields) = [pprHsConDeclRecFields (unLoc fields) <+> arrow]
|
| 919 | 921 | |
| 922 | + -- We may have inner binders without outer ones, for example:
|
|
| 923 | + -- data D a where MkD :: forall. forall a. D a
|
|
| 924 | + -- and
|
|
| 925 | + -- data D a where MkD :: (forall a. D a)
|
|
| 926 | + -- These cases have different outer_bndrs: explicit or implicit.
|
|
| 927 | + -- We want to add an empty `forall.` or wrap type into parentheses
|
|
| 928 | + -- to highlight the fact that binds in the question are indeed inner.
|
|
| 929 | + (inner_bndrs_lguard, inner_bndrs_rguard)
|
|
| 930 | + | null inner_bndrs = (empty, empty)
|
|
| 931 | + | HsOuterImplicit{} <- outer_bndrs = (lparen, rparen)
|
|
| 932 | + | HsOuterExplicit{hso_bndrs=[]} <- outer_bndrs = (text "forall" <+> text ".", empty)
|
|
| 933 | + | otherwise = (empty, empty)
|
|
| 934 | + |
|
| 920 | 935 | ppr_con_names :: (OutputableBndr a) => [GenLocated l a] -> SDoc
|
| 921 | 936 | ppr_con_names = pprWithCommas (pprPrefixOcc . unLoc)
|
| 922 | 937 |
| ... | ... | @@ -898,12 +898,11 @@ splitLHsGadtTy (L _ sig_ty) |
| 898 | 898 | | (outer_bndrs, sigma_ty) <- split_outer_bndrs sig_ty
|
| 899 | 899 | , (inner_bndrs, phi_ty) <- split_inner_bndrs sigma_ty
|
| 900 | 900 | , (mb_ctxt, rho_ty) <- splitLHsQualTy_KP phi_ty
|
| 901 | - = case rho_ty of
|
|
| 902 | - L _ (HsFunTy _ _ (L _ (XHsType HsRecTy{})) _) | not (null inner_bndrs)
|
|
| 901 | + = if is_gadt_rec_ty rho_ty && not (null inner_bndrs)
|
|
| 903 | 902 | -- Bad! Record GADTs are not allowed to have inner_bndrs,
|
| 904 | 903 | -- undo the split to get a proper error message later
|
| 905 | - -> (outer_bndrs, [], Nothing, sigma_ty)
|
|
| 906 | - _ -> (outer_bndrs, inner_bndrs, mb_ctxt, rho_ty)
|
|
| 904 | + then (outer_bndrs, [], Nothing, sigma_ty)
|
|
| 905 | + else (outer_bndrs, inner_bndrs, mb_ctxt, rho_ty)
|
|
| 907 | 906 | where
|
| 908 | 907 | split_outer_bndrs :: HsSigType GhcPs -> (HsOuterSigTyVarBndrs GhcPs, LHsType GhcPs)
|
| 909 | 908 | split_outer_bndrs (HsSig{sig_bndrs = outer_bndrs, sig_body = body_ty}) =
|
| ... | ... | @@ -914,8 +913,17 @@ splitLHsGadtTy (L _ sig_ty) |
| 914 | 913 | , hst_body = body })
|
| 915 | 914 | = let ~(teles, t) = split_inner_bndrs body
|
| 916 | 915 | in (tele:teles, t)
|
| 916 | + split_inner_bndrs t@(L _ (HsParTy _ ty))
|
|
| 917 | + | not (is_gadt_rec_ty ty)
|
|
| 918 | + = split_inner_bndrs ty
|
|
| 919 | + | otherwise
|
|
| 920 | + = ([], t)
|
|
| 917 | 921 | split_inner_bndrs t = ([], t)
|
| 918 | 922 | |
| 923 | + -- type of form {fld :: ty, ...} -> ResTy
|
|
| 924 | + is_gadt_rec_ty (L _ (HsFunTy _ _ (L _ (XHsType HsRecTy{})) _)) = True
|
|
| 925 | + is_gadt_rec_ty _ = False
|
|
| 926 | + |
|
| 919 | 927 | -- | Decompose a type of the form @forall <tvs>. body@ into its constituent
|
| 920 | 928 | -- parts. Only splits type variable binders that
|
| 921 | 929 | -- were quantified invisibly (e.g., @forall a.@, with a dot).
|
| 1 | - |
|
| 2 | -T14320.hs:17:14: error: [GHC-71492]
|
|
| 3 | - GADT constructor type signature cannot contain nested ‘forall’s or contexts
|
|
| 4 | - In the definition of data constructor ‘TEBad’ |
| ... | ... | @@ -2,15 +2,6 @@ |
| 2 | 2 | {-# LANGUAGE RankNTypes #-}
|
| 3 | 3 | module T18191 where
|
| 4 | 4 | |
| 5 | -data T where
|
|
| 6 | - MkT :: (forall a. a -> b -> T)
|
|
| 7 | - |
|
| 8 | -data S a where
|
|
| 9 | - MkS :: (forall a. S a)
|
|
| 10 | - |
|
| 11 | -data U a where
|
|
| 12 | - MkU :: (Show a => U a)
|
|
| 13 | - |
|
| 14 | 5 | data Z a where
|
| 15 | 6 | MkZ1 :: forall a. forall b. { unZ1 :: (a, b) } -> Z (a, b)
|
| 16 | 7 | MkZ2 :: Eq a => Eq b => { unZ1 :: (a, b) } -> Z (a, b) |
| 1 | - |
|
| 2 | -T18191.hs:6:11: error: [GHC-71492]
|
|
| 3 | - • GADT constructor type signature cannot contain nested ‘forall’s or contexts
|
|
| 4 | - • In the definition of data constructor ‘MkT’
|
|
| 5 | - |
|
| 6 | -T18191.hs:9:11: error: [GHC-71492]
|
|
| 7 | - • GADT constructor type signature cannot contain nested ‘forall’s or contexts
|
|
| 8 | - • In the definition of data constructor ‘MkS’
|
|
| 9 | - |
|
| 10 | -T18191.hs:12:11: error: [GHC-71492]
|
|
| 11 | - • GADT constructor type signature cannot contain nested ‘forall’s or contexts
|
|
| 12 | - • In the definition of data constructor ‘MkU’
|
|
| 13 | - |
|
| 14 | -T18191.hs:15:21: error: [GHC-71492]
|
|
| 1 | +T18191.hs:6:21: error: [GHC-71492]
|
|
| 15 | 2 | • GADT constructor type signature cannot contain nested ‘forall’s or contexts
|
| 16 | 3 | • In the definition of data constructor ‘MkZ1’
|
| 17 | 4 | |
| 18 | -T18191.hs:15:31: error: [GHC-89246]
|
|
| 5 | +T18191.hs:6:31: error: [GHC-89246]
|
|
| 19 | 6 | • Record syntax is illegal here: {unZ1 :: (a, b)}
|
| 20 | 7 | • In the definition of data constructor ‘MkZ1’
|
| 21 | 8 | |
| 22 | -T18191.hs:16:19: error: [GHC-71492]
|
|
| 9 | +T18191.hs:7:19: error: [GHC-71492]
|
|
| 23 | 10 | • GADT constructor type signature cannot contain nested ‘forall’s or contexts
|
| 24 | 11 | • In the definition of data constructor ‘MkZ2’
|
| 25 | 12 | |
| 26 | -T18191.hs:16:27: error: [GHC-89246]
|
|
| 13 | +T18191.hs:7:27: error: [GHC-89246]
|
|
| 27 | 14 | • Record syntax is illegal here: {unZ1 :: (a, b)}
|
| 28 | 15 | • In the definition of data constructor ‘MkZ2’
|
| 16 | + |
| 1 | +{-# LANGUAGE GADTs #-}
|
|
| 2 | +module T27423a where
|
|
| 3 | + |
|
| 4 | +data G a where
|
|
| 5 | + MkG1 :: a -> G a
|
|
| 6 | + MkG2 :: (a -> G a)
|
|
| 7 | + MkG3 :: forall a. a -> G a
|
|
| 8 | + MkG4 :: forall a. (a -> G a)
|
|
| 9 | + |
|
| 10 | +-- this is equivalent to `forall {b}. (forall a. a -> b -> T)`.
|
|
| 11 | +data T where
|
|
| 12 | + MkT2 :: (forall a. a -> b -> T)
|
|
| 13 | + |
|
| 14 | +-- this is equivalent to `forall. (forall a. S a)`.
|
|
| 15 | +data S a where
|
|
| 16 | + MkS :: (forall a. S a)
|
|
| 17 | + |
|
| 18 | +-- A forall and a context combined inside the same parentheses, with no
|
|
| 19 | +-- outer forall at all.
|
|
| 20 | +data Y a where
|
|
| 21 | + MkY :: (forall a. Show a => a -> Y a)
|
|
| 22 | + |
|
| 23 | +-- Multiple, redundant nested parentheses around the whole type should
|
|
| 24 | +-- be accepted.
|
|
| 25 | +data H a where
|
|
| 26 | + MkH :: ((a -> H a))
|
|
| 27 | + |
|
| 28 | +-- An unparenthesised outer forall together with an independent,
|
|
| 29 | +-- parenthesised inner forall.
|
|
| 30 | +data I a where
|
|
| 31 | + MkI :: forall a. (forall b. I (b, a)) |
| 1 | +{-# LANGUAGE GADTs #-}
|
|
| 2 | +module T27423b where
|
|
| 3 | + |
|
| 4 | +-- Record-style GADT constructors must remain unparenthesisable, per
|
|
| 5 | +-- GHC Proposal #402: this is out of scope for #27423 and should
|
|
| 6 | +-- continue to be rejected.
|
|
| 7 | +data T1 a where
|
|
| 8 | + MkT1 :: ({ fld :: a } -> T1 a)
|
|
| 9 | + |
|
| 10 | +data T2 a where
|
|
| 11 | + MkT2 :: (forall a. { fld :: a } -> T2 a)
|
|
| 12 | + |
|
| 13 | +-- Without parentheses, forall-or-nothing applies to the whole type, so
|
|
| 14 | +-- `b` is not implicitly quantified and this must be rejected.
|
|
| 15 | +data T3 where
|
|
| 16 | + MkT3 :: forall a. a -> b -> T3 |
| 1 | +T27423b.hs:8:12: error: [GHC-89246]
|
|
| 2 | + • Record syntax is illegal here: {fld :: a}
|
|
| 3 | + • In the definition of data constructor ‘MkT1’
|
|
| 4 | + |
|
| 5 | +T27423b.hs:11:12: error: [GHC-71492]
|
|
| 6 | + • GADT constructor type signature cannot contain nested ‘forall’s or contexts
|
|
| 7 | + • In the definition of data constructor ‘MkT2’
|
|
| 8 | + |
|
| 9 | +T27423b.hs:11:22: error: [GHC-89246]
|
|
| 10 | + • Record syntax is illegal here: {fld :: a}
|
|
| 11 | + • In the definition of data constructor ‘MkT2’
|
|
| 12 | + |
|
| 13 | +T27423b.hs:16:26: error: [GHC-76037]
|
|
| 14 | + Not in scope: type variable ‘b’
|
|
| 15 | + |
| ... | ... | @@ -114,7 +114,7 @@ test('T7558', normal, compile, ['']) |
| 114 | 114 | test('T9380', normal, compile_and_run, [''])
|
| 115 | 115 | test('T12087', normal, compile_fail, [''])
|
| 116 | 116 | test('T12468', normal, compile_fail, [''])
|
| 117 | -test('T14320', normal, compile_fail, [''])
|
|
| 117 | +test('T14320', normal, compile, [''])
|
|
| 118 | 118 | test('T14719', normal, compile_fail, ['-fdiagnostics-show-caret'])
|
| 119 | 119 | test('T14808', normal, compile, [''])
|
| 120 | 120 | test('T15009', normal, compile, [''])
|
| ... | ... | @@ -132,3 +132,6 @@ test('T19847b', normal, compile, ['']) |
| 132 | 132 | test('T23022', normal, compile, ['-dcore-lint'])
|
| 133 | 133 | test('T23023', normal, compile_fail, ['-O -dcore-lint']) # todo: move this test?
|
| 134 | 134 | test('T23298', normal, compile_fail, [''])
|
| 135 | + |
|
| 136 | +test('T27423a', normal, compile, [''])
|
|
| 137 | +test('T27423b', normal, compile_fail, ['']) |
| ... | ... | @@ -932,3 +932,8 @@ PprModifiers: |
| 932 | 932 | PprQualifiedStrings:
|
| 933 | 933 | $(CHECK_PPR) $(LIBDIR) PprQualifiedStrings.hs
|
| 934 | 934 | $(CHECK_EXACT) $(LIBDIR) PprQualifiedStrings.hs
|
| 935 | + |
|
| 936 | +.PHONY: T27423c
|
|
| 937 | +T27423c:
|
|
| 938 | + $(CHECK_PPR) $(LIBDIR) T27423c.hs
|
|
| 939 | + $(CHECK_EXACT) $(LIBDIR) T27423c.hs |
| 1 | +{-# LANGUAGE GADTs #-}
|
|
| 2 | +module T27423c where
|
|
| 3 | + |
|
| 4 | +-- Exact-printing regression test
|
|
| 5 | +-- Not every declaration there would pass renamer without errors
|
|
| 6 | +data G a where
|
|
| 7 | + MkG1 :: a -> G a
|
|
| 8 | + MkG2 :: (a -> G a)
|
|
| 9 | + MkG3 :: forall a. a -> G a
|
|
| 10 | + MkG4 :: forall a. (a -> G a)
|
|
| 11 | + |
|
| 12 | +data T where
|
|
| 13 | + MkT1 :: forall a. a -> b -> T
|
|
| 14 | + MkT2 :: (forall a. a -> b -> T)
|
|
| 15 | + |
|
| 16 | +data S a where
|
|
| 17 | + MkS :: (forall a. S a)
|
|
| 18 | + |
|
| 19 | +data U a where
|
|
| 20 | + MkU :: (Show a => U a)
|
|
| 21 | + |
|
| 22 | +data V a where
|
|
| 23 | + MkV1 :: ((a -> V a))
|
|
| 24 | + MkV2 :: forall a. (forall b. V (b, a))
|
|
| 25 | + MkV3 :: (forall a. Show a => a -> V a)
|
|
| 26 | + MkV4 :: forall a. ((forall b. (Show a => a -> (b -> V a)))) |
| ... | ... | @@ -223,3 +223,5 @@ test('TestLevelImports', [ignore_stderr, req_ppr_deps], makefile_test, ['TestLev |
| 223 | 223 | test('TestNamedDefaults', [ignore_stderr, req_ppr_deps], makefile_test, ['TestNamedDefaults'])
|
| 224 | 224 | test('PprModifiers', [ignore_stderr,req_ppr_deps], makefile_test, ['PprModifiers'])
|
| 225 | 225 | test('PprQualifiedStrings', [ignore_stderr,req_ppr_deps], makefile_test, ['PprQualifiedStrings'])
|
| 226 | + |
|
| 227 | +test('T27423c', [ignore_stderr,req_ppr_deps], makefile_test, ['T27423c']) |