@@ -26,6 +26,7 @@ import Decorators._
26
26
import scala .internal .Chars
27
27
import scala .annotation .{tailrec , switch }
28
28
import rewrites .Rewrites .{patch , overlapsPatch }
29
+ import config .Config .silentTemplateIdent
29
30
30
31
object Parsers {
31
32
@@ -616,6 +617,7 @@ object Parsers {
616
617
617
618
/** If indentation is not significant, check that this is not the start of a
618
619
* statement that's indented relative to the current region.
620
+ * TODO: Drop if `with` is required before indented template definitions.
619
621
*/
620
622
def checkNextNotIndented (): Unit = in.currentRegion match
621
623
case r : IndentSignificantRegion if in.isNewLine =>
@@ -1249,10 +1251,14 @@ object Parsers {
1249
1251
newLineOptWhenFollowedBy(LBRACE )
1250
1252
}
1251
1253
1252
- def possibleTemplateStart (): Unit = {
1253
- in.observeIndented()
1254
+ def possibleTemplateStart (): Unit =
1255
+ if in.token == WITH then
1256
+ in.nextToken()
1257
+ if in.token != LBRACE && in.token != INDENT then
1258
+ syntaxError(i " indented definitions or `{' expected " )
1259
+ else if silentTemplateIdent then
1260
+ in.observeIndented()
1254
1261
newLineOptWhenFollowedBy(LBRACE )
1255
- }
1256
1262
1257
1263
def indentRegion [T ](tag : EndMarkerTag )(op : => T ): T = {
1258
1264
val iw = in.currentRegion.indentWidth
@@ -2125,25 +2131,20 @@ object Parsers {
2125
2131
}
2126
2132
}
2127
2133
2128
- /** SimpleExpr ::= ‘new’ (ConstrApp {`with` ConstrApp} [TemplateBody] | TemplateBody)
2134
+ /** SimpleExpr ::= ‘new’ ConstrApp {`with` ConstrApp} [TemplateBody]
2135
+ * | ‘new’ TemplateBody
2129
2136
*/
2130
2137
def newExpr (): Tree =
2131
2138
indentRegion(NEW ) {
2132
2139
val start = in.skipToken()
2133
2140
def reposition (t : Tree ) = t.withSpan(Span (start, in.lastOffset))
2134
2141
possibleBracesStart()
2135
2142
val parents =
2136
- if (in.isNestedStart) Nil
2137
- else constrApp() :: {
2138
- if (in.token == WITH ) {
2139
- // Enable this for 3.1, when we drop `with` for inheritance:
2140
- // in.errorUnlessInScala2Mode(
2141
- // "anonymous class with multiple parents is no longer supported; use a named class instead")
2142
- in.nextToken()
2143
- tokenSeparated(WITH , constrApp)
2144
- }
2145
- else Nil
2146
- }
2143
+ if in.token == WITH then
2144
+ possibleTemplateStart()
2145
+ Nil
2146
+ else if in.token == LBRACE then Nil
2147
+ else constrApps(commaOK = false , templateCanFollow = true )
2147
2148
possibleBracesStart()
2148
2149
parents match {
2149
2150
case parent :: Nil if ! in.isNestedStart =>
@@ -3325,7 +3326,7 @@ object Parsers {
3325
3326
val parents =
3326
3327
if (in.token == EXTENDS ) {
3327
3328
in.nextToken()
3328
- tokenSeparated( WITH , constrApp )
3329
+ constrApps(commaOK = true , templateCanFollow = false )
3329
3330
}
3330
3331
else Nil
3331
3332
Template (constr, parents, Nil , EmptyValDef , Nil )
@@ -3375,6 +3376,7 @@ object Parsers {
3375
3376
if in.token == COLON then
3376
3377
in.nextToken()
3377
3378
if in.token == LBRACE
3379
+ || in.token == WITH
3378
3380
|| in.token == LBRACKET
3379
3381
|| in.token == LPAREN && followingIsParamOrGivenType()
3380
3382
then
@@ -3387,7 +3389,7 @@ object Parsers {
3387
3389
syntaxError(" `<:' is only allowed for given with `inline' modifier" )
3388
3390
in.nextToken()
3389
3391
TypeBoundsTree (EmptyTree , toplevelTyp()) :: Nil
3390
- else if name.isEmpty && in.token != LBRACE then
3392
+ else if name.isEmpty && in.token != LBRACE && in.token != WITH then
3391
3393
tokenSeparated(COMMA , constrApp)
3392
3394
else Nil
3393
3395
@@ -3423,23 +3425,29 @@ object Parsers {
3423
3425
if in.token == LPAREN then parArgumentExprss(wrapNew(t)) else t
3424
3426
}
3425
3427
3426
- /** ConstrApps ::= ConstrApp {‘with’ ConstrApp} (to be deprecated in 3.1)
3427
- * | ConstrApp {‘,’ ConstrApp}
3428
+ /** ConstrApps ::= ConstrApp {(‘,’ | ‘with’) ConstrApp}
3428
3429
*/
3429
- def constrApps (): List [Tree ] = {
3430
+ def constrApps (commaOK : Boolean , templateCanFollow : Boolean ): List [Tree ] =
3430
3431
val t = constrApp()
3431
3432
val ts =
3432
- if ( in.token == WITH ) {
3433
+ if in.token == WITH then
3433
3434
in.nextToken()
3434
- tokenSeparated(WITH , constrApp)
3435
- }
3436
- else if (in.token == COMMA ) {
3435
+ if templateCanFollow && (in.token == LBRACE || in.token == INDENT ) then Nil
3436
+ else
3437
+ if (in.isScala2Mode || in.oldSyntax) && in.isAfterLineEnd then
3438
+ // Disallow
3439
+ //
3440
+ // extends p1 with
3441
+ // p2
3442
+ //
3443
+ // since that means something else under significant indentation
3444
+ in.errorOrMigrationWarning(" `with` cannot be followed by new line, place at beginning of next line instead" )
3445
+ constrApps(commaOK, templateCanFollow)
3446
+ else if commaOK && in.token == COMMA then
3437
3447
in.nextToken()
3438
- tokenSeparated(COMMA , constrApp)
3439
- }
3448
+ constrApps(commaOK, templateCanFollow)
3440
3449
else Nil
3441
3450
t :: ts
3442
- }
3443
3451
3444
3452
/** InheritClauses ::= [‘extends’ ConstrApps] [‘derives’ QualId {‘,’ QualId}]
3445
3453
*/
@@ -3451,7 +3459,7 @@ object Parsers {
3451
3459
in.errorOrMigrationWarning(" `extends' must be followed by at least one parent" )
3452
3460
Nil
3453
3461
}
3454
- else constrApps()
3462
+ else constrApps(commaOK = true , templateCanFollow = true )
3455
3463
}
3456
3464
else Nil
3457
3465
val derived =
@@ -3490,7 +3498,8 @@ object Parsers {
3490
3498
checkNextNotIndented()
3491
3499
Template (constr, Nil , Nil , EmptyValDef , Nil )
3492
3500
3493
- /** TemplateBody ::= [nl] `{' TemplateStatSeq `}'
3501
+ /** TemplateBody ::= [nl | `with'] `{' TemplateStatSeq `}'
3502
+ * EnumBody ::= [nl | ‘with’] ‘{’ [SelfType] EnumStat {semi EnumStat} ‘}’
3494
3503
*/
3495
3504
def templateBodyOpt (constr : DefDef , parents : List [Tree ], derived : List [Tree ]): Template =
3496
3505
val (self, stats) =
@@ -3518,7 +3527,7 @@ object Parsers {
3518
3527
case x : RefTree => atSpan(start, pointOffset(pkg))(PackageDef (x, stats))
3519
3528
}
3520
3529
3521
- /** Packaging ::= package QualId [nl] `{' TopStatSeq `}'
3530
+ /** Packaging ::= package QualId [nl | `with' ] `{' TopStatSeq `}'
3522
3531
*/
3523
3532
def packaging (start : Int ): Tree = {
3524
3533
val pkg = qualId()
0 commit comments