@@ -585,10 +585,44 @@ object Parsers {
585585 try op finally in.adjustSepRegions(closing)
586586 }
587587
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+
588622/* -------- REWRITES ----------------------------------------------------------- */
589623
590624 /** 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 .
592626 */
593627 var possibleColonOffset : Int = - 1
594628
@@ -1606,13 +1640,6 @@ object Parsers {
16061640
16071641/* ----------- EXPRESSIONS ------------------------------------------------ */
16081642
1609- /** EqualsExpr ::= `=' Expr
1610- */
1611- def equalsExpr (): Tree = {
1612- accept(EQUALS )
1613- expr()
1614- }
1615-
16161643 def condExpr (altToken : Token ): Tree =
16171644 if (in.token == LPAREN ) {
16181645 var t : Tree = atSpan(in.offset) { Parens (inParens(exprInParens())) }
@@ -1676,7 +1703,9 @@ object Parsers {
16761703 */
16771704 val exprInParens : () => Tree = () => expr(Location .InParens )
16781705
1679- def expr (): Tree = expr(Location .ElseWhere )
1706+ val expr : () => Tree = () => expr(Location .ElseWhere )
1707+
1708+ def subExpr () = subPart(expr)
16801709
16811710 def expr (location : Location .Value ): Tree = {
16821711 val start = in.offset
@@ -1714,7 +1743,7 @@ object Parsers {
17141743 atSpan(in.skipToken()) {
17151744 val cond = condExpr(DO )
17161745 newLinesOpt()
1717- val body = expr ()
1746+ val body = subExpr ()
17181747 WhileDo (cond, body)
17191748 }
17201749 }
@@ -1753,7 +1782,7 @@ object Parsers {
17531782 if (in.token == CATCH ) {
17541783 val span = in.offset
17551784 in.nextToken()
1756- (expr (), span)
1785+ (subExpr (), span)
17571786 }
17581787 else (EmptyTree , - 1 )
17591788
@@ -1768,7 +1797,7 @@ object Parsers {
17681797 }
17691798
17701799 val finalizer =
1771- if (in.token == FINALLY ) { in.nextToken(); expr () }
1800+ if (in.token == FINALLY ) { in.nextToken(); subExpr () }
17721801 else {
17731802 if (handler.isEmpty) warning(
17741803 EmptyCatchAndFinallyBlock (body),
@@ -1823,7 +1852,7 @@ object Parsers {
18231852 case EQUALS =>
18241853 t match {
18251854 case Ident (_) | Select (_, _) | Apply (_, _) =>
1826- atSpan(startOffset(t), in.skipToken()) { Assign (t, expr ()) }
1855+ atSpan(startOffset(t), in.skipToken()) { Assign (t, subExpr ()) }
18271856 case _ =>
18281857 t
18291858 }
@@ -1870,8 +1899,8 @@ object Parsers {
18701899 atSpan(start, in.skipToken()) {
18711900 val cond = condExpr(THEN )
18721901 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 () }
18751904 else EmptyTree
18761905 mkIf(cond, thenp, elsep)
18771906 }
@@ -2224,7 +2253,7 @@ object Parsers {
22242253 else if (in.token == CASE ) generator()
22252254 else {
22262255 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 ()) }
22282257 else generatorRest(pat, casePat = false )
22292258 }
22302259
@@ -2241,7 +2270,7 @@ object Parsers {
22412270 if (casePat) GenCheckMode .FilterAlways
22422271 else if (ctx.settings.strict.value) GenCheckMode .Check
22432272 else GenCheckMode .FilterNow // filter for now, to keep backwards compat
2244- GenFrom (pat, expr (), checkMode)
2273+ GenFrom (pat, subExpr (), checkMode)
22452274 }
22462275
22472276 /** ForExpr ::= `for' (`(' Enumerators `)' | `{' Enumerators `}')
@@ -2313,12 +2342,12 @@ object Parsers {
23132342 newLinesOpt()
23142343 if (in.token == YIELD ) {
23152344 in.nextToken()
2316- ForYield (enums, expr ())
2345+ ForYield (enums, subExpr ())
23172346 }
23182347 else if (in.token == DO ) {
23192348 if (rewriteToOldSyntax()) dropTerminator()
23202349 in.nextToken()
2321- ForDo (enums, expr ())
2350+ ForDo (enums, subExpr ())
23222351 }
23232352 else {
23242353 if (! wrappedEnums) syntaxErrorOrIncomplete(YieldOrDoExpectedInForComprehension ())
@@ -2758,7 +2787,7 @@ object Parsers {
27582787 syntaxError(VarValParametersMayNotBeCallByName (name, mods.is(Mutable )))
27592788 val tpt = paramType()
27602789 val default =
2761- if (in.token == EQUALS ) { in.nextToken(); expr () }
2790+ if (in.token == EQUALS ) { in.nextToken(); subExpr () }
27622791 else EmptyTree
27632792 if (impliedMods.mods.nonEmpty)
27642793 impliedMods = impliedMods.withMods(Nil ) // keep only flags, so that parameter positions don't overlap
@@ -3003,7 +3032,7 @@ object Parsers {
30033032 (lhs.toList forall (_.isInstanceOf [Ident ])))
30043033 wildcardIdent()
30053034 else
3006- expr ()
3035+ subExpr ()
30073036 }
30083037 else EmptyTree
30093038 lhs match {
@@ -3043,7 +3072,7 @@ object Parsers {
30433072 if (in.isScala2Mode) newLineOptWhenFollowedBy(LBRACE )
30443073 val rhs = {
30453074 if (! (in.token == LBRACE && scala2ProcedureSyntax(" " ))) accept(EQUALS )
3046- atSpan(in.offset) { constrExpr( ) }
3075+ atSpan(in.offset) { subPart(constrExpr ) }
30473076 }
30483077 makeConstructor(Nil , vparamss, rhs).withMods(mods).setComment(in.getDocComment(start))
30493078 }
@@ -3076,7 +3105,7 @@ object Parsers {
30763105 if (in.token == EQUALS )
30773106 indentRegion(name) {
30783107 in.nextToken()
3079- expr ()
3108+ subExpr ()
30803109 }
30813110 else if (! tpt.isEmpty)
30823111 EmptyTree
@@ -3100,7 +3129,7 @@ object Parsers {
31003129 /** ConstrExpr ::= SelfInvocation
31013130 * | `{' SelfInvocation {semi BlockStat} `}'
31023131 */
3103- def constrExpr () : Tree =
3132+ val constrExpr : () => Tree = () =>
31043133 if (in.isNestedStart)
31053134 atSpan(in.offset) {
31063135 inBracesOrIndented {
@@ -3351,7 +3380,7 @@ object Parsers {
33513380 if in.token == EQUALS && parents.length == 1 && parents.head.isType then
33523381 in.nextToken()
33533382 mods1 |= Final
3354- DefDef (name, tparams, vparamss, parents.head, expr ())
3383+ DefDef (name, tparams, vparamss, parents.head, subExpr ())
33553384 else
33563385 // println(i"given $name $hasExtensionParams $hasGivenSig")
33573386 possibleTemplateStart()
0 commit comments