@@ -585,6 +585,50 @@ 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+ warning(
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+
622+ /** If indentation is not significant, check that this is not the start of a
623+ * statement that's indented relative to the current region.
624+ */
625+ def checkNextNotIndented (): Unit = in.currentRegion match
626+ case r : InBraces if in.token == NEWLINE || in.token == NEWLINES =>
627+ val nextIndentWidth = in.indentWidth(in.next.offset)
628+ if r.indentWidth < nextIndentWidth then
629+ warning(i " Line is indented too far to the right, or a `{' is missing " , in.next.offset)
630+ case _ =>
631+
588632/* -------- REWRITES ----------------------------------------------------------- */
589633
590634 /** The last offset where a colon at the end of line would be required if a subsequent { ... }
@@ -1606,13 +1650,6 @@ object Parsers {
16061650
16071651/* ----------- EXPRESSIONS ------------------------------------------------ */
16081652
1609- /** EqualsExpr ::= `=' Expr
1610- */
1611- def equalsExpr (): Tree = {
1612- accept(EQUALS )
1613- expr()
1614- }
1615-
16161653 def condExpr (altToken : Token ): Tree =
16171654 if (in.token == LPAREN ) {
16181655 var t : Tree = atSpan(in.offset) { Parens (inParens(exprInParens())) }
@@ -1676,7 +1713,9 @@ object Parsers {
16761713 */
16771714 val exprInParens : () => Tree = () => expr(Location .InParens )
16781715
1679- def expr (): Tree = expr(Location .ElseWhere )
1716+ val expr : () => Tree = () => expr(Location .ElseWhere )
1717+
1718+ def subExpr () = subPart(expr)
16801719
16811720 def expr (location : Location .Value ): Tree = {
16821721 val start = in.offset
@@ -1714,7 +1753,7 @@ object Parsers {
17141753 atSpan(in.skipToken()) {
17151754 val cond = condExpr(DO )
17161755 newLinesOpt()
1717- val body = expr ()
1756+ val body = subExpr ()
17181757 WhileDo (cond, body)
17191758 }
17201759 }
@@ -1753,7 +1792,7 @@ object Parsers {
17531792 if (in.token == CATCH ) {
17541793 val span = in.offset
17551794 in.nextToken()
1756- (expr (), span)
1795+ (subExpr (), span)
17571796 }
17581797 else (EmptyTree , - 1 )
17591798
@@ -1768,7 +1807,7 @@ object Parsers {
17681807 }
17691808
17701809 val finalizer =
1771- if (in.token == FINALLY ) { in.nextToken(); expr () }
1810+ if (in.token == FINALLY ) { in.nextToken(); subExpr () }
17721811 else {
17731812 if (handler.isEmpty) warning(
17741813 EmptyCatchAndFinallyBlock (body),
@@ -1823,7 +1862,7 @@ object Parsers {
18231862 case EQUALS =>
18241863 t match {
18251864 case Ident (_) | Select (_, _) | Apply (_, _) =>
1826- atSpan(startOffset(t), in.skipToken()) { Assign (t, expr ()) }
1865+ atSpan(startOffset(t), in.skipToken()) { Assign (t, subExpr ()) }
18271866 case _ =>
18281867 t
18291868 }
@@ -1870,8 +1909,8 @@ object Parsers {
18701909 atSpan(start, in.skipToken()) {
18711910 val cond = condExpr(THEN )
18721911 newLinesOpt()
1873- val thenp = expr ()
1874- val elsep = if (in.token == ELSE ) { in.nextToken(); expr () }
1912+ val thenp = subExpr ()
1913+ val elsep = if (in.token == ELSE ) { in.nextToken(); subExpr () }
18751914 else EmptyTree
18761915 mkIf(cond, thenp, elsep)
18771916 }
@@ -2224,7 +2263,7 @@ object Parsers {
22242263 else if (in.token == CASE ) generator()
22252264 else {
22262265 val pat = pattern1()
2227- if (in.token == EQUALS ) atSpan(startOffset(pat), in.skipToken()) { GenAlias (pat, expr ()) }
2266+ if (in.token == EQUALS ) atSpan(startOffset(pat), in.skipToken()) { GenAlias (pat, subExpr ()) }
22282267 else generatorRest(pat, casePat = false )
22292268 }
22302269
@@ -2241,7 +2280,7 @@ object Parsers {
22412280 if (casePat) GenCheckMode .FilterAlways
22422281 else if (ctx.settings.strict.value) GenCheckMode .Check
22432282 else GenCheckMode .FilterNow // filter for now, to keep backwards compat
2244- GenFrom (pat, expr (), checkMode)
2283+ GenFrom (pat, subExpr (), checkMode)
22452284 }
22462285
22472286 /** ForExpr ::= `for' (`(' Enumerators `)' | `{' Enumerators `}')
@@ -2313,12 +2352,12 @@ object Parsers {
23132352 newLinesOpt()
23142353 if (in.token == YIELD ) {
23152354 in.nextToken()
2316- ForYield (enums, expr ())
2355+ ForYield (enums, subExpr ())
23172356 }
23182357 else if (in.token == DO ) {
23192358 if (rewriteToOldSyntax()) dropTerminator()
23202359 in.nextToken()
2321- ForDo (enums, expr ())
2360+ ForDo (enums, subExpr ())
23222361 }
23232362 else {
23242363 if (! wrappedEnums) syntaxErrorOrIncomplete(YieldOrDoExpectedInForComprehension ())
@@ -2758,7 +2797,7 @@ object Parsers {
27582797 syntaxError(VarValParametersMayNotBeCallByName (name, mods.is(Mutable )))
27592798 val tpt = paramType()
27602799 val default =
2761- if (in.token == EQUALS ) { in.nextToken(); expr () }
2800+ if (in.token == EQUALS ) { in.nextToken(); subExpr () }
27622801 else EmptyTree
27632802 if (impliedMods.mods.nonEmpty)
27642803 impliedMods = impliedMods.withMods(Nil ) // keep only flags, so that parameter positions don't overlap
@@ -3003,7 +3042,7 @@ object Parsers {
30033042 (lhs.toList forall (_.isInstanceOf [Ident ])))
30043043 wildcardIdent()
30053044 else
3006- expr ()
3045+ subExpr ()
30073046 }
30083047 else EmptyTree
30093048 lhs match {
@@ -3043,7 +3082,7 @@ object Parsers {
30433082 if (in.isScala2Mode) newLineOptWhenFollowedBy(LBRACE )
30443083 val rhs = {
30453084 if (! (in.token == LBRACE && scala2ProcedureSyntax(" " ))) accept(EQUALS )
3046- atSpan(in.offset) { constrExpr( ) }
3085+ atSpan(in.offset) { subPart(constrExpr ) }
30473086 }
30483087 makeConstructor(Nil , vparamss, rhs).withMods(mods).setComment(in.getDocComment(start))
30493088 }
@@ -3076,7 +3115,7 @@ object Parsers {
30763115 if (in.token == EQUALS )
30773116 indentRegion(name) {
30783117 in.nextToken()
3079- expr ()
3118+ subExpr ()
30803119 }
30813120 else if (! tpt.isEmpty)
30823121 EmptyTree
@@ -3100,7 +3139,7 @@ object Parsers {
31003139 /** ConstrExpr ::= SelfInvocation
31013140 * | `{' SelfInvocation {semi BlockStat} `}'
31023141 */
3103- def constrExpr () : Tree =
3142+ val constrExpr : () => Tree = () =>
31043143 if (in.isNestedStart)
31053144 atSpan(in.offset) {
31063145 inBracesOrIndented {
@@ -3351,7 +3390,7 @@ object Parsers {
33513390 if in.token == EQUALS && parents.length == 1 && parents.head.isType then
33523391 in.nextToken()
33533392 mods1 |= Final
3354- DefDef (name, tparams, vparamss, parents.head, expr ())
3393+ DefDef (name, tparams, vparamss, parents.head, subExpr ())
33553394 else
33563395 // println(i"given $name $hasExtensionParams $hasGivenSig")
33573396 possibleTemplateStart()
@@ -3431,22 +3470,27 @@ object Parsers {
34313470
34323471 /** TemplateOpt = [Template]
34333472 */
3434- def templateOpt (constr : DefDef ): Template = {
3473+ def templateOpt (constr : DefDef ): Template =
34353474 possibleTemplateStart()
3436- if ( in.token == EXTENDS || isIdent(nme.derives ))
3475+ if in.token == EXTENDS || isIdent(nme.derives ) then
34373476 template(constr)
34383477 else
3439- if (in.isNestedStart) template(constr)
3440- else Template (constr, Nil , Nil , EmptyValDef , Nil )
3441- }
3478+ if in.isNestedStart then
3479+ template(constr)
3480+ else
3481+ checkNextNotIndented()
3482+ Template (constr, Nil , Nil , EmptyValDef , Nil )
34423483
34433484 /** TemplateBody ::= [nl] `{' TemplateStatSeq `}'
34443485 */
3445- def templateBodyOpt (constr : DefDef , parents : List [Tree ], derived : List [Tree ]): Template = {
3486+ def templateBodyOpt (constr : DefDef , parents : List [Tree ], derived : List [Tree ]): Template =
34463487 val (self, stats) =
3447- if (in.isNestedStart) templateBody() else (EmptyValDef , Nil )
3488+ if in.isNestedStart then
3489+ templateBody()
3490+ else
3491+ checkNextNotIndented()
3492+ (EmptyValDef , Nil )
34483493 Template (constr, parents, derived, self, stats)
3449- }
34503494
34513495 def templateBody (): (ValDef , List [Tree ]) = {
34523496 val r = inDefScopeBraces { templateStatSeq() }
0 commit comments