@@ -585,10 +585,44 @@ object Parsers {
585
585
try op finally in.adjustSepRegions(closing)
586
586
}
587
587
588
+ /** Parse `body` while checking (under -noindent) that a `{` is not missing before it.
589
+ * This is done as follows:
590
+ * If the next token S is indented relative to the current region,
591
+ * and the end of `body` is followed by a new line and another statement,
592
+ * check that that other statement is indented less than S
593
+ */
594
+ def subPart [T ](body : () => T ): T = in.currentRegion match
595
+ case r : InBraces if in.isAfterLineEnd =>
596
+ val startIndentWidth = in.indentWidth(in.offset)
597
+ if r.indentWidth < startIndentWidth then
598
+ // Note: we can get here only if indentation is not significant
599
+ // If indentation is significant, we would see an <indent> as current token
600
+ // and the indent region would be Indented instead of InBraces.
601
+ //
602
+ // If indentation would be significant, an <indent> would be inserted here.
603
+ val t = body()
604
+ // Therefore, make sure there would be a matching <outdent>
605
+ def nextIndentWidth = in.indentWidth(in.next.offset)
606
+ if (in.token == NEWLINE || in.token == NEWLINES )
607
+ && ! (nextIndentWidth < startIndentWidth)
608
+ then
609
+ syntaxError(
610
+ if startIndentWidth <= nextIndentWidth then
611
+ i """ Line is indented too far to the right, or a `{' is missing before:
612
+ |
613
+ | $t"""
614
+ else
615
+ in.spaceTabMismatchMsg(startIndentWidth, nextIndentWidth),
616
+ in.next.offset
617
+ )
618
+ t
619
+ else body()
620
+ case _ => body()
621
+
588
622
/* -------- REWRITES ----------------------------------------------------------- */
589
623
590
624
/** The last offset where a colon at the end of line would be required if a subsequent { ... }
591
- * block would be converted to an indentation region .
625
+ * block would be converted to an indentation reg`ion .
592
626
*/
593
627
var possibleColonOffset : Int = - 1
594
628
@@ -1606,13 +1640,6 @@ object Parsers {
1606
1640
1607
1641
/* ----------- EXPRESSIONS ------------------------------------------------ */
1608
1642
1609
- /** EqualsExpr ::= `=' Expr
1610
- */
1611
- def equalsExpr (): Tree = {
1612
- accept(EQUALS )
1613
- expr()
1614
- }
1615
-
1616
1643
def condExpr (altToken : Token ): Tree =
1617
1644
if (in.token == LPAREN ) {
1618
1645
var t : Tree = atSpan(in.offset) { Parens (inParens(exprInParens())) }
@@ -1676,7 +1703,9 @@ object Parsers {
1676
1703
*/
1677
1704
val exprInParens : () => Tree = () => expr(Location .InParens )
1678
1705
1679
- def expr (): Tree = expr(Location .ElseWhere )
1706
+ val expr : () => Tree = () => expr(Location .ElseWhere )
1707
+
1708
+ def subExpr () = subPart(expr)
1680
1709
1681
1710
def expr (location : Location .Value ): Tree = {
1682
1711
val start = in.offset
@@ -1714,7 +1743,7 @@ object Parsers {
1714
1743
atSpan(in.skipToken()) {
1715
1744
val cond = condExpr(DO )
1716
1745
newLinesOpt()
1717
- val body = expr ()
1746
+ val body = subExpr ()
1718
1747
WhileDo (cond, body)
1719
1748
}
1720
1749
}
@@ -1753,7 +1782,7 @@ object Parsers {
1753
1782
if (in.token == CATCH ) {
1754
1783
val span = in.offset
1755
1784
in.nextToken()
1756
- (expr (), span)
1785
+ (subExpr (), span)
1757
1786
}
1758
1787
else (EmptyTree , - 1 )
1759
1788
@@ -1768,7 +1797,7 @@ object Parsers {
1768
1797
}
1769
1798
1770
1799
val finalizer =
1771
- if (in.token == FINALLY ) { in.nextToken(); expr () }
1800
+ if (in.token == FINALLY ) { in.nextToken(); subExpr () }
1772
1801
else {
1773
1802
if (handler.isEmpty) warning(
1774
1803
EmptyCatchAndFinallyBlock (body),
@@ -1823,7 +1852,7 @@ object Parsers {
1823
1852
case EQUALS =>
1824
1853
t match {
1825
1854
case Ident (_) | Select (_, _) | Apply (_, _) =>
1826
- atSpan(startOffset(t), in.skipToken()) { Assign (t, expr ()) }
1855
+ atSpan(startOffset(t), in.skipToken()) { Assign (t, subExpr ()) }
1827
1856
case _ =>
1828
1857
t
1829
1858
}
@@ -1870,8 +1899,8 @@ object Parsers {
1870
1899
atSpan(start, in.skipToken()) {
1871
1900
val cond = condExpr(THEN )
1872
1901
newLinesOpt()
1873
- val thenp = expr ()
1874
- val elsep = if (in.token == ELSE ) { in.nextToken(); expr () }
1902
+ val thenp = subExpr ()
1903
+ val elsep = if (in.token == ELSE ) { in.nextToken(); subExpr () }
1875
1904
else EmptyTree
1876
1905
mkIf(cond, thenp, elsep)
1877
1906
}
@@ -2224,7 +2253,7 @@ object Parsers {
2224
2253
else if (in.token == CASE ) generator()
2225
2254
else {
2226
2255
val pat = pattern1()
2227
- if (in.token == EQUALS ) atSpan(startOffset(pat), in.skipToken()) { GenAlias (pat, expr ()) }
2256
+ if (in.token == EQUALS ) atSpan(startOffset(pat), in.skipToken()) { GenAlias (pat, subExpr ()) }
2228
2257
else generatorRest(pat, casePat = false )
2229
2258
}
2230
2259
@@ -2241,7 +2270,7 @@ object Parsers {
2241
2270
if (casePat) GenCheckMode .FilterAlways
2242
2271
else if (ctx.settings.strict.value) GenCheckMode .Check
2243
2272
else GenCheckMode .FilterNow // filter for now, to keep backwards compat
2244
- GenFrom (pat, expr (), checkMode)
2273
+ GenFrom (pat, subExpr (), checkMode)
2245
2274
}
2246
2275
2247
2276
/** ForExpr ::= `for' (`(' Enumerators `)' | `{' Enumerators `}')
@@ -2313,12 +2342,12 @@ object Parsers {
2313
2342
newLinesOpt()
2314
2343
if (in.token == YIELD ) {
2315
2344
in.nextToken()
2316
- ForYield (enums, expr ())
2345
+ ForYield (enums, subExpr ())
2317
2346
}
2318
2347
else if (in.token == DO ) {
2319
2348
if (rewriteToOldSyntax()) dropTerminator()
2320
2349
in.nextToken()
2321
- ForDo (enums, expr ())
2350
+ ForDo (enums, subExpr ())
2322
2351
}
2323
2352
else {
2324
2353
if (! wrappedEnums) syntaxErrorOrIncomplete(YieldOrDoExpectedInForComprehension ())
@@ -2758,7 +2787,7 @@ object Parsers {
2758
2787
syntaxError(VarValParametersMayNotBeCallByName (name, mods.is(Mutable )))
2759
2788
val tpt = paramType()
2760
2789
val default =
2761
- if (in.token == EQUALS ) { in.nextToken(); expr () }
2790
+ if (in.token == EQUALS ) { in.nextToken(); subExpr () }
2762
2791
else EmptyTree
2763
2792
if (impliedMods.mods.nonEmpty)
2764
2793
impliedMods = impliedMods.withMods(Nil ) // keep only flags, so that parameter positions don't overlap
@@ -3003,7 +3032,7 @@ object Parsers {
3003
3032
(lhs.toList forall (_.isInstanceOf [Ident ])))
3004
3033
wildcardIdent()
3005
3034
else
3006
- expr ()
3035
+ subExpr ()
3007
3036
}
3008
3037
else EmptyTree
3009
3038
lhs match {
@@ -3043,7 +3072,7 @@ object Parsers {
3043
3072
if (in.isScala2Mode) newLineOptWhenFollowedBy(LBRACE )
3044
3073
val rhs = {
3045
3074
if (! (in.token == LBRACE && scala2ProcedureSyntax(" " ))) accept(EQUALS )
3046
- atSpan(in.offset) { constrExpr( ) }
3075
+ atSpan(in.offset) { subPart(constrExpr ) }
3047
3076
}
3048
3077
makeConstructor(Nil , vparamss, rhs).withMods(mods).setComment(in.getDocComment(start))
3049
3078
}
@@ -3076,7 +3105,7 @@ object Parsers {
3076
3105
if (in.token == EQUALS )
3077
3106
indentRegion(name) {
3078
3107
in.nextToken()
3079
- expr ()
3108
+ subExpr ()
3080
3109
}
3081
3110
else if (! tpt.isEmpty)
3082
3111
EmptyTree
@@ -3100,7 +3129,7 @@ object Parsers {
3100
3129
/** ConstrExpr ::= SelfInvocation
3101
3130
* | `{' SelfInvocation {semi BlockStat} `}'
3102
3131
*/
3103
- def constrExpr () : Tree =
3132
+ val constrExpr : () => Tree = () =>
3104
3133
if (in.isNestedStart)
3105
3134
atSpan(in.offset) {
3106
3135
inBracesOrIndented {
@@ -3351,7 +3380,7 @@ object Parsers {
3351
3380
if in.token == EQUALS && parents.length == 1 && parents.head.isType then
3352
3381
in.nextToken()
3353
3382
mods1 |= Final
3354
- DefDef (name, tparams, vparamss, parents.head, expr ())
3383
+ DefDef (name, tparams, vparamss, parents.head, subExpr ())
3355
3384
else
3356
3385
// println(i"given $name $hasExtensionParams $hasGivenSig")
3357
3386
possibleTemplateStart()
0 commit comments