Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
-
4e9297ea
by Simon Jakobi at 2026-09-11T08:32:45-04:00
-
4f78dfdf
by Simon Jakobi at 2026-09-11T08:33:24-04:00
-
130286e3
by Alan Zimmerman at 2026-09-11T08:34:08-04:00
-
cc447dac
by Simon Jakobi at 2026-09-11T14:43:13-04:00
-
da7bb249
by Alan Zimmerman at 2026-09-11T14:43:14-04:00
29 changed files:
- .gitlab/ci.sh
- + changelog.d/27732
- compiler/GHC/Hs/Expr.hs
- compiler/GHC/Hs/Pat.hs
- compiler/GHC/Parser.y
- compiler/GHC/Parser/Annotation.hs
- compiler/GHC/Parser/PostProcess.hs
- compiler/GHC/Rename/Module.hs
- compiler/GHC/Tc/Errors/Types.hs
- docs/users_guide/exts/type_data.rst
- testsuite/tests/codeGen/should_run/all.T
- testsuite/tests/ghc-api/T25121_status.stdout
- + testsuite/tests/type-data/should_fail/T27732a.hs
- + testsuite/tests/type-data/should_fail/T27732a.stderr
- + testsuite/tests/type-data/should_fail/T27732b.hs
- + testsuite/tests/type-data/should_fail/T27732b.stderr
- + testsuite/tests/type-data/should_fail/T27732c.hs
- + testsuite/tests/type-data/should_fail/T27732c.stderr
- + testsuite/tests/type-data/should_fail/T27732d.hs
- + testsuite/tests/type-data/should_fail/T27732d.stderr
- + testsuite/tests/type-data/should_fail/T27732e.hs
- + testsuite/tests/type-data/should_fail/T27732e.stderr
- + testsuite/tests/type-data/should_fail/T27732f.hs
- + testsuite/tests/type-data/should_fail/T27732f.stderr
- testsuite/tests/type-data/should_fail/TDStrictnessGADT.stderr
- testsuite/tests/type-data/should_fail/TDStrictnessH98.stderr
- testsuite/tests/type-data/should_fail/all.T
- utils/check-exact/ExactPrint.hs
- utils/check-exact/Utils.hs
Changes:
| ... | ... | @@ -1106,7 +1106,7 @@ if [ "${CI_COMMIT_BRANCH:-}" == "master" ] && [ "${CI_PROJECT_PATH:-}" == "ghc/ |
| 1106 | 1106 | fi
|
| 1107 | 1107 | fi
|
| 1108 | 1108 | if [ -n "${IGNORE_PERF_FAILURES:-}" ]; then
|
| 1109 | - RUNTEST_ARGS=( "${RUNTEST_ARGS[@]:-}" "--ignore-perf-failures=$IGNORE_PERF_FAILURES" )
|
|
| 1109 | + RUNTEST_ARGS="${RUNTEST_ARGS:-} --ignore-perf-failures=$IGNORE_PERF_FAILURES"
|
|
| 1110 | 1110 | fi
|
| 1111 | 1111 | |
| 1112 | 1112 | if [[ -z ${BIGNUM_BACKEND:-} ]]; then BIGNUM_BACKEND=gmp; fi
|
| 1 | +section: language
|
|
| 2 | +synopsis: Reject ``~``, ``UNPACK`` and multiplicity annotations on ``type data`` fields
|
|
| 3 | +description:
|
|
| 4 | + ``type data`` declarations (:extension:`TypeData`) now reject any
|
|
| 5 | + strictness, unpackedness or multiplicity annotation on constructor
|
|
| 6 | + fields. Previously only ``!`` was rejected.
|
|
| 7 | +mrs: !16563
|
|
| 8 | +issues: #27732 |
| ... | ... | @@ -294,7 +294,7 @@ type instance XDo GhcPs = (AnnList, EpaLocation) |
| 294 | 294 | type instance XDo GhcRn = NoExtField
|
| 295 | 295 | type instance XDo GhcTc = Type
|
| 296 | 296 | |
| 297 | -type instance XExplicitList GhcPs = AnnList
|
|
| 297 | +type instance XExplicitList GhcPs = (EpToken "[", EpToken "]")
|
|
| 298 | 298 | type instance XExplicitList GhcRn = NoExtField
|
| 299 | 299 | type instance XExplicitList GhcTc = Type
|
| 300 | 300 | -- GhcPs: ExplicitList includes all source-level
|
| ... | ... | @@ -1440,7 +1440,7 @@ type instance XCmdArrApp GhcPs = (IsUnicodeSyntax, EpaLocation) |
| 1440 | 1440 | type instance XCmdArrApp GhcRn = NoExtField
|
| 1441 | 1441 | type instance XCmdArrApp GhcTc = Type
|
| 1442 | 1442 | |
| 1443 | -type instance XCmdArrForm GhcPs = AnnList
|
|
| 1443 | +type instance XCmdArrForm GhcPs = (EpUniToken "(|" "⦇", EpUniToken "|)" "⦈")
|
|
| 1444 | 1444 | -- | fixity (filled in by the renamer), for forms that were converted from
|
| 1445 | 1445 | -- OpApp's by the renamer
|
| 1446 | 1446 | type instance XCmdArrForm GhcRn = Maybe Fixity
|
| ... | ... | @@ -104,7 +104,7 @@ type instance XBangPat GhcPs = EpToken "!" |
| 104 | 104 | type instance XBangPat GhcRn = NoExtField
|
| 105 | 105 | type instance XBangPat GhcTc = NoExtField
|
| 106 | 106 | |
| 107 | -type instance XListPat GhcPs = AnnList
|
|
| 107 | +type instance XListPat GhcPs = (EpToken "[", EpToken "]")
|
|
| 108 | 108 | -- After parsing, ListPat can refer to a built-in Haskell list pattern
|
| 109 | 109 | -- or an overloaded list pattern.
|
| 110 | 110 | type instance XListPat GhcRn = NoExtField
|
| ... | ... | @@ -3282,7 +3282,7 @@ aexp2 :: { ECP } |
| 3282 | 3282 | -- arrow notation extension
|
| 3283 | 3283 | | '(|' aexp cmdargs '|)' {% runPV (unECP $2) >>= \ $2 ->
|
| 3284 | 3284 | fmap ecpFromCmd $
|
| 3285 | - amsA' (sLL $1 $> $ HsCmdArrForm (AnnList (glRM $1) (ListBanana (epUniTok $1) (epUniTok $4)) []) $2 Prefix
|
|
| 3285 | + amsA' (sLL $1 $> $ HsCmdArrForm (epUniTok $1, epUniTok $4) $2 Prefix
|
|
| 3286 | 3286 | (reverse $3)) }
|
| 3287 | 3287 | |
| 3288 | 3288 | projection :: { Located (NonEmpty (LocatedAn NoEpAnns (DotFieldOcc GhcPs))) }
|
| ... | ... | @@ -3414,9 +3414,9 @@ tup_tail :: { forall b. DisambECP b => PV [Either (EpAnn Bool) (LocatedA b)] } |
| 3414 | 3414 | -- Never empty.
|
| 3415 | 3415 | list :: { forall b. DisambECP b => SrcSpan -> (EpaLocation, EpaLocation) -> PV (LocatedA b) }
|
| 3416 | 3416 | : texp { \loc (ao,ac) -> unECP $1 >>= \ $1 ->
|
| 3417 | - mkHsExplicitListPV loc [$1] (AnnList Nothing (ListSquare (EpTok ao) (EpTok ac)) []) }
|
|
| 3417 | + mkHsExplicitListPV loc [$1] (EpTok ao, EpTok ac) }
|
|
| 3418 | 3418 | | lexps { \loc (ao,ac) -> $1 >>= \ $1 ->
|
| 3419 | - mkHsExplicitListPV loc (reverse $1) (AnnList Nothing (ListSquare (EpTok ao) (EpTok ac)) []) }
|
|
| 3419 | + mkHsExplicitListPV loc (reverse $1) (EpTok ao, EpTok ac) }
|
|
| 3420 | 3420 | | texp '..' { \loc (ao,ac) -> unECP $1 >>= \ $1 ->
|
| 3421 | 3421 | amsA' (L loc $ ArithSeq (AnnArithSeq (EpTok ao) Nothing (epTok $2) (EpTok ac)) Nothing (From $1))
|
| 3422 | 3422 | >>= ecpFromExp' }
|
| ... | ... | @@ -519,10 +519,8 @@ data AnnList |
| 519 | 519 | } deriving (Data,Eq)
|
| 520 | 520 | |
| 521 | 521 | data AnnListBrackets
|
| 522 | - = ListParens (EpToken "(") (EpToken ")")
|
|
| 523 | - | ListBraces (EpToken "{") (EpToken "}")
|
|
| 522 | + = ListBraces (EpToken "{") (EpToken "}")
|
|
| 524 | 523 | | ListSquare (EpToken "[") (EpToken "]")
|
| 525 | - | ListBanana (EpUniToken "(|" "⦇") (EpUniToken "|)" "⦈")
|
|
| 526 | 524 | | ListNone
|
| 527 | 525 | deriving (Data,Eq)
|
| 528 | 526 | |
| ... | ... | @@ -1094,10 +1092,8 @@ instance Outputable AnnList where |
| 1094 | 1092 | = text "AnnList" <+> ppr l <+> ppr p <+> ppr s
|
| 1095 | 1093 | |
| 1096 | 1094 | instance Outputable AnnListBrackets where
|
| 1097 | - ppr (ListParens o c) = text "ListParens" <+> ppr o <+> ppr c
|
|
| 1098 | 1095 | ppr (ListBraces o c) = text "ListBraces" <+> ppr o <+> ppr c
|
| 1099 | 1096 | ppr (ListSquare o c) = text "ListSquare" <+> ppr o <+> ppr c
|
| 1100 | - ppr (ListBanana o c) = text "ListBanana" <+> ppr o <+> ppr c
|
|
| 1101 | 1097 | ppr ListNone = text "ListNone"
|
| 1102 | 1098 | |
| 1103 | 1099 | instance Outputable AnnCType where
|
| ... | ... | @@ -1827,7 +1827,7 @@ class (b ~ (Body b) GhcPs, AnnoBody b) => DisambECP b where |
| 1827 | 1827 | mkHsTySigPV
|
| 1828 | 1828 | :: SrcSpanAnnA -> LocatedA b -> LHsType GhcPs -> TokDcolon -> PV (LocatedA b)
|
| 1829 | 1829 | -- | Disambiguate "[a,b,c]" (list syntax)
|
| 1830 | - mkHsExplicitListPV :: SrcSpan -> [LocatedA b] -> AnnList -> PV (LocatedA b)
|
|
| 1830 | + mkHsExplicitListPV :: SrcSpan -> [LocatedA b] -> (EpToken "[", EpToken "]") -> PV (LocatedA b)
|
|
| 1831 | 1831 | -- | Disambiguate "$(...)" and "[quasi|...|]" (TH splices)
|
| 1832 | 1832 | mkHsSplicePV :: Located (HsUntypedSplice GhcPs) -> PV (LocatedA b)
|
| 1833 | 1833 | -- | Disambiguate "f { a = b, ... }" syntax (record construction and record updates)
|
| ... | ... | @@ -71,7 +71,6 @@ import GHC.Data.Graph.Directed ( SCC, flattenSCC, Node(..) |
| 71 | 71 | , stronglyConnCompFromEdgedVerticesUniq )
|
| 72 | 72 | import GHC.Data.OrdList
|
| 73 | 73 | import qualified GHC.LanguageExtensions as LangExt
|
| 74 | -import GHC.Core.DataCon ( isSrcStrict )
|
|
| 75 | 74 | |
| 76 | 75 | import Control.Monad
|
| 77 | 76 | import Data.Bifunctor ( first )
|
| ... | ... | @@ -2116,8 +2115,8 @@ rnDataDefn doc (HsDataDefn { dd_cType = cType, dd_ctxt = context, dd_cons = cond |
| 2116 | 2115 | = do {
|
| 2117 | 2116 | ; when (has_labelled_fields condecl) $
|
| 2118 | 2117 | failWith $ TcRnTypeDataForbids TypeDataForbidsLabelledFields
|
| 2119 | - ; when (has_strictness_flags condecl) $
|
|
| 2120 | - failWith $ TcRnTypeDataForbids TypeDataForbidsStrictnessAnnotations
|
|
| 2118 | + ; when (has_field_annotations condecl) $
|
|
| 2119 | + failWith $ TcRnTypeDataForbids TypeDataForbidsFieldAnnotations
|
|
| 2121 | 2120 | }
|
| 2122 | 2121 | |
| 2123 | 2122 | has_labelled_fields (ConDeclGADT { con_g_args = RecConGADT _ _ }) = True
|
| ... | ... | @@ -2125,13 +2124,19 @@ rnDataDefn doc (HsDataDefn { dd_cType = cType, dd_ctxt = context, dd_cons = cond |
| 2125 | 2124 | = not (null (unLoc flds))
|
| 2126 | 2125 | has_labelled_fields _ = False
|
| 2127 | 2126 | |
| 2128 | - has_strictness_flags condecl
|
|
| 2129 | - = any isSrcStrict (con_arg_bangs condecl)
|
|
| 2127 | + has_field_annotations condecl
|
|
| 2128 | + = not (all unannotated (con_arg_fields condecl))
|
|
| 2129 | + where
|
|
| 2130 | + unannotated (CDF { cdf_bang = NoSrcStrict
|
|
| 2131 | + , cdf_unpack = NoSrcUnpack
|
|
| 2132 | + , cdf_multiplicity = HsModifiedFunArr _ [] (HsStandardArr _) })
|
|
| 2133 | + = True
|
|
| 2134 | + unannotated _ = False
|
|
| 2130 | 2135 | |
| 2131 | - con_arg_bangs (ConDeclGADT { con_g_args = PrefixConGADT _ args }) = map cdf_bang args
|
|
| 2132 | - con_arg_bangs (ConDeclH98 { con_args = PrefixCon _ args }) = map cdf_bang args
|
|
| 2133 | - con_arg_bangs (ConDeclH98 { con_args = InfixCon _ arg1 arg2 }) = [cdf_bang arg1, cdf_bang arg2]
|
|
| 2134 | - con_arg_bangs _ = []
|
|
| 2136 | + con_arg_fields (ConDeclGADT { con_g_args = PrefixConGADT _ args }) = args
|
|
| 2137 | + con_arg_fields (ConDeclH98 { con_args = PrefixCon _ args }) = args
|
|
| 2138 | + con_arg_fields (ConDeclH98 { con_args = InfixCon _ arg1 arg2 }) = [arg1, arg2]
|
|
| 2139 | + con_arg_fields _ = []
|
|
| 2135 | 2140 | |
| 2136 | 2141 | {-
|
| 2137 | 2142 | Note [Type data declarations]
|
| ... | ... | @@ -2166,8 +2171,9 @@ preceded by `type`, with the following restrictions: |
| 2166 | 2171 | (R2) There are no labelled fields. Perhaps these could be supported
|
| 2167 | 2172 | using type families, but they are omitted for now.
|
| 2168 | 2173 | |
| 2169 | -(R3) There are no strictness flags, because they don't make sense at
|
|
| 2170 | - the type level.
|
|
| 2174 | +(R3) There are no strictness, unpackedness or multiplicity annotations
|
|
| 2175 | + (!, ~, {-# UNPACK #-}, {-# NOUNPACK #-}, %m ->, ⊸), because they
|
|
| 2176 | + don't make sense at the type level.
|
|
| 2171 | 2177 | |
| 2172 | 2178 | (R4) The types of the constructors contain no constraints.
|
| 2173 | 2179 |
| ... | ... | @@ -2866,6 +2866,12 @@ data TcRnMessage where |
| 2866 | 2866 | type-data/should_fail/TDRecordsH98
|
| 2867 | 2867 | type-data/should_fail/TDStrictnessGADT
|
| 2868 | 2868 | type-data/should_fail/TDStrictnessH98
|
| 2869 | + type-data/should_fail/T27732a
|
|
| 2870 | + type-data/should_fail/T27732b
|
|
| 2871 | + type-data/should_fail/T27732c
|
|
| 2872 | + type-data/should_fail/T27732d
|
|
| 2873 | + type-data/should_fail/T27732e
|
|
| 2874 | + type-data/should_fail/T27732f
|
|
| 2869 | 2875 | -}
|
| 2870 | 2876 | TcRnTypeDataForbids :: !TypeDataForbids -> TcRnMessage
|
| 2871 | 2877 | |
| ... | ... | @@ -4541,15 +4547,15 @@ data ZonkerMessage where |
| 4541 | 4547 | data TypeDataForbids
|
| 4542 | 4548 | = TypeDataForbidsDatatypeContexts
|
| 4543 | 4549 | | TypeDataForbidsLabelledFields
|
| 4544 | - | TypeDataForbidsStrictnessAnnotations
|
|
| 4550 | + | TypeDataForbidsFieldAnnotations
|
|
| 4545 | 4551 | | TypeDataForbidsDerivingClauses
|
| 4546 | 4552 | deriving Generic
|
| 4547 | 4553 | |
| 4548 | 4554 | instance Outputable TypeDataForbids where
|
| 4549 | - ppr TypeDataForbidsDatatypeContexts = text "Data type contexts"
|
|
| 4550 | - ppr TypeDataForbidsLabelledFields = text "Labelled fields"
|
|
| 4551 | - ppr TypeDataForbidsStrictnessAnnotations = text "Strictness flags"
|
|
| 4552 | - ppr TypeDataForbidsDerivingClauses = text "Deriving clauses"
|
|
| 4555 | + ppr TypeDataForbidsDatatypeContexts = text "Data type contexts"
|
|
| 4556 | + ppr TypeDataForbidsLabelledFields = text "Labelled fields"
|
|
| 4557 | + ppr TypeDataForbidsFieldAnnotations = text "Strictness, unpackedness or multiplicity annotations"
|
|
| 4558 | + ppr TypeDataForbidsDerivingClauses = text "Deriving clauses"
|
|
| 4553 | 4559 | |
| 4554 | 4560 | -- | Specifies which back ends can handle a requested foreign import or export
|
| 4555 | 4561 | type ExpectedBackends = [Backend]
|
| ... | ... | @@ -33,7 +33,8 @@ either an ordinary algebraic data type or a GADT, prefixed with the keyword |
| 33 | 33 | ``type``, except that it may not contain
|
| 34 | 34 | a datatype context (even with :extension:`DatatypeContexts`),
|
| 35 | 35 | labelled fields,
|
| 36 | -strictness flags, or
|
|
| 36 | +:ref:`strictness <strict-haskell>`, :ref:`unpackedness <unpack-pragma>` or
|
|
| 37 | +:ref:`multiplicity <linear-types>` annotations, or
|
|
| 37 | 38 | a ``deriving`` clause.
|
| 38 | 39 | |
| 39 | 40 | The only constraints permitted in the types of constructors are
|
| ... | ... | @@ -258,7 +258,7 @@ test('T24893', normal, compile_and_run, ['-O']) |
| 258 | 258 | test('CCallConv', [req_c], compile_and_run, ['CCallConv_c.c'])
|
| 259 | 259 | test('T25364', normal, compile_and_run, [''])
|
| 260 | 260 | test('T26061', normal, compile_and_run, [''])
|
| 261 | -test('T26537', normal, compile_and_run, ['-O2 -fregs-graph'])
|
|
| 261 | +test('T26537', compile_timeout_multiplier(1.5), compile_and_run, ['-O2 -fregs-graph'])
|
|
| 262 | 262 | test('T24016', normal, compile_and_run, ['-O1 -fPIC'])
|
| 263 | 263 | test('T27046',
|
| 264 | 264 | [ req_cmm
|
| ... | ... | @@ -15,7 +15,7 @@ X(FunArr) match = NoExtField |
| 15 | 15 | X(ExprWithTySig) match = EpUniToken "::" "\8759"
|
| 16 | 16 | X(UntypedSplice) match = NoExtField
|
| 17 | 17 | X(ExplicitList) mismatch
|
| 18 | - >>> AnnList
|
|
| 18 | + >>> ((EpToken "["),(EpToken "]"))
|
|
| 19 | 19 | <<< ((EpToken "'"),(EpToken "["),(EpToken "]"))
|
| 20 | 20 | X(ExplicitTuple) mismatch
|
| 21 | 21 | >>> AnnParen
|
| 1 | +{-# LANGUAGE TypeData, LazyFieldAnnotations #-}
|
|
| 2 | +module T27732a where
|
|
| 3 | + |
|
| 4 | +type data T a = Cons ~a |
| 1 | +T27732a.hs:4:17: error: [GHC-67297]
|
|
| 2 | + Strictness, unpackedness or multiplicity annotations are not allowed in type data declarations.
|
|
| 3 | + |
| 1 | +{-# LANGUAGE TypeData, LazyFieldAnnotations #-}
|
|
| 2 | +module T27732b where
|
|
| 3 | + |
|
| 4 | +type data T a where
|
|
| 5 | + Cons :: ~a -> T a |
| 1 | +T27732b.hs:5:6: error: [GHC-67297]
|
|
| 2 | + Strictness, unpackedness or multiplicity annotations are not allowed in type data declarations.
|
|
| 3 | + |
| 1 | +{-# LANGUAGE TypeData #-}
|
|
| 2 | +module T27732c where
|
|
| 3 | + |
|
| 4 | +type data T a = Cons {-# UNPACK #-} a |
| 1 | +T27732c.hs:4:17: error: [GHC-67297]
|
|
| 2 | + Strictness, unpackedness or multiplicity annotations are not allowed in type data declarations.
|
|
| 3 | + |
| 1 | +{-# LANGUAGE TypeData #-}
|
|
| 2 | +module T27732d where
|
|
| 3 | + |
|
| 4 | +type data T a = Cons {-# NOUNPACK #-} a |
| 1 | +T27732d.hs:4:17: error: [GHC-67297]
|
|
| 2 | + Strictness, unpackedness or multiplicity annotations are not allowed in type data declarations.
|
|
| 3 | + |
| 1 | +{-# LANGUAGE TypeData, LinearTypes #-}
|
|
| 2 | +module T27732e where
|
|
| 3 | + |
|
| 4 | +type data T where
|
|
| 5 | + MkT :: Int %1 -> T |
| 1 | +T27732e.hs:5:3: error: [GHC-67297]
|
|
| 2 | + Strictness, unpackedness or multiplicity annotations are not allowed in type data declarations.
|
|
| 3 | + |
| 1 | +{-# LANGUAGE TypeData, LinearTypes, UnicodeSyntax #-}
|
|
| 2 | +module T27732f where
|
|
| 3 | + |
|
| 4 | +type data T where
|
|
| 5 | + MkT :: Int ⊸ T |
| 1 | +T27732f.hs:5:3: error: [GHC-67297]
|
|
| 2 | + Strictness, unpackedness or multiplicity annotations are not allowed in type data declarations.
|
|
| 3 | + |
| 1 | +TDStrictnessGADT.hs:5:6: error: [GHC-67297]
|
|
| 2 | + Strictness, unpackedness or multiplicity annotations are not allowed in type data declarations.
|
|
| 1 | 3 | |
| 2 | -TDStrictnessGADT.hs:5:6: [GHC-67297]
|
|
| 3 | - Strictness flags are not allowed in type data declarations. |
| 1 | +TDStrictnessH98.hs:4:17: error: [GHC-67297]
|
|
| 2 | + Strictness, unpackedness or multiplicity annotations are not allowed in type data declarations.
|
|
| 1 | 3 | |
| 2 | -TDStrictnessH98.hs:4:17: [GHC-67297]
|
|
| 3 | - Strictness flags are not allowed in type data declarations. |
| ... | ... | @@ -13,3 +13,9 @@ test('TDStrictnessGADT', normal, compile_fail, ['']) |
| 13 | 13 | test('TDStrictnessH98', normal, compile_fail, [''])
|
| 14 | 14 | test('TDTagToEnum', normal, compile_fail, [''])
|
| 15 | 15 | test('T22332b', normal, compile_fail, [''])
|
| 16 | +test('T27732a', normal, compile_fail, [''])
|
|
| 17 | +test('T27732b', normal, compile_fail, [''])
|
|
| 18 | +test('T27732c', normal, compile_fail, [''])
|
|
| 19 | +test('T27732d', normal, compile_fail, [''])
|
|
| 20 | +test('T27732e', normal, compile_fail, [''])
|
|
| 21 | +test('T27732f', normal, compile_fail, ['']) |
| ... | ... | @@ -140,9 +140,9 @@ defaultEPState = EPState |
| 140 | 140 | |
| 141 | 141 | -- | The R part of RWS. The environment. Updated via 'local' as we
|
| 142 | 142 | -- enter a new AST element, having a different anchor point.
|
| 143 | -data EPOptions m a = EPOptions
|
|
| 144 | - { epTokenPrint :: String -> m a
|
|
| 145 | - , epWhitespacePrint :: String -> m a
|
|
| 143 | +data EPOptions m w = EPOptions
|
|
| 144 | + { epTokenPrint :: String -> m w
|
|
| 145 | + , epWhitespacePrint :: String -> m w
|
|
| 146 | 146 | }
|
| 147 | 147 | |
| 148 | 148 | -- | Helper to create a 'EPOptions'
|
| ... | ... | @@ -163,8 +163,7 @@ stringOptions = epOptions return return |
| 163 | 163 | deltaOptions :: EPOptions Identity ()
|
| 164 | 164 | deltaOptions = epOptions (\_ -> return ()) (\_ -> return ())
|
| 165 | 165 | |
| 166 | -data EPWriter a = EPWriter
|
|
| 167 | - { output :: !a }
|
|
| 166 | +data EPWriter w = EPWriter { output :: !w }
|
|
| 168 | 167 | |
| 169 | 168 | instance Monoid w => Semigroup (EPWriter w) where
|
| 170 | 169 | (EPWriter a) <> (EPWriter b) = EPWriter (a <> b)
|
| ... | ... | @@ -239,7 +238,220 @@ setAnchorEpaL (EpAnn _ an _) anc ts cs = EpAnn anc (setTrailing (an {al_anchor = |
| 239 | 238 | -- | Key entry point. Switches to an independent AST element with its
|
| 240 | 239 | -- own annotation, calculating new offsets, etc
|
| 241 | 240 | markAnnotated :: (Monad m, Monoid w, ExactPrint a) => a -> EP w m a
|
| 242 | -markAnnotated a = enterAnn (getAnnotationEntry a) a
|
|
| 241 | +markAnnotated a = enterAnn (getAnnotationEntry a) a -- See Note [Exact print main loop]
|
|
| 242 | + |
|
| 243 | +{-
|
|
| 244 | +Note [Exact print main loop]
|
|
| 245 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 246 | + |
|
| 247 | +Exact printing is the process of taking the ParsedSource, or some
|
|
| 248 | +subtree from it, and rendering it to a string, which accurately
|
|
| 249 | +reflects the original source that was parsed, except detail of
|
|
| 250 | +whitespace (such as spaces vs tabs) is discarded.
|
|
| 251 | + |
|
| 252 | +The ParsedSource or fragment from it must implement the ExactPrint
|
|
| 253 | +class, and this file does that, as well as supporting machinery to
|
|
| 254 | +drive the process. The ExactPrint class is described later in this
|
|
| 255 | +note.
|
|
| 256 | + |
|
| 257 | +The entry point for exact printing is the exactPrint function, defined
|
|
| 258 | +as
|
|
| 259 | + |
|
| 260 | + exactPrint :: ExactPrint ast => ast -> String
|
|
| 261 | + exactPrint ast = snd $ runIdentity (runEP stringOptions (markAnnotated ast))
|
|
| 262 | + |
|
| 263 | + type EP w m a = RWST (EPOptions m w) (EPWriter w) EPState m a
|
|
| 264 | + |
|
| 265 | + runEP :: (Monad m) => EPOptions m w -> EP w m a -> m (a, w)
|
|
| 266 | + runEP epReader action = do
|
|
| 267 | + (ast, w) <- evalRWST action epReader defaultEPState
|
|
| 268 | + return (ast, output w)
|
|
| 269 | + |
|
| 270 | + data EPWriter w = EPWriter { output :: !w }
|
|
| 271 | + |
|
| 272 | + data EPOptions m w = EPOptions
|
|
| 273 | + { epTokenPrint :: String -> m w
|
|
| 274 | + , epWhitespacePrint :: String -> m w
|
|
| 275 | + }
|
|
| 276 | + |
|
| 277 | +This offers some flexibility in how the output is produced, in that
|
|
| 278 | +the EpWriter and EPOptions work together, defining an output type and
|
|
| 279 | +a function to render whitespace and non-whitepace.
|
|
| 280 | + |
|
| 281 | +In normal operation (via exactPrint) these are simply returning the
|
|
| 282 | +string unchanged and accumulating a larger string. But it has also been
|
|
| 283 | +used to render an HTML version of the source as it prints.
|
|
| 284 | + |
|
| 285 | +The main reason exact print exists is to make it easier for tool
|
|
| 286 | +writers to manipulate the ParsedSource, and render this back to the
|
|
| 287 | +original source, except for the changed parts. One manipulation is to
|
|
| 288 | +simply take say a FunBind with its signature from one place in the
|
|
| 289 | +code to another. When doing this, the original parsed locations are no
|
|
| 290 | +longer useful when rendering the source back to a string. To enable
|
|
| 291 | +this, we have another entry point, for converting all absolute
|
|
| 292 | +locations to relative ones, using DeltaPos, which captures the line
|
|
| 293 | +and col offset relative to the prior output.
|
|
| 294 | + |
|
| 295 | +The function to do this is
|
|
| 296 | + |
|
| 297 | + makeDeltaAst :: ExactPrint ast => ast -> ast
|
|
| 298 | + makeDeltaAst ast = fst $ runIdentity (runEP deltaOptions (markAnnotated ast))
|
|
| 299 | + |
|
| 300 | +The implementation is practically identical for exactPrint and
|
|
| 301 | +makeDeltaAst, they simply return the second or first part of the same
|
|
| 302 | +calculation.
|
|
| 303 | + |
|
| 304 | +This simplifies the implementation of the required ExactPrint
|
|
| 305 | +implmentations, in that we only need one per ast item, which encodes
|
|
| 306 | +how to print it, and this print process does bookkeeping to keep track
|
|
| 307 | +of what spacing it used when doing the print, so it can return the
|
|
| 308 | +updated item, with the original absolute SrcSpan's converted to
|
|
| 309 | +DeltaPos values instead.
|
|
| 310 | + |
|
| 311 | +This information is captured in the XRec/Anno instances used in GHC
|
|
| 312 | +Hs, which are mostly LocatedA a, defined as
|
|
| 313 | + |
|
| 314 | + GenLocated (EpAnn [TrailingAnn]) a
|
|
| 315 | + |
|
| 316 | + data EpAnn ann
|
|
| 317 | + = EpAnn { entry :: !EpaLocation
|
|
| 318 | + , anns :: !ann
|
|
| 319 | + , comments :: !EpAnnComments
|
|
| 320 | + }
|
|
| 321 | + |
|
| 322 | + data EpaLocation = EpaSpan !SrcSpan
|
|
| 323 | + | EpaDelta !SrcSpan !DeltaPos [LEpaComment]
|
|
| 324 | + |
|
| 325 | +When parsed, the entry EpaLocation captures an EpaSpan with the parsed
|
|
| 326 | +absolute location. After makeDeltaAst, this instead uses EpaDelta,
|
|
| 327 | +including the original SrcSpan, the relative spaceing as a DeltaPos,
|
|
| 328 | +and any comments that may come before the item, e.g. comments before a
|
|
| 329 | +semicolon.
|
|
| 330 | + |
|
| 331 | +Both exactPrint and makeDeltaAst call markAnnotated on the item to be
|
|
| 332 | +printed, inside the monad machinery.
|
|
| 333 | + |
|
| 334 | + markAnnotated :: (Monad m, Monoid w, ExactPrint a) => a -> EP w m a
|
|
| 335 | + markAnnotated a = enterAnn (getAnnotationEntry a) a
|
|
| 336 | + |
|
| 337 | +This makes use of the ExactPrint instance for the ParsedSource and
|
|
| 338 | +for every other part of the ParsedSource as a tree.
|
|
| 339 | + |
|
| 340 | + class (Typeable a) => ExactPrint a where
|
|
| 341 | + getAnnotationEntry :: a -> Entry
|
|
| 342 | + exact :: (Monad m, Monoid w) => a -> EP w m a
|
|
| 343 | + setAnnotationAnchor :: a -> EpaLocation -> [TrailingAnn] -> EpAnnComments -> a
|
|
| 344 | + |
|
| 345 | +- getAnnotationEntry : returns the Entry information, normally derived
|
|
| 346 | + directly from the EpAnn in the LocatedA enclosing the item.
|
|
| 347 | + Entry contains
|
|
| 348 | + - The location of the first non-comment part of the item to be printed.
|
|
| 349 | + - Any [TrailingAnn] (semis, commas, etc) to follow the item.
|
|
| 350 | + - Any comments associated with the item, but not with enclosed items.
|
|
| 351 | + These comments may also precede or follow the entry location
|
|
| 352 | + - Some technical flags, relating to flushing remaining comments at the
|
|
| 353 | + last (topmost) item, and if the anchor can be updated (see below).
|
|
| 354 | + |
|
| 355 | +- exact : Do the actual printing of the item, having been put in the right
|
|
| 356 | + place in terms of print location by the main loop, based on a call to
|
|
| 357 | + getAnnotationEntry for it. This printing normally comprises making nested
|
|
| 358 | + markAnnotated calls on the nested items in the current one, e.g.
|
|
| 359 | + |
|
| 360 | + exact (HsApp an e1 e2) = do
|
|
| 361 | + e1' <- markAnnotated e1
|
|
| 362 | + e2' <- markAnnotated e2
|
|
| 363 | + return (HsApp an e1' e2')
|
|
| 364 | + |
|
| 365 | +- setAnnotationAnchor : the main loop printing does two things:
|
|
| 366 | + - produce output, reflecting the items being printed
|
|
| 367 | + - convert all the locations in the item (each an EpaLocation) from its
|
|
| 368 | + EpaSpan version to an EpaDelta one, which is independent of absolute
|
|
| 369 | + location, being the spacing from the previous print output to this
|
|
| 370 | + entry point
|
|
| 371 | + To allow these updated locations to be captured, the item implements
|
|
| 372 | + the setAnnotationAnchor method, which updates the fields of the Entry
|
|
| 373 | + returned by getAnnotationEntry
|
|
| 374 | + |
|
| 375 | +You will recall
|
|
| 376 | + |
|
| 377 | + markAnnotated a = enterAnn (getAnnotationEntry a) a
|
|
| 378 | + enterAnn :: (Monad m, Monoid w, ExactPrint a) => Entry -> a -> EP w m a
|
|
| 379 | + |
|
| 380 | +enterAnn is the part that is repeatedly called via markAnnotated, to
|
|
| 381 | +manage the bookkeeping around printing and calculating the updated
|
|
| 382 | +delta positions.
|
|
| 383 | + |
|
| 384 | +It manages the printing state, adding the new comments from the Entry,
|
|
| 385 | +positioning the print head to the entry point, takes account of whether
|
|
| 386 | +it is an absolute span or a delta, and prints any comments that must come
|
|
| 387 | +before this location.
|
|
| 388 | + |
|
| 389 | +At this print location, it calls the `exact` method on the item. This
|
|
| 390 | +is the only place `exact` can be called. Within `exact` implementations
|
|
| 391 | +the `markAnnotated` function should be used instead, to ensure the state
|
|
| 392 | +is managed properly for printing.
|
|
| 393 | + |
|
| 394 | +Once the item is printed via its `exact` method, which normally
|
|
| 395 | +recurses via `markAnnotated` into any nested items inside it, the
|
|
| 396 | +`enterAnn` function prints any [TrailingAnn] from the entry and any
|
|
| 397 | +trailing comments. It then wraps up by calling
|
|
| 398 | +`setAnnotationAnchor`with the updated (now delta-based) values for the
|
|
| 399 | +Entry
|
|
| 400 | + |
|
| 401 | +Printing Complicated Items
|
|
| 402 | +~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 403 | +Sometimes we need to print a sub-item which does not map cleanly onto the
|
|
| 404 | +ExactPrint class, usually because there are parts spread through the item
|
|
| 405 | +that need to be managed together while printing.
|
|
| 406 | + |
|
| 407 | +An example is in
|
|
| 408 | +https://gitlab.haskell.org/ghc/ghc/-/merge_requests/16321, where
|
|
| 409 | +ConDeclGADT needs to print its inner_bindings, but the these in turn
|
|
| 410 | +may have parens, e.g.
|
|
| 411 | + |
|
| 412 | + data V a where
|
|
| 413 | + MkV4 :: forall a. ((forall b. (Show a => a -> (b -> V a))))
|
|
| 414 | + |
|
| 415 | +Here there are inner bindings for the first forall, the multiple
|
|
| 416 | +parens around the second forall, and the second forall, wrapping the
|
|
| 417 | +inner content within this.
|
|
| 418 | + |
|
| 419 | +But the inner content `Show a => a -> (b -> V a)` had to be printed "inside"
|
|
| 420 | +the inner_bindings, to correctly close the nested parens.
|
|
| 421 | + |
|
| 422 | +The approach in !16321 modified `enterAnn`, to pass in alternate versions
|
|
| 423 | +of the `exact` implementation. This works, but it makes an already
|
|
| 424 | +complicated function even more complicated.
|
|
| 425 | + |
|
| 426 | +An ExactPrint-idiomatic approach is to create a helper data structure
|
|
| 427 | +to represent this nested organisation, and provide ExactPrint
|
|
| 428 | +instances for that.
|
|
| 429 | + |
|
| 430 | +This is done in
|
|
| 431 | +https://gitlab.haskell.org/ghc/ghc/-/merge_requests/16644, using
|
|
| 432 | + |
|
| 433 | + data InnerBindings
|
|
| 434 | + = InnerMore (LHsGadtTelescope GhcPs) InnerBindings
|
|
| 435 | + | InnerDone (Maybe (LHsContext GhcPs), HsConDeclGADTDetails GhcPs, LHsType GhcPs)
|
|
| 436 | + |
|
| 437 | +The key part of the ExactPrint instance for this is
|
|
| 438 | + |
|
| 439 | + exact (InnerMore (L l (HsGadtPar (lp, rp))) xs) = do
|
|
| 440 | + lp' <- markEpToken lp
|
|
| 441 | + xs' <- markAnnotated xs
|
|
| 442 | + rp' <- markEpToken rp
|
|
| 443 | + return (InnerMore (L l (HsGadtPar (lp',rp'))) xs')
|
|
| 444 | + |
|
| 445 | +This first prints the opening paren, prints the balance of the cons list, then
|
|
| 446 | +prints the closing paren.
|
|
| 447 | + |
|
| 448 | +Conversions to and from this structure populate the initial values from
|
|
| 449 | +the ConDeclGADT, and retrieve the updated delta-based values after
|
|
| 450 | +printing.
|
|
| 451 | + |
|
| 452 | +Another use of this technique involves HsModuleImpDecls.
|
|
| 453 | + |
|
| 454 | +-}
|
|
| 243 | 455 | |
| 244 | 456 | -- | For HsModule, because we do not have a proper SrcSpan, we must
|
| 245 | 457 | -- indicate to flush trailing comments when done.
|
| ... | ... | @@ -377,6 +589,7 @@ cua NoCanUpdateAnchor _ = return [] |
| 377 | 589 | -- This is combination of the ghc=exactprint Delta.withAST and
|
| 378 | 590 | -- Print.exactPC functions and effectively does the delta processing
|
| 379 | 591 | -- immediately followed by the print processing. JIT ghc-exactprint.
|
| 592 | +-- See Note [Exact print main loop]
|
|
| 380 | 593 | enterAnn :: (Monad m, Monoid w, ExactPrint a) => Entry -> a -> EP w m a
|
| 381 | 594 | enterAnn NoEntryVal a = do
|
| 382 | 595 | p <- getPosP
|
| ... | ... | @@ -764,18 +977,12 @@ markLensBracketsO' :: (Monad m, Monoid w) |
| 764 | 977 | => a -> Lens a AnnListBrackets -> EP w m a
|
| 765 | 978 | markLensBracketsO' a l =
|
| 766 | 979 | case view l a of
|
| 767 | - ListParens o c -> do
|
|
| 768 | - o' <- markEpToken o
|
|
| 769 | - return (set l (ListParens o' c) a)
|
|
| 770 | 980 | ListBraces o c -> do
|
| 771 | 981 | o' <- markEpToken o
|
| 772 | 982 | return (set l (ListBraces o' c) a)
|
| 773 | 983 | ListSquare o c -> do
|
| 774 | 984 | o' <- markEpToken o
|
| 775 | 985 | return (set l (ListSquare o' c) a)
|
| 776 | - ListBanana o c -> do
|
|
| 777 | - o' <- markEpUniToken o
|
|
| 778 | - return (set l (ListBanana o' c) a)
|
|
| 779 | 986 | ListNone -> return (set l ListNone a)
|
| 780 | 987 | |
| 781 | 988 | markLensBracketsC :: (Monad m, Monoid w)
|
| ... | ... | @@ -786,18 +993,12 @@ markLensBracketsC' :: (Monad m, Monoid w) |
| 786 | 993 | => a -> Lens a AnnListBrackets -> EP w m a
|
| 787 | 994 | markLensBracketsC' a l =
|
| 788 | 995 | case view l a of
|
| 789 | - ListParens o c -> do
|
|
| 790 | - c' <- markEpToken c
|
|
| 791 | - return (set l (ListParens o c') a)
|
|
| 792 | 996 | ListBraces o c -> do
|
| 793 | 997 | c' <- markEpToken c
|
| 794 | 998 | return (set l (ListBraces o c') a)
|
| 795 | 999 | ListSquare o c -> do
|
| 796 | 1000 | c' <- markEpToken c
|
| 797 | 1001 | return (set l (ListSquare o c') a)
|
| 798 | - ListBanana o c -> do
|
|
| 799 | - c' <- markEpUniToken c
|
|
| 800 | - return (set l (ListBanana o c') a)
|
|
| 801 | 1002 | ListNone -> return (set l ListNone a)
|
| 802 | 1003 | |
| 803 | 1004 | -- -------------------------------------
|
| ... | ... | @@ -2919,13 +3120,13 @@ instance ExactPrint (HsExpr GhcPs) where |
| 2919 | 3120 | (an',l',stmts') <- exactDo (an,l) do_or_list_comp stmts
|
| 2920 | 3121 | return (HsDo (an',l') do_or_list_comp stmts')
|
| 2921 | 3122 | |
| 2922 | - exact (ExplicitList an es) = do
|
|
| 3123 | + exact (ExplicitList (o,c) es) = do
|
|
| 2923 | 3124 | debugM $ "ExplicitList start"
|
| 2924 | - an0 <- markLensBracketsO' an lal_brackets
|
|
| 3125 | + o' <- markEpToken o
|
|
| 2925 | 3126 | es' <- mapM markAnnotated es
|
| 2926 | - an1 <- markLensBracketsC' an0 lal_brackets
|
|
| 3127 | + c' <- markEpToken c
|
|
| 2927 | 3128 | debugM $ "ExplicitList end"
|
| 2928 | - return (ExplicitList an1 es')
|
|
| 3129 | + return (ExplicitList (o',c') es')
|
|
| 2929 | 3130 | exact (RecordCon x con_id binds) = do
|
| 2930 | 3131 | con_id' <- markAnnotated con_id
|
| 2931 | 3132 | binds' <- markAnnotated binds
|
| ... | ... | @@ -3335,8 +3536,8 @@ instance ExactPrint (HsCmd GhcPs) where |
| 3335 | 3536 | arr' <- markAnnotated arr
|
| 3336 | 3537 | return (HsCmdArrApp (isU, l') arr' arg' HsHigherOrderApp False)
|
| 3337 | 3538 | |
| 3338 | - exact (HsCmdArrForm an e fixity cs) = do
|
|
| 3339 | - an0 <- markLensBracketsO' an lal_brackets
|
|
| 3539 | + exact (HsCmdArrForm (o,c) e fixity cs) = do
|
|
| 3540 | + o' <- markEpUniToken o
|
|
| 3340 | 3541 | (e',cs') <- case (fixity, cs) of
|
| 3341 | 3542 | (Infix, (arg1:argrest)) -> do
|
| 3342 | 3543 | arg1' <- markAnnotated arg1
|
| ... | ... | @@ -3348,8 +3549,8 @@ instance ExactPrint (HsCmd GhcPs) where |
| 3348 | 3549 | cs' <- mapM markAnnotated cs
|
| 3349 | 3550 | return (e', cs')
|
| 3350 | 3551 | (Infix, []) -> error "Not possible"
|
| 3351 | - an1 <- markLensBracketsC' an0 lal_brackets
|
|
| 3352 | - return (HsCmdArrForm an1 e' fixity cs')
|
|
| 3552 | + c' <- markEpUniToken c
|
|
| 3553 | + return (HsCmdArrForm (o',c') e' fixity cs')
|
|
| 3353 | 3554 | |
| 3354 | 3555 | exact (HsCmdApp an e1 e2) = do
|
| 3355 | 3556 | e1' <- markAnnotated e1
|
| ... | ... | @@ -4671,9 +4872,11 @@ instance ExactPrint (Pat GhcPs) where |
| 4671 | 4872 | pat' <- markAnnotated pat
|
| 4672 | 4873 | return (BangPat an0 pat')
|
| 4673 | 4874 | |
| 4674 | - exact (ListPat an pats) = do
|
|
| 4675 | - (an', pats') <- markAnnList' an (mapM markAnnotated pats)
|
|
| 4676 | - return (ListPat an' pats')
|
|
| 4875 | + exact (ListPat (os,cs) pats) = do
|
|
| 4876 | + os' <- markEpToken os
|
|
| 4877 | + pats' <- mapM markAnnotated pats
|
|
| 4878 | + cs' <- markEpToken cs
|
|
| 4879 | + return (ListPat (os',cs') pats')
|
|
| 4677 | 4880 | |
| 4678 | 4881 | exact (TuplePat an pats boxity) = do
|
| 4679 | 4882 | an0 <- markOpeningParen an
|
| ... | ... | @@ -342,10 +342,8 @@ insertTopLevelCppComments (HsModule (XModulePs an lo mdeprec mbDoc) mmn mexports |
| 342 | 342 | (xs',rest') = allocPreceding xs rest
|
| 343 | 343 | |
| 344 | 344 | annListBracketsLocs :: AnnListBrackets -> (EpaLocation,EpaLocation)
|
| 345 | -annListBracketsLocs (ListParens o c) = (getEpTokenLoc o, getEpTokenLoc c)
|
|
| 346 | 345 | annListBracketsLocs (ListBraces o c) = (getEpTokenLoc o, getEpTokenLoc c)
|
| 347 | 346 | annListBracketsLocs (ListSquare o c) = (getEpTokenLoc o, getEpTokenLoc c)
|
| 348 | -annListBracketsLocs (ListBanana o c) = (getEpUniTokenLoc o, getEpUniTokenLoc c)
|
|
| 349 | 347 | annListBracketsLocs ListNone = (noAnn, noAnn)
|
| 350 | 348 | |
| 351 | 349 | data SplitWhere = Before | After
|