@@ -26,6 +26,7 @@ import Decorators._
2626import scala .internal .Chars
2727import scala .annotation .{tailrec , switch }
2828import rewrites .Rewrites .{patch , overlapsPatch }
29+ import config .Config .silentTemplateIdent
2930
3031object Parsers {
3132
@@ -616,6 +617,7 @@ object Parsers {
616617
617618 /** If indentation is not significant, check that this is not the start of a
618619 * statement that's indented relative to the current region.
620+ * TODO: Drop if `with` is required before indented template definitions.
619621 */
620622 def checkNextNotIndented (): Unit = in.currentRegion match
621623 case r : IndentSignificantRegion if in.isNewLine =>
@@ -1249,10 +1251,14 @@ object Parsers {
12491251 newLineOptWhenFollowedBy(LBRACE )
12501252 }
12511253
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()
12541261 newLineOptWhenFollowedBy(LBRACE )
1255- }
12561262
12571263 def indentRegion [T ](tag : EndMarkerTag )(op : => T ): T = {
12581264 val iw = in.currentRegion.indentWidth
@@ -2125,25 +2131,20 @@ object Parsers {
21252131 }
21262132 }
21272133
2128- /** SimpleExpr ::= ‘new’ (ConstrApp {`with` ConstrApp} [TemplateBody] | TemplateBody)
2134+ /** SimpleExpr ::= ‘new’ ConstrApp {`with` ConstrApp} [TemplateBody]
2135+ * | ‘new’ TemplateBody
21292136 */
21302137 def newExpr (): Tree =
21312138 indentRegion(NEW ) {
21322139 val start = in.skipToken()
21332140 def reposition (t : Tree ) = t.withSpan(Span (start, in.lastOffset))
21342141 possibleBracesStart()
21352142 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 )
21472148 possibleBracesStart()
21482149 parents match {
21492150 case parent :: Nil if ! in.isNestedStart =>
@@ -3325,7 +3326,7 @@ object Parsers {
33253326 val parents =
33263327 if (in.token == EXTENDS ) {
33273328 in.nextToken()
3328- tokenSeparated( WITH , constrApp )
3329+ constrApps(commaOK = true , templateCanFollow = false )
33293330 }
33303331 else Nil
33313332 Template (constr, parents, Nil , EmptyValDef , Nil )
@@ -3375,6 +3376,7 @@ object Parsers {
33753376 if in.token == COLON then
33763377 in.nextToken()
33773378 if in.token == LBRACE
3379+ || in.token == WITH
33783380 || in.token == LBRACKET
33793381 || in.token == LPAREN && followingIsParamOrGivenType()
33803382 then
@@ -3387,7 +3389,7 @@ object Parsers {
33873389 syntaxError(" `<:' is only allowed for given with `inline' modifier" )
33883390 in.nextToken()
33893391 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
33913393 tokenSeparated(COMMA , constrApp)
33923394 else Nil
33933395
@@ -3423,23 +3425,29 @@ object Parsers {
34233425 if in.token == LPAREN then parArgumentExprss(wrapNew(t)) else t
34243426 }
34253427
3426- /** ConstrApps ::= ConstrApp {‘with’ ConstrApp} (to be deprecated in 3.1)
3427- * | ConstrApp {‘,’ ConstrApp}
3428+ /** ConstrApps ::= ConstrApp {(‘,’ | ‘with’) ConstrApp}
34283429 */
3429- def constrApps (): List [Tree ] = {
3430+ def constrApps (commaOK : Boolean , templateCanFollow : Boolean ): List [Tree ] =
34303431 val t = constrApp()
34313432 val ts =
3432- if ( in.token == WITH ) {
3433+ if in.token == WITH then
34333434 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
34373447 in.nextToken()
3438- tokenSeparated(COMMA , constrApp)
3439- }
3448+ constrApps(commaOK, templateCanFollow)
34403449 else Nil
34413450 t :: ts
3442- }
34433451
34443452 /** InheritClauses ::= [‘extends’ ConstrApps] [‘derives’ QualId {‘,’ QualId}]
34453453 */
@@ -3451,7 +3459,7 @@ object Parsers {
34513459 in.errorOrMigrationWarning(" `extends' must be followed by at least one parent" )
34523460 Nil
34533461 }
3454- else constrApps()
3462+ else constrApps(commaOK = true , templateCanFollow = true )
34553463 }
34563464 else Nil
34573465 val derived =
@@ -3490,7 +3498,8 @@ object Parsers {
34903498 checkNextNotIndented()
34913499 Template (constr, Nil , Nil , EmptyValDef , Nil )
34923500
3493- /** TemplateBody ::= [nl] `{' TemplateStatSeq `}'
3501+ /** TemplateBody ::= [nl | `with'] `{' TemplateStatSeq `}'
3502+ * EnumBody ::= [nl | ‘with’] ‘{’ [SelfType] EnumStat {semi EnumStat} ‘}’
34943503 */
34953504 def templateBodyOpt (constr : DefDef , parents : List [Tree ], derived : List [Tree ]): Template =
34963505 val (self, stats) =
@@ -3518,7 +3527,7 @@ object Parsers {
35183527 case x : RefTree => atSpan(start, pointOffset(pkg))(PackageDef (x, stats))
35193528 }
35203529
3521- /** Packaging ::= package QualId [nl] `{' TopStatSeq `}'
3530+ /** Packaging ::= package QualId [nl | `with' ] `{' TopStatSeq `}'
35223531 */
35233532 def packaging (start : Int ): Tree = {
35243533 val pkg = qualId()
0 commit comments