@@ -2585,22 +2585,54 @@ object Parsers {
25852585 mkIf(cond, thenp, elsep)
25862586 }
25872587
2588+ /* When parsing (what will become) a sub sub match, that is,
2589+ * when in a guard of case of a match, in a guard of case of a match;
2590+ * we will eventually reach Scanners.handleNewLine at the end of the sub sub match
2591+ * with an in.currretRegion of the shape `InCase +: Indented :+ InCase :+ Indented :+ ...`
2592+ * if we did not do dropInnerCaseRegion.
2593+ * In effect, a single outdent would be inserted by handleNewLine after the sub sub match.
2594+ * This causes the remaining cases of the outer match to be included in the intermediate sub match.
2595+ * For example:
2596+ * match
2597+ * case x1 if x1 match
2598+ * case y if y match
2599+ * case z => "a"
2600+ * case x2 => "b"
2601+ * would become
2602+ * match
2603+ * case x1 if x1 match {
2604+ * case y if y match {
2605+ * case z => "a"
2606+ * }
2607+ * case x2 => "b"
2608+ * }
2609+ * This issue is avoided by dropping the `InCase` region when parsing match clause,
2610+ * since `Indetented :+ Indented :+ ...` now allows handleNewLine to insert two outdents.
2611+ * Note that this _could_ break previous code which relied on matches within guards
2612+ * being considered as a separate region without explicit indentation.
2613+ */
2614+ private def dropInnerCaseRegion (): Unit =
2615+ in.currentRegion match
2616+ case Indented (width, prefix, Scanners .InCase (r)) => in.currentRegion = Indented (width, prefix, r)
2617+ case Scanners .InCase (r) => in.currentRegion = r
2618+ case _ =>
2619+
25882620 /** MatchClause ::= `match' `{' CaseClauses `}'
2621+ * | `match' ExprCaseClause
25892622 */
25902623 def matchClause (t : Tree ): Match =
25912624 atSpan(startOffset(t), in.skipToken()) {
2592- Match (t, inBracesOrIndented(caseClauses(() => caseClause())))
2625+ val cases =
2626+ if in.featureEnabled(Feature .subCases) then
2627+ dropInnerCaseRegion()
2628+ if in.token == CASE
2629+ then caseClause(exprOnly = true ) :: Nil // single case without new line
2630+ else inBracesOrIndented(caseClauses(() => caseClause()))
2631+ else
2632+ inBracesOrIndented(caseClauses(() => caseClause()))
2633+ Match (t, cases)
25932634 }
25942635
2595- /** SubMatchClause ::= `match' `{' CaseClauses `}'
2596- */
2597- def subMatchClause (t : Tree ): SubMatch = atSpan(startOffset(t), accept(MATCH )):
2598- val cases =
2599- if in.token == CASE
2600- then caseClause(exprOnly = true ) :: Nil // single sub case without new line
2601- else inBracesOrIndented(caseClauses(() => caseClause()))
2602- SubMatch (t, cases)
2603-
26042636 /** `match' <<< TypeCaseClauses >>>
26052637 */
26062638 def matchType (t : Tree ): MatchTypeTree =
@@ -3109,12 +3141,19 @@ object Parsers {
31093141 accept(CASE )
31103142 (withinMatchPattern(pattern()), guard())
31113143 }
3112- val body =
3113- if in.token == WITH && in.featureEnabled(Feature .subCases) then atSpan(in.skipToken()):
3114- val t = subMatchClause(simpleExpr(Location .ElseWhere ))
3144+ var grd1 = grd // may be reset to EmptyTree (and used as sub match body instead) if there is no leading ARROW
3145+ val tok = in.token
3146+
3147+ extension (self : Tree ) def asSubMatch : Tree = self match
3148+ case Match (sel, cases) if in.featureEnabled(Feature .subCases) =>
31153149 if in.isStatSep then in.nextToken() // else may have been consumed by sub sub match
3116- t
3117- else atSpan(accept(ARROW )):
3150+ SubMatch (sel, cases)
3151+ case _ =>
3152+ syntaxErrorOrIncomplete(ExpectedTokenButFound (ARROW , tok))
3153+ EmptyTree
3154+
3155+ val body = tok match
3156+ case ARROW => atSpan(in.skipToken()):
31183157 if exprOnly then
31193158 if in.indentSyntax && in.isAfterLineEnd && in.token != INDENT then
31203159 warning(em """ Misleading indentation: this expression forms part of the preceding catch case.
@@ -3123,7 +3162,16 @@ object Parsers {
31233162 |an indented case. """ )
31243163 expr()
31253164 else block()
3126- CaseDef (pat, grd, body)
3165+ case IF => atSpan(in.skipToken()):
3166+ // a sub match after a guard is parsed the same as one without
3167+ val t = inSepRegion(InCase )(postfixExpr(Location .InGuard ))
3168+ t.asSubMatch
3169+ case other =>
3170+ val t = grd1.asSubMatch
3171+ grd1 = EmptyTree
3172+ t
3173+
3174+ CaseDef (pat, grd1, body)
31273175 }
31283176
31293177 /** TypeCaseClause ::= ‘case’ (InfixType | ‘_’) ‘=>’ Type [semi]
0 commit comments