diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 70541b54857b..2436db28a1ec 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1392,7 +1392,7 @@ object Parsers { } else simpleExpr() - /** SimpleExpr ::= new Template + /** SimpleExpr ::= ‘new’ (ConstrApp [TemplateBody] | TemplateBody) * | BlockExpr * | ‘'{’ BlockExprContents ‘}’ * | ‘'(’ ExprsInParens ‘)’ @@ -1436,15 +1436,7 @@ object Parsers { atPos(in.offset)(Quote(inBrackets(typ()))) case NEW => canApply = false - val start = in.skipToken() - val (impl, missingBody) = template(emptyConstructor) - impl.parents match { - case parent :: Nil if missingBody => - if (parent.isType) ensureApplied(wrapNew(parent)) - else parent.withPos(Position(start, in.lastOffset)) - case _ => - New(impl.withPos(Position(start, in.lastOffset))) - } + newExpr() case _ => if (isLiteral) literal() else { @@ -1474,6 +1466,33 @@ object Parsers { } } + /** SimpleExpr ::= ‘new’ (ConstrApp {`with` ConstrApp} [TemplateBody] | TemplateBody) + */ + def newExpr(): Tree = { + val start = in.skipToken() + def reposition(t: Tree) = t.withPos(Position(start, in.lastOffset)) + newLineOptWhenFollowedBy(LBRACE) + val parents = + if (in.token == LBRACE) Nil + else constrApp() :: { + if (in.token == WITH) { + // Enable this for 3.1, when we drop `with` for inheritance: + // in.errorUnlessInScala2Mode( + // "anonymous class with multiple parents is no longer supported; use a named class instead") + in.nextToken() + tokenSeparated(WITH, constrApp) + } + else Nil + } + newLineOptWhenFollowedBy(LBRACE) + parents match { + case parent :: Nil if in.token != LBRACE => + reposition(if (parent.isType) ensureApplied(wrapNew(parent)) else parent) + case _ => + New(reposition(templateBodyOpt(emptyConstructor, parents, isEnum = false))) + } + } + /** ExprsInParens ::= ExprInParens {`,' ExprInParens} */ def exprsInParensOpt(): List[Tree] = @@ -2381,18 +2400,18 @@ object Parsers { } def objectDefRest(start: Offset, mods: Modifiers, name: TermName): ModuleDef = { - val template = templateOpt(emptyConstructor) - ModuleDef(name, template).withMods(mods).setComment(in.getDocComment(start)) + val templ = templateOpt(emptyConstructor) + ModuleDef(name, templ).withMods(mods).setComment(in.getDocComment(start)) } - /** EnumDef ::= id ClassConstr [`extends' [ConstrApps]] EnumBody + /** EnumDef ::= id ClassConstr [`extends' ConstrApps] EnumBody */ def enumDef(start: Offset, mods: Modifiers, enumMod: Mod): TypeDef = atPos(start, nameStart) { val modName = ident() val clsName = modName.toTypeName val constr = classConstr(clsName) - val impl = templateOpt(constr, isEnum = true) - TypeDef(clsName, impl).withMods(addMod(mods, enumMod)).setComment(in.getDocComment(start)) + val templ = templateOpt(constr, isEnum = true) + TypeDef(clsName, templ).withMods(addMod(mods, enumMod)).setComment(in.getDocComment(start)) } /** EnumCase = `case' (id ClassConstr [`extends' ConstrApps] | ids) @@ -2448,34 +2467,48 @@ object Parsers { else t } - /** Template ::= ConstrApps [TemplateBody] | TemplateBody - * ConstrApps ::= ConstrApp {`with' ConstrApp} - * - * @return a pair consisting of the template, and a boolean which indicates - * whether the template misses a body (i.e. no {...} part). + /** ConstrApps ::= ConstrApp {‘with’ ConstrApp} (to be deprecated in 3.1) + * | ConstrApp {‘,’ ConstrApp} */ - def template(constr: DefDef, isEnum: Boolean = false): (Template, Boolean) = { + def constrApps(): List[Tree] = { + val t = constrApp() + val ts = + if (in.token == WITH) { + in.nextToken() + tokenSeparated(WITH, constrApp) + } + else if (in.token == COMMA) { + in.nextToken() + tokenSeparated(COMMA, constrApp) + } + else Nil + t :: ts + } + + /** Template ::= [‘extends’ ConstrApps] [TemplateBody] + */ + def template(constr: DefDef, isEnum: Boolean = false): Template = { + val parents = + if (in.token == EXTENDS) { + in.nextToken() + constrApps() + } + else Nil newLineOptWhenFollowedBy(LBRACE) - if (in.token == LBRACE) (templateBodyOpt(constr, Nil, isEnum), false) - else { - val parents = tokenSeparated(WITH, constrApp) - newLineOptWhenFollowedBy(LBRACE) - if (isEnum && in.token != LBRACE) - syntaxErrorOrIncomplete(ExpectedTokenButFound(LBRACE, in.token)) - val missingBody = in.token != LBRACE - (templateBodyOpt(constr, parents, isEnum), missingBody) - } + if (isEnum && in.token != LBRACE) + syntaxErrorOrIncomplete(ExpectedTokenButFound(LBRACE, in.token)) + templateBodyOpt(constr, parents, isEnum) } - /** TemplateOpt = [`extends' Template | TemplateBody] + /** TemplateOpt = [Template] */ - def templateOpt(constr: DefDef, isEnum: Boolean = false): Template = - if (in.token == EXTENDS) { in.nextToken(); template(constr, isEnum)._1 } - else { - newLineOptWhenFollowedBy(LBRACE) - if (in.token == LBRACE) template(constr, isEnum)._1 - else Template(constr, Nil, EmptyValDef, Nil) - } + def templateOpt(constr: DefDef, isEnum: Boolean = false): Template = { + newLineOptWhenFollowedBy(LBRACE) + if (in.token == EXTENDS || in.token == LBRACE) + template(constr, isEnum) + else + Template(constr, Nil, EmptyValDef, Nil) + } /** TemplateBody ::= [nl] `{' TemplateStatSeq `}' */ diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index 193c4d74d977..eb74d736f2bb 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -250,6 +250,11 @@ object Scanners { isScala2Mode } + /** A migration warning if in Scala-2 mode, an error otherwise */ + def errorOrMigrationWarning(msg: String, pos: Position = Position(offset)): Unit = + if (isScala2Mode) ctx.migrationWarning(msg, source.atPos(pos)) + else ctx.error(msg, source.atPos(pos)) + // Get next token ------------------------------------------------------------ /** Are we directly in a string interpolation expression? diff --git a/docs/docs/internals/syntax.md b/docs/docs/internals/syntax.md index d83734dc0854..fa5205bfff50 100644 --- a/docs/docs/internals/syntax.md +++ b/docs/docs/internals/syntax.md @@ -186,7 +186,7 @@ PostfixExpr ::= InfixExpr [id] InfixExpr ::= PrefixExpr | InfixExpr id [nl] InfixExpr InfixOp(expr, op, expr) PrefixExpr ::= [‘-’ | ‘+’ | ‘~’ | ‘!’] SimpleExpr PrefixOp(expr, op) -SimpleExpr ::= ‘new’ Template New(templ) +SimpleExpr ::= ‘new’ (ConstrApp [TemplateBody] | TemplateBody) New(constr | templ) | BlockExpr | ''{’ BlockExprContents ‘}’ | ‘'(’ ExprsInParens ‘)’ @@ -340,14 +340,14 @@ DefDef ::= DefSig [(‘:’ | ‘<:’) Type] ‘=’ Expr TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef | [‘case’] ‘object’ ObjectDef | ‘enum’ EnumDef -ClassDef ::= id ClassConstr TemplateOpt ClassDef(mods, name, tparams, templ) -ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsParamClauses with DefDef(_, , Nil, vparamss, EmptyTree, EmptyTree) as first stat +ClassDef ::= id ClassConstr [Template] ClassDef(mods, name, tparams, templ) +ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsParamClauses with DefDef(_, , Nil, vparamss, EmptyTree, EmptyTree) as first stat ConstrMods ::= {Annotation} [AccessModifier] -ObjectDef ::= id TemplateOpt ModuleDef(mods, name, template) // no constructor -EnumDef ::= id ClassConstr [‘extends’ [ConstrApps]] EnumBody EnumDef(mods, name, tparams, template) -TemplateOpt ::= [‘extends’ Template | [nl] TemplateBody] +ObjectDef ::= id [Template] ModuleDef(mods, name, template) // no constructor +EnumDef ::= id ClassConstr [‘extends’ ConstrApps] EnumBody EnumDef(mods, name, tparams, template) Template ::= ConstrApps [TemplateBody] | TemplateBody Template(constr, parents, self, stats) ConstrApps ::= ConstrApp {‘with’ ConstrApp} + | ConstrApp {‘,’ ConstrApp} ConstrApp ::= AnnotType {ArgumentExprs} Apply(tp, args) ConstrExpr ::= SelfInvocation | ConstrBlock diff --git a/tests/invalid/neg/typelevel.scala b/tests/invalid/neg/typelevel.scala index 32d270b965a9..2dcebb19a41d 100644 --- a/tests/invalid/neg/typelevel.scala +++ b/tests/invalid/neg/typelevel.scala @@ -53,7 +53,7 @@ object Test { val rr1 = new Deco1(HCons(1, HNil)) ++ HNil val rr1a: HCons[Int, HNil.type] = rr1 // error (type error because no inline) - class Deco2(val as: HList) extends java.lang.Cloneable with java.lang.Comparable[Deco2] { + class Deco2(val as: HList) extends java.lang.Cloneable, java.lang.Comparable[Deco2] { inline def ++ (bs: HList) = concat(as, bs) } } \ No newline at end of file diff --git a/tests/neg/i2770.scala b/tests/neg/i2770.scala index 4e7c6cb0a8cd..8680f6c94318 100644 --- a/tests/neg/i2770.scala +++ b/tests/neg/i2770.scala @@ -8,7 +8,7 @@ trait C2 extends B2 { type L[X, Y] <: String } // error: illegal override trait D { type I } trait E extends D { type I <: String } trait F extends D { type I >: String } -trait G extends E with F // ok +trait G extends E, F // ok trait H extends D { type I >: Int } -trait H2 extends E with H // error: illegal override +trait H2 extends E, H // error: illegal override diff --git a/tests/pos/Iter2.scala b/tests/pos/Iter2.scala index b9dc5d625611..ff4ab32e0c21 100644 --- a/tests/pos/Iter2.scala +++ b/tests/pos/Iter2.scala @@ -58,16 +58,16 @@ object Iter2 { def fromIterator[B](it: Iterator[B]): C[B] } - trait Iterable[+IA] extends IterableOnce[IA] with FromIterator[Iterable] { + trait Iterable[+IA] extends IterableOnce[IA], FromIterator[Iterable] { def view: View[IA] = new View(iterator) } - trait Seq[+AA] extends Iterable[AA] with FromIterator[Seq] { + trait Seq[+AA] extends Iterable[AA], FromIterator[Seq] { def apply(i: Int): AA def length: Int } - sealed trait List[+A] extends Seq[A] with FromIterator[List] { + sealed trait List[+A] extends Seq[A], FromIterator[List] { def isEmpty: Boolean def head: A def tail: List[A] @@ -84,7 +84,7 @@ object Iter2 { if (isEmpty) 0 else 1 + tail.length } - class View[+A](it: Iterator[A]) extends Iterable[A] with FromIterator[View] { + class View[+A](it: Iterator[A]) extends Iterable[A], FromIterator[View] { def iterator: Iterator[A] = it.copy def fromIterator[B](it: Iterator[B]): View[B] = new View(it) } @@ -101,7 +101,7 @@ object Iter2 { def tail = ??? } - class ArrayBuffer[A] private (initElems: Array[AnyRef], initLen: Int) extends Seq[A] with FromIterator[ArrayBuffer] { + class ArrayBuffer[A] private (initElems: Array[AnyRef], initLen: Int) extends Seq[A], FromIterator[ArrayBuffer] { def this() = this(new Array[AnyRef](16), 0) def this(it: ArrayIterator[A]) = this(it.elems, it.len) private var elems: Array[AnyRef] = initElems @@ -116,7 +116,7 @@ object Iter2 { def length = len } /* - class SeqView[A](itf: () => Iterator) extends Seq[A] with FromIterator[SeqView] { + class SeqView[A](itf: () => Iterator) extends Seq[A], FromIterator[SeqView] { def iterator = it def buildIterator = it def fromIterator[B](it: Iterator[B]) = it match { diff --git a/tests/pos/this-types.scala b/tests/pos/this-types.scala index d75de54b3ffa..ddbc0f9c1b8a 100644 --- a/tests/pos/this-types.scala +++ b/tests/pos/this-types.scala @@ -9,7 +9,7 @@ trait C extends A { type A_This = C_This type C_This <: C } -trait D extends B with C { +trait D extends B, C { type B_This = D_This type C_This = D_This type D_This <: D diff --git a/tests/pos/traits_1.scala b/tests/pos/traits_1.scala index 3c6f9437a5fa..bd597149e268 100644 --- a/tests/pos/traits_1.scala +++ b/tests/pos/traits_1.scala @@ -17,7 +17,7 @@ object Test { case _ => false } } - trait BorderedColoredShape extends Shape with Bordered with Colored { + trait BorderedColoredShape extends Shape, Bordered, Colored { override def equals(other: Any) = other match { case that: BorderedColoredShape => ( super.equals(that) && diff --git a/tests/pos/typeclass-encoding.scala b/tests/pos/typeclass-encoding.scala index 69679e218ee3..12ae16e208a6 100644 --- a/tests/pos/typeclass-encoding.scala +++ b/tests/pos/typeclass-encoding.scala @@ -65,7 +65,7 @@ object semiGroups { type StaticPart[X] = MonoidStatic[X] } - implicit object extend_Int_Monoid extends MonoidStatic[Int] with Implementation[Int] { + implicit object extend_Int_Monoid extends MonoidStatic[Int], Implementation[Int] { type Implemented = Monoid def unit: Int = 0 def inject($this: Int) = new Monoid { @@ -74,7 +74,7 @@ object semiGroups { } } - implicit object extend_String_Monoid extends MonoidStatic[String] with Implementation[String] { + implicit object extend_String_Monoid extends MonoidStatic[String], Implementation[String] { type Implemented = Monoid def unit = "" def inject($this: String): Monoid { type This = String } = diff --git a/tests/run-separate-compilation/tasty-positioned.check b/tests/run-separate-compilation/tasty-positioned.check index 6730ef470015..3005121fb971 100644 --- a/tests/run-separate-compilation/tasty-positioned.check +++ b/tests/run-separate-compilation/tasty-positioned.check @@ -5,4 +5,4 @@ acbvasdfa columns:13-36 lines:12-12 acbvasdfa columns:13-24 lines:13-13 a b columns:6-25 lines:15-16 -Foo columns:16-19 lines:17-17 +Foo columns:12-19 lines:17-17 diff --git a/tests/run/generic/SearchResult.scala b/tests/run/generic/SearchResult.scala index d4380a072b9f..96ec7e3f2536 100644 --- a/tests/run/generic/SearchResult.scala +++ b/tests/run/generic/SearchResult.scala @@ -11,7 +11,7 @@ import Shapes._ */ sealed trait SearchResult extends Enum -object SearchResult extends { +object SearchResult { private val $values = new runtime.EnumValues[SearchResult] def valueOf = $values.fromInt diff --git a/tests/run/t6090.scala b/tests/run/t6090.scala index e7dbb36a05ae..51999a917e38 100644 --- a/tests/run/t6090.scala +++ b/tests/run/t6090.scala @@ -1,6 +1,6 @@ class X { def ==(other: X) = true } class V(val x: X) extends AnyVal -object Test extends { +object Test { def main(args: Array[String]) = assert((new V(new X) == new V(new X))) }