Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC Commits: 9769cc03 by Simon Hengel at 2026-02-01T04:21:03-05:00 Update the documentation for MultiWayIf (fixes #25376) (so that it matches the implementation) - - - - - 5fc9442a by Peter Trommler at 2026-02-01T04:21:44-05:00 hadrian: Fix dependency generation for assembler Assembler files allow # for comments unless in column 1. A modern cpp for C treats those a preprocessor directives. We tell gcc that a .S file is assembler with cpp and not C. Fixes #26819 - - - - - 74dbb224 by Simon Peyton Jones at 2026-02-01T15:07:49-05:00 Include current phase in the range for rule/unfoldings This MR fixes a bad loop in the compiler: #26826. The fix is to add (WAR2) to Note [What is active in the RHS of a RULE or unfolding?] in GHC.Core.Opt.Simplify.Utils - - - - - f856b07b by Vladislav Zavialov at 2026-02-01T15:07:50-05:00 Refactor: merge HsMultilineString into HsString (#26860) Before this patch, HsLit defined two separate constructors to represent single-line and multi-line strings: data HsLit x ... | HsString (XHsString x) FastString | HsMultilineString (XHsMultilineString x) FastString I found this to be an unnecessary complication and an obstacle to unifying HsLit with HsTyLit. Now we use HsString for both kinds of literals. One user-facing change here is `ppr (HsString st s)` behaving differently for single-line strings containing newlines: x = "first line \ \asdf\n\ \second line" Previously, the literal was fed to `ftext` with its newlines, producing an ill-formed SDoc. This issue is now addressed by using `split` for both single-line and multi-line strings: vcat $ map text $ split '\n' (unpackFS src) See the parser/should_fail/T26860ppr test. In addition (and unrelatedly to the main payload of this patch), drop the unused pmPprHsLit helper. - - - - - 26 changed files: - compiler/GHC/Core/Opt/OccurAnal.hs - compiler/GHC/Core/Opt/Simplify/Env.hs - compiler/GHC/Core/Opt/Simplify/Utils.hs - compiler/GHC/Core/Opt/WorkWrap.hs - compiler/GHC/Hs/Lit.hs - compiler/GHC/Hs/Syn/Type.hs - compiler/GHC/HsToCore/Match/Literal.hs - compiler/GHC/HsToCore/Quote.hs - compiler/GHC/Parser.y - compiler/GHC/Parser/String.hs - compiler/GHC/Rename/Expr.hs - compiler/GHC/Tc/Gen/HsType.hs - compiler/GHC/Types/InlinePragma.hs - compiler/Language/Haskell/Syntax/Extension.hs - compiler/Language/Haskell/Syntax/Lit.hs - docs/users_guide/exts/multiway_if.rst - hadrian/src/Builder.hs - hadrian/src/Rules/Compile.hs - hadrian/src/Settings/Builders/Cc.hs - hadrian/src/Settings/Packages.hs - + testsuite/tests/parser/should_fail/T26860ppr.hs - + testsuite/tests/parser/should_fail/T26860ppr.stderr - testsuite/tests/parser/should_fail/all.T - + testsuite/tests/simplCore/should_compile/T26826.hs - testsuite/tests/simplCore/should_compile/all.T - utils/check-exact/ExactPrint.hs Changes: ===================================== compiler/GHC/Core/Opt/OccurAnal.hs ===================================== @@ -1417,16 +1417,17 @@ then we *must* choose f to be a loop breaker. Example: see Note That is the whole reason for computing rule_fv_env in mkLoopBreakerNodes. Wrinkles: -* We only consider /active/ rules. See Note [Finding rule RHS free vars] +(RLB1) We only consider /active/ rules. + This is important: see Note [Finding rule RHS free vars] -* We need only consider free vars that are also binders in this Rec +(RLB2) We need only consider free vars that are also binders in this Rec group. See also Note [Finding rule RHS free vars] -* We only consider variables free in the *RHS* of the rule, in +(RLB3) We only consider variables free in the *RHS* of the rule, in contrast to the way we build the Rec group in the first place (Note [Rule dependency info]) -* Why "transitive sequence of rules"? Because active rules apply +(RLB4) Why "transitive sequence of rules"? Because active rules apply unconditionally, without checking loop-breaker-ness. See Note [Loop breaker dependencies]. @@ -1854,10 +1855,13 @@ makeNode !env imp_rule_edges bndr_set (bndr, rhs) add_rule_uds (_, l, r) uds = l `andUDs` r `andUDs` uds -------- active_rule_fvs ------------ + -- See Note [Rules and loop breakers] active_rule_fvs = foldr add_active_rule imp_rule_fvs rules_w_uds add_active_rule (rule, _, rhs_uds) fvs - | is_active (ruleActivation rule) + | is_active (ruleActivation rule) -- See (RLB1) = udFreeVars bndr_set rhs_uds `unionVarSet` fvs + -- Only consider the `rhs_uss`, not the LHS ones; see (RLB3) + -- udFreeVars restricts to bndr_set; see (RLB2) | otherwise = fvs ===================================== compiler/GHC/Core/Opt/Simplify/Env.hs ===================================== @@ -12,7 +12,7 @@ module GHC.Core.Opt.Simplify.Env ( -- * Environments SimplEnv(..), pprSimplEnv, -- Temp not abstract - SimplPhase(..), isActive, + SimplPhase(..), isActive, simplStartPhase, simplEndPhase, seArityOpts, seCaseCase, seCaseFolding, seCaseMerge, seCastSwizzle, seDoEtaReduction, seEtaExpand, seFloatEnable, seInline, seNames, seOptCoercionOpts, sePhase, sePlatform, sePreInline, @@ -293,7 +293,9 @@ data SimplMode = SimplMode -- See comments in GHC.Core.Opt.Simplify.Monad -- | See Note [SimplPhase] data SimplPhase -- | A simplifier phase: InitialPhase, Phase 2, Phase 1, Phase 0, FinalPhase + -- NB: (SimplPhase p) is equivalent to (SimplPhaseRange p p) = SimplPhase CompilerPhase + -- | Simplifying the RHS of a rule or of a stable unfolding: the range of -- phases of the activation of the rule/stable unfolding. -- @@ -302,13 +304,18 @@ data SimplPhase -- -- See Note [What is active in the RHS of a RULE or unfolding?] -- in GHC.Core.Opt.Simplify.Utils. - | SimplPhaseRange - { simplStartPhase :: CompilerPhase - , simplEndPhase :: CompilerPhase - } + | SimplPhaseRange CompilerPhase CompilerPhase deriving Eq +simplStartPhase :: SimplPhase -> CompilerPhase +simplStartPhase (SimplPhase p) = p +simplStartPhase (SimplPhaseRange p _) = p + +simplEndPhase :: SimplPhase -> CompilerPhase +simplEndPhase (SimplPhase p) = p +simplEndPhase (SimplPhaseRange _ p) = p + instance Outputable SimplPhase where ppr (SimplPhase p) = ppr p ppr (SimplPhaseRange s e) = brackets $ ppr s <> ellipsis <> ppr e @@ -322,12 +329,13 @@ instance Outputable SimplPhase where -- -- See Note [SimplPhase]. isActive :: SimplPhase -> ActivationGhc -> Bool -isActive (SimplPhase p) act = isActiveInPhase p act -isActive (SimplPhaseRange start end) act = - -- To check whether the activation is active throughout the whole phase range, - -- it's sufficient to check the endpoints of the phase range, because an - -- activation can never have gaps (all activations are phase intervals). - isActiveInPhase start act && isActiveInPhase end act +isActive (SimplPhase p) act + = isActiveInPhase p act +isActive (SimplPhaseRange start end) act + = -- To check whether the activation is active throughout the whole phase range, + -- it's sufficient to check the endpoints of the phase range, because an + -- activation can never have gaps (all activations are phase intervals). + isActiveInPhase start act && isActiveInPhase end act {- Note [SimplPhase] ~~~~~~~~~~~~~~~~~~~~ ===================================== compiler/GHC/Core/Opt/Simplify/Utils.hs ===================================== @@ -1099,7 +1099,7 @@ updModeForStableUnfoldings :: ActivationGhc -> SimplMode -> SimplMode -- See Note [Simplifying inside stable unfoldings] updModeForStableUnfoldings unf_act current_mode = current_mode - { sm_phase = phaseFromActivation (sm_phase current_mode) unf_act + { sm_phase = phaseForRuleOrUnf (sm_phase current_mode) unf_act -- See Note [What is active in the RHS of a RULE or unfolding?] , sm_eta_expand = False -- See Note [Eta expansion in stable unfoldings and rules] @@ -1123,27 +1123,32 @@ updModeForRuleRHS :: ActivationGhc -> SimplMode -> SimplMode updModeForRuleRHS rule_act current_mode = current_mode -- See Note [What is active in the RHS of a RULE or unfolding?] - { sm_phase = phaseFromActivation (sm_phase current_mode) rule_act + { sm_phase = phaseForRuleOrUnf (sm_phase current_mode) rule_act , sm_eta_expand = False -- See Note [Eta expansion in stable unfoldings and rules] } --- | Compute the phase range to set the 'SimplMode' to --- when simplifying the RHS of a rule or of a stable unfolding. +-- | `phaseForRuleOrUnf` computes the phase range to use when +-- simplifying the RHS of a rule or of a stable unfolding. -- +-- This subtle function implements the careful plan described in -- See Note [What is active in the RHS of a RULE or unfolding?] -phaseFromActivation - :: SimplPhase -- ^ the current simplifier phase +phaseForRuleOrUnf + :: SimplPhase -- ^ the current simplifier phase -> ActivationGhc -- ^ the activation of the RULE or stable unfolding -> SimplPhase -phaseFromActivation p act - | isNeverActive act - = p +phaseForRuleOrUnf current_phase act + | start == end + = SimplPhase start | otherwise - = SimplPhaseRange act_start act_end + = SimplPhaseRange start end where - act_start = beginPhase act - act_end = endPhase act + start, end :: CompilerPhase + start = beginPhase act `earliestPhase` simplStartPhase current_phase + end = endPhase act `latestPhase` simplEndPhase current_phase + -- The beginPhase/endPhase implements (WAR1) + -- The simplStartPhase/simplEndPhase implements (WAR2) + -- of Note [What is active in the RHS of a RULE or unfolding?] {- Note [Simplifying rules] ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1275,26 +1280,47 @@ Our carefully crafted plan is as follows: ------------------------------------------------------------- When simplifying the RHS of a RULE R with activation range A, - fire only other rules R' that are active throughout all of A. + fire only other rules R' that are active + (WAR1) throughout all of A + (WAR2) in the current phase + See `phaseForRuleOrUnf`. ------------------------------------------------------------- -Reason: R might fire in any phase in A. Then R' can fire only if R' is active -in that phase. If not, it's not safe to unconditionally fire R' in the RHS of R. +Reasons for (WAR1): + * R might fire in any phase in A. Then R' can fire only if R' is active in that + phase. If not, it's not safe to unconditionally fire R' in the RHS of R. + +Reasons for (WAR2): + * If A is empty (e.g. a NOINLINE pragma, so the unfolding is never active) + we don't want to vacuously satisfy (WAR1) and thereby fire /all/ RULES in + the unfolding. Two RULES may be crafted so that they are never simultaneously + active, and will loop if they are. + + * Suppose we are in Phase 2, looking at a stable unfolding for INLINE [1]. + If we just do (WAR1) we will fire RULES active in phase 1; but the + occurrence analyser ignores any rules not active in the current phase. + So occ-anal may fail to detect a loop breaker; see #26826 for details. + See Note [Rules and loop breakers] in GHC.Core.Opt.OccurAnal. + + * Aesthetically, this means that when the simplifer is in phase N, it + won't switch to a phase-range that doesn't include N (e.g. might be later + than N). This is what caused #26826. + + * Also note that as the current phase advances, it'll eventually be inside + the range specified by (WAR1), and hence will not widen the range. + Unless the latter is empty, of course. This plan is implemented by: - 1. Setting the simplifier phase to the range of phases - corresponding to the start/end phases of the rule's activation. + 1. Setting the simplifier phase to the /range/ of phases + corresponding to the start/end phases of the rule's activation, implementing + (WAR1) and (WAR2). This happens in `phaseForRuleOrUnf`. + 2. When checking whether another rule is active, we use the function isActive :: SimplPhase -> Activation -> Bool from GHC.Core.Opt.Simplify.Env, which checks whether the other rule is active throughout the whole range of phases. -However, if the rule whose RHS we are simplifying is never active, instead of -setting the phase range to an empty interval, we keep the current simplifier -phase. This special case avoids firing ALL rules in the RHS of a never-active -rule. - You might wonder about a situation such as the following: module M1 where @@ -1307,6 +1333,7 @@ It looks tempting to use "r1" when simplifying the RHS of "r2", yet we **must not** do so: for any module M that imports M1, we are going to start simplification in M starting at InitialPhase, and we will see the fully simplified rules RHSs imported from M1. + Conclusion: stick to the plan. Note [Simplifying inside stable unfoldings] ===================================== compiler/GHC/Core/Opt/WorkWrap.hs ===================================== @@ -914,9 +914,9 @@ mkStrWrapperInlinePrag (InlinePragma { inl_inline = fn_inl where srcTxt = SourceText $ fsLit "{-# INLINE" -- See Note [Wrapper activation] - wrapper_phase = foldr (laterPhase . get_rule_phase) earliest_inline_phase rules - earliest_inline_phase = beginPhase fn_act `laterPhase` nextPhase InitialPhase - -- laterPhase (nextPhase InitialPhase) is a temporary hack + wrapper_phase = foldr (latestPhase . get_rule_phase) earliest_inline_phase rules + earliest_inline_phase = beginPhase fn_act `latestPhase` nextPhase InitialPhase + -- latestPhase (nextPhase InitialPhase) is a temporary hack -- to inline no earlier than phase 2. I got regressions in -- 'mate', due to changes in full laziness due to Note [Case -- MFEs], when I did earlier inlining. ===================================== compiler/GHC/Hs/Lit.hs ===================================== @@ -45,7 +45,6 @@ import Language.Haskell.Syntax.Lit type instance XHsChar (GhcPass _) = SourceText type instance XHsCharPrim (GhcPass _) = SourceText type instance XHsString (GhcPass _) = SourceText -type instance XHsMultilineString (GhcPass _) = SourceText type instance XHsStringPrim (GhcPass _) = SourceText type instance XHsInt (GhcPass _) = NoExtField type instance XHsIntPrim (GhcPass _) = SourceText @@ -147,7 +146,6 @@ hsLitNeedsParens p = go go (HsChar {}) = False go (HsCharPrim {}) = False go (HsString {}) = False - go (HsMultilineString {}) = False go (HsStringPrim {}) = False go (HsInt _ x) = p > topPrec && il_neg x go (HsFloatPrim {}) = False @@ -177,7 +175,6 @@ convertLit :: XXLit (GhcPass p)~DataConCantHappen => HsLit (GhcPass p) -> HsLit convertLit (HsChar a x) = HsChar a x convertLit (HsCharPrim a x) = HsCharPrim a x convertLit (HsString a x) = HsString a x -convertLit (HsMultilineString a x) = HsMultilineString a x convertLit (HsStringPrim a x) = HsStringPrim a x convertLit (HsInt a x) = HsInt a x convertLit (HsIntPrim a x) = HsIntPrim a x @@ -212,8 +209,7 @@ Equivalently it's True if instance IsPass p => Outputable (HsLit (GhcPass p)) where ppr (HsChar st c) = pprWithSourceText st (pprHsChar c) ppr (HsCharPrim st c) = pprWithSourceText st (pprPrimChar c) - ppr (HsString st s) = pprWithSourceText st (pprHsString s) - ppr (HsMultilineString st s) = + ppr (HsString st s) = case st of NoSourceText -> pprHsString s SourceText src -> vcat $ map text $ split '\n' (unpackFS src) @@ -248,36 +244,6 @@ instance Outputable OverLitVal where ppr (HsFractional f) = ppr f ppr (HsIsString st s) = pprWithSourceText st (pprHsString s) --- | pmPprHsLit pretty prints literals and is used when pretty printing pattern --- match warnings. All are printed the same (i.e., without hashes if they are --- primitive and not wrapped in constructors if they are boxed). This happens --- mainly for too reasons: --- * We do not want to expose their internal representation --- * The warnings become too messy -pmPprHsLit :: forall p. IsPass p => HsLit (GhcPass p) -> SDoc -pmPprHsLit (HsChar _ c) = pprHsChar c -pmPprHsLit (HsCharPrim _ c) = pprHsChar c -pmPprHsLit (HsString st s) = pprWithSourceText st (pprHsString s) -pmPprHsLit (HsMultilineString st s) = pprWithSourceText st (pprHsString s) -pmPprHsLit (HsStringPrim _ s) = pprHsBytes s -pmPprHsLit (HsInt _ i) = integer (il_value i) -pmPprHsLit (HsIntPrim _ i) = integer i -pmPprHsLit (HsWordPrim _ w) = integer w -pmPprHsLit (HsInt8Prim _ i) = integer i -pmPprHsLit (HsInt16Prim _ i) = integer i -pmPprHsLit (HsInt32Prim _ i) = integer i -pmPprHsLit (HsInt64Prim _ i) = integer i -pmPprHsLit (HsWord8Prim _ w) = integer w -pmPprHsLit (HsWord16Prim _ w) = integer w -pmPprHsLit (HsWord32Prim _ w) = integer w -pmPprHsLit (HsWord64Prim _ w) = integer w -pmPprHsLit (HsFloatPrim _ f) = ppr f -pmPprHsLit (HsDoublePrim _ d) = ppr d -pmPprHsLit (XLit x) = case ghcPass @p of - GhcTc -> case x of - (HsInteger _ i _) -> integer i - (HsRat f _) -> ppr f - negateOverLitVal :: OverLitVal -> OverLitVal negateOverLitVal (HsIntegral i) = HsIntegral (negateIntegralLit i) negateOverLitVal (HsFractional f) = HsFractional (negateFractionalLit f) ===================================== compiler/GHC/Hs/Syn/Type.hs ===================================== @@ -75,7 +75,6 @@ hsLitType :: forall p. IsPass p => HsLit (GhcPass p) -> Type hsLitType (HsChar _ _) = charTy hsLitType (HsCharPrim _ _) = charPrimTy hsLitType (HsString _ _) = stringTy -hsLitType (HsMultilineString _ _) = stringTy hsLitType (HsStringPrim _ _) = addrPrimTy hsLitType (HsInt _ _) = intTy hsLitType (HsIntPrim _ _) = intPrimTy ===================================== compiler/GHC/HsToCore/Match/Literal.hs ===================================== @@ -117,7 +117,6 @@ dsLit l = do HsDoublePrim _ fl -> return (Lit (LitDouble (rationalFromFractionalLit fl))) HsChar _ c -> return (mkCharExpr c) HsString _ str -> mkStringExprFS str - HsMultilineString _ str -> mkStringExprFS str HsInt _ i -> return (mkIntExpr platform (il_value i)) XLit x -> case ghcPass @p of GhcTc -> case x of @@ -463,7 +462,6 @@ getSimpleIntegralLit (XLit (HsInteger _ i ty)) = Just (i, ty) getSimpleIntegralLit HsChar{} = Nothing getSimpleIntegralLit HsCharPrim{} = Nothing getSimpleIntegralLit HsString{} = Nothing -getSimpleIntegralLit HsMultilineString{} = Nothing getSimpleIntegralLit HsStringPrim{} = Nothing getSimpleIntegralLit (XLit (HsRat{})) = Nothing getSimpleIntegralLit HsFloatPrim{} = Nothing ===================================== compiler/GHC/HsToCore/Quote.hs ===================================== @@ -3077,7 +3077,6 @@ repLiteral lit HsChar _ _ -> Just charLName HsCharPrim _ _ -> Just charPrimLName HsString _ _ -> Just stringLName - HsMultilineString _ _ -> Just stringLName _ -> Nothing mk_integer :: Integer -> MetaM (HsLit GhcTc) ===================================== compiler/GHC/Parser.y ===================================== @@ -4131,7 +4131,7 @@ literal :: { Located (HsLit GhcPs) } : CHAR { sL1 $1 $ HsChar (getCHARs $1) $ getCHAR $1 } | STRING { sL1 $1 $ HsString (getSTRINGs $1) $ getSTRING $1 } - | STRING_MULTI { sL1 $1 $ HsMultilineString (getSTRINGMULTIs $1) + | STRING_MULTI { sL1 $1 $ HsString (getSTRINGMULTIs $1) $ getSTRINGMULTI $1 } | PRIMINTEGER { sL1 $1 $ HsIntPrim (getPRIMINTEGERs $1) $ getPRIMINTEGER $1 } ===================================== compiler/GHC/Parser/String.hs ===================================== @@ -392,9 +392,9 @@ proposal: https://github.com/ghc-proposals/ghc-proposals/pull/569 Multiline string literals are syntax sugar for normal string literals, with an extra post processing step. This all happens in the Lexer; that -is, HsMultilineString will contain the post-processed string. This matches -the same behavior as HsString, which contains the normalized string -(see Note [Literal source text]). +is, the multi-line HsString will contain the post-processed string. +This matches the behavior of the single-line HsString, which contains +the normalized string too (see Note [Literal source text]). The canonical steps for post processing a multiline string are: 1. Collapse string gaps ===================================== compiler/GHC/Rename/Expr.hs ===================================== @@ -352,18 +352,13 @@ rnExpr (HsOverLabel src v) hs_ty_arg = mkEmptyWildCardBndrs $ wrapGenSpan $ HsTyLit noExtField (HsStrTy NoSourceText v) -rnExpr (HsLit x lit) | Just (src, s) <- stringLike lit +rnExpr (HsLit x lit) | HsString src s <- lit = do { opt_OverloadedStrings <- xoptM LangExt.OverloadedStrings ; if opt_OverloadedStrings then rnExpr (HsOverLit x (mkHsIsString src s)) else do { ; rnLit lit ; return (HsLit x (convertLit lit), emptyFVs) } } - where - stringLike = \case - HsString src s -> Just (src, s) - HsMultilineString src s -> Just (src, s) - _ -> Nothing rnExpr (HsLit x lit) = do { rnLit lit ===================================== compiler/GHC/Tc/Gen/HsType.hs ===================================== @@ -4786,7 +4786,6 @@ promotionErr name err tyLitFromLit :: HsLit GhcRn -> Maybe (HsTyLit GhcRn) tyLitFromLit (HsString x str) = Just (HsStrTy x str) -tyLitFromLit (HsMultilineString x str) = Just (HsStrTy x str) tyLitFromLit (HsChar x char) = Just (HsCharTy x char) tyLitFromLit _ = Nothing ===================================== compiler/GHC/Types/InlinePragma.hs ===================================== @@ -104,9 +104,8 @@ module GHC.Types.InlinePragma , endPhase -- *** Queries , isActiveInPhase - , laterPhase - , laterThanPhase - , nextPhase + , latestPhase, earliestPhase + , laterThanPhase, nextPhase ) where import GHC.Prelude @@ -422,13 +421,21 @@ nextPhase (Phase 0) = FinalPhase nextPhase (Phase n) = Phase (n-1) nextPhase FinalPhase = FinalPhase -laterPhase :: CompilerPhase -> CompilerPhase -> CompilerPhase --- ^ Returns the later of two phases -laterPhase (Phase n1) (Phase n2) = Phase (n1 `min` n2) -laterPhase InitialPhase p2 = p2 -laterPhase FinalPhase _ = FinalPhase -laterPhase p1 InitialPhase = p1 -laterPhase _ FinalPhase = FinalPhase +earliestPhase :: CompilerPhase -> CompilerPhase -> CompilerPhase +-- ^ Returns the earliest of two phases +earliestPhase (Phase n1) (Phase n2) = Phase (n1 `max` n2) +earliestPhase InitialPhase _ = InitialPhase +earliestPhase FinalPhase p2 = p2 +earliestPhase _ InitialPhase = InitialPhase +earliestPhase p1 FinalPhase = p1 + +latestPhase :: CompilerPhase -> CompilerPhase -> CompilerPhase +-- ^ Returns the latest of two phases +latestPhase (Phase n1) (Phase n2) = Phase (n1 `min` n2) +latestPhase InitialPhase p2 = p2 +latestPhase FinalPhase _ = FinalPhase +latestPhase p1 InitialPhase = p1 +latestPhase _ FinalPhase = FinalPhase -- | @p1 `laterThanOrEqualPhase` p2@ computes whether @p1@ happens (strictly) -- after @p2@. ===================================== compiler/Language/Haskell/Syntax/Extension.hs ===================================== @@ -609,7 +609,6 @@ type family XXParStmtBlock x x' type family XHsChar x type family XHsCharPrim x type family XHsString x -type family XHsMultilineString x type family XHsStringPrim x type family XHsInt x type family XHsIntPrim x ===================================== compiler/Language/Haskell/Syntax/Lit.hs ===================================== @@ -47,8 +47,6 @@ data HsLit x -- ^ Unboxed character | HsString (XHsString x) {- SourceText -} FastString -- ^ String - | HsMultilineString (XHsMultilineString x) {- SourceText -} FastString - -- ^ String | HsStringPrim (XHsStringPrim x) {- SourceText -} !ByteString -- ^ Packed bytes | HsInt (XHsInt x) IntegralLit ===================================== docs/users_guide/exts/multiway_if.rst ===================================== @@ -10,7 +10,7 @@ Multi-way if-expressions Allow the use of multi-way-``if`` syntax. -With :extension:`MultiWayIf` extension GHC accepts conditional expressions with +With the :extension:`MultiWayIf` extension GHC accepts conditional expressions with multiple branches: :: if | guard1 -> expr1 @@ -24,12 +24,12 @@ which is roughly equivalent to :: ... _ | guardN -> exprN -Multi-way if expressions introduce a new layout context. So the example +Multi-way if expressions introduce a new kind of layout context that does not generate semicolons. The example above is equivalent to: :: if { | guard1 -> expr1 - ; | ... - ; | guardN -> exprN + | ... + | guardN -> exprN } The following behaves as expected: :: @@ -41,14 +41,14 @@ The following behaves as expected: :: because layout translates it as :: if { | guard1 -> if { | guard2 -> expr2 - ; | guard3 -> expr3 + | guard3 -> expr3 } - ; | guard4 -> expr4 + | guard4 -> expr4 } Layout with multi-way if works in the same way as other layout contexts, -except that the semi-colons between guards in a multi-way if are -optional. So it is not necessary to line up all the guards at the same +except that desugaring does not insert semicolons. +So it is not necessary to line up all the guards at the same column; this is consistent with the way guards work in function definitions and case expressions. ===================================== hadrian/src/Builder.hs ===================================== @@ -49,7 +49,7 @@ import GHC.Toolchain.Program -- * Compile or preprocess a source file. -- * Extract source dependencies by passing @-MM@ command line argument. data CcMode = CompileC | FindCDependencies DependencyType deriving (Eq, Generic, Show) -data DependencyType = CDep | CxxDep deriving (Eq, Generic, Show) +data DependencyType = CDep | CxxDep | AsmDep deriving (Eq, Generic, Show) instance Binary CcMode instance Hashable CcMode ===================================== hadrian/src/Rules/Compile.hs ===================================== @@ -282,8 +282,11 @@ needDependencies lang context@Context {..} src depFile = do discover -- Continue the discovery process -- We need to pass different flags to cc depending on whether the - -- file to compile is a .c or a .cpp file - depType = if lang == Cxx then CxxDep else CDep + -- file to compile is a .c or a .cpp or a .S file + depType = case lang of + Cxx -> CxxDep + Asm -> AsmDep + _ -> CDep parseFile :: FilePath -> Action [String] parseFile file = do ===================================== hadrian/src/Settings/Builders/Cc.hs ===================================== @@ -18,6 +18,7 @@ ccBuilderArgs = do , arg "-o", arg =<< getOutput ] , builder (Cc (FindCDependencies CDep)) ? findCDepExpr CDep , builder (Cc (FindCDependencies CxxDep)) ? findCDepExpr CxxDep + , builder (Cc (FindCDependencies AsmDep)) ? findCDepExpr AsmDep ] where findCDepExpr depType = do @@ -26,10 +27,10 @@ ccBuilderArgs = do , arg "-MM", arg "-MG" , arg "-MF", arg output , arg "-MT", arg $ dropExtension output -<.> "o" - , case depType of CDep -> mempty; CxxDep -> arg "-std=c++11" + , case depType of CDep -> mempty; CxxDep -> arg "-std=c++11"; AsmDep -> mempty , cIncludeArgs - , arg "-x", arg (case depType of CDep -> "c"; CxxDep -> "c++") - , case depType of CDep -> mempty; CxxDep -> getContextData cxxOpts + , arg "-x", arg (case depType of CDep -> "c"; CxxDep -> "c++"; AsmDep -> "assembler-with-cpp") + , case depType of CDep -> mempty; CxxDep -> getContextData cxxOpts; AsmDep -> mempty -- Pass 'ghcversion.h' to give sources access to the -- `MIN_VERSION_GLASGOW_HASKELL` macro. , notStage0 ? arg "-include" <> arg "rts/include/ghcversion.h" ===================================== hadrian/src/Settings/Packages.hs ===================================== @@ -428,6 +428,7 @@ rtsPackageArgs = package rts ? do ] , builder (Cc (FindCDependencies CDep)) ? cArgs , builder (Cc (FindCDependencies CxxDep)) ? cArgs + , builder (Cc (FindCDependencies AsmDep)) ? cArgs , builder (Ghc CompileCWithGhc) ? map ("-optc" ++) <$> cArgs , builder (Ghc CompileCppWithGhc) ? map ("-optcxx" ++) <$> cArgs , builder Ghc ? ghcArgs ===================================== testsuite/tests/parser/should_fail/T26860ppr.hs ===================================== @@ -0,0 +1,11 @@ +{-# LANGUAGE NoOverloadedStrings #-} + +module T26860ppr where + +-- Test that the error message containing the string literal is well-formatted. +-- See also: parser/should_fail/MultilineStringsError +x :: Int +x = "first line \ + \asdf\n\ + \second line" + ===================================== testsuite/tests/parser/should_fail/T26860ppr.stderr ===================================== @@ -0,0 +1,13 @@ +T26860ppr.hs:8:5: error: [GHC-83865] + • Couldn't match type ‘[Char]’ with ‘Int’ + Expected: Int + Actual: String + • In the expression: + "first line \ + \asdf\n\ + \second line" + In an equation for ‘x’: + x = "first line \ + \asdf\n\ + \second line" + ===================================== testsuite/tests/parser/should_fail/all.T ===================================== @@ -244,3 +244,4 @@ test('T25530', normal, compile_fail, ['']) test('T26418', normal, compile_fail, ['']) test('T12488c', normal, compile_fail, ['']) test('T12488d', normal, compile_fail, ['']) +test('T26860ppr', normal, compile_fail, ['']) ===================================== testsuite/tests/simplCore/should_compile/T26826.hs ===================================== @@ -0,0 +1,86 @@ +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE CPP #-} +{-# LANGUAGE GADTs #-} +{-# LANGUAGE KindSignatures #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeAbstractions #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeData #-} + +module T26826 where + +import Data.Kind (Type) + +type data AstSpan = + FullSpan | PrimalStepSpan AstSpan | PlainSpan + +data SAstSpan (s :: AstSpan) where + SFullSpan :: SAstSpan FullSpan + SPrimalStepSpan :: SAstSpan s -> SAstSpan (PrimalStepSpan s) + SPlainSpan :: SAstSpan PlainSpan + +class KnownSpan (s :: AstSpan) where + knownSpan :: SAstSpan s + +instance KnownSpan FullSpan where + knownSpan = SFullSpan + +instance KnownSpan s => KnownSpan (PrimalStepSpan s) where + knownSpan = SPrimalStepSpan (knownSpan @s) + +instance KnownSpan PlainSpan where + knownSpan = SPlainSpan + +class ADReady target where + ttlet :: target a -> (target a -> target b) -> target b + ttletPrimal :: target a -> (target a -> target b) -> target b + ttletPlain :: target a -> (target a -> target b) -> target b + tplainPart :: target a -> target a + tfromPlain :: target a -> target a + tprimalPart :: target a -> target a + tfromPrimal :: target a -> target a + +type SpanTargetFam target (s :: AstSpan) (y :: Type) = target y + +type AstEnv target = () + +data AstTensor (s :: AstSpan) (y :: Type) where + AstLet + :: forall a b s1 s2. + KnownSpan s1 + => AstTensor s1 a + -> AstTensor s2 b + -> AstTensor s2 b + + AstPrimalPart :: KnownSpan s' => AstTensor s' a -> AstTensor (PrimalStepSpan s') a + AstFromPrimal :: AstTensor (PrimalStepSpan s') a -> AstTensor s' a + AstPlainPart :: KnownSpan s' => AstTensor s' a -> AstTensor PlainSpan a + AstFromPlain :: AstTensor PlainSpan a -> AstTensor s' a + +interpretAst + :: forall target s y. (ADReady target, KnownSpan s) + => AstEnv target -> AstTensor s y + -> SpanTargetFam target s y +{-# INLINE [1] interpretAst #-} +interpretAst !env + = \case + AstLet @_ @_ @s1 @s2 u v -> + case knownSpan @s1 of + SFullSpan -> + ttlet (interpretAst env u) + (\_w -> interpretAst env v) + SPrimalStepSpan _ -> + ttletPrimal (interpretAst env u) + (\_w -> interpretAst env v) + SPlainSpan -> + ttletPlain (interpretAst env u) + (\_w -> interpretAst env v) + AstPrimalPart a -> + tprimalPart (interpretAst env a) + AstFromPrimal a -> + tfromPrimal (interpretAst env a) + AstPlainPart a -> + tplainPart (interpretAst env a) + AstFromPlain a -> + tfromPlain (interpretAst env a) ===================================== testsuite/tests/simplCore/should_compile/all.T ===================================== @@ -578,4 +578,6 @@ test('T26615', [grep_errmsg(r'fEqList')], multimod_compile, ['T26615', '-O -fsp # T26722: there should be no reboxing in $wg test('T26722', [grep_errmsg(r'SPEC')], compile, ['-O -dno-typeable-binds']) + test('T26805', [grep_errmsg(r'fromInteger')], compile, ['-O -dno-typeable-binds -ddump-simpl -dsuppress-uniques']) +test('T26826', normal, compile, ['-O']) ===================================== utils/check-exact/ExactPrint.hs ===================================== @@ -4794,7 +4794,6 @@ hsLit2String lit = HsChar src v -> toSourceTextWithSuffix src v "" HsCharPrim src p -> toSourceTextWithSuffix src p "" HsString src v -> toSourceTextWithSuffix src v "" - HsMultilineString src v -> toSourceTextWithSuffix src v "" HsStringPrim src v -> toSourceTextWithSuffix src v "" HsInt _ (IL src _ v) -> toSourceTextWithSuffix src v "" HsIntPrim src v -> toSourceTextWithSuffix src v "" View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/da4121c174228ef396ff0f6e1b00d24... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/da4121c174228ef396ff0f6e1b00d24... You're receiving this email because of your account on gitlab.haskell.org.