Skip to content

Allow , in parents of template #5518

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 71 additions & 38 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1392,7 +1392,7 @@ object Parsers {
}
else simpleExpr()

/** SimpleExpr ::= new Template
/** SimpleExpr ::= new’ (ConstrApp [TemplateBody] | TemplateBody)
* | BlockExpr
* | ‘'{’ BlockExprContents ‘}’
* | ‘'(’ ExprsInParens ‘)’
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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] =
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 `}'
*/
Expand Down
5 changes: 5 additions & 0 deletions compiler/src/dotty/tools/dotc/parsing/Scanners.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down
12 changes: 6 additions & 6 deletions docs/docs/internals/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 ‘)’
Expand Down Expand Up @@ -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(_, <init>, Nil, vparamss, EmptyTree, EmptyTree) as first stat
ClassDef ::= id ClassConstr [Template] ClassDef(mods, name, tparams, templ)
ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsParamClauses with DefDef(_, <init>, 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
Expand Down
2 changes: 1 addition & 1 deletion tests/invalid/neg/typelevel.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
4 changes: 2 additions & 2 deletions tests/neg/i2770.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
12 changes: 6 additions & 6 deletions tests/pos/Iter2.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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)
}
Expand All @@ -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
Expand All @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion tests/pos/this-types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion tests/pos/traits_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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) &&
Expand Down
4 changes: 2 additions & 2 deletions tests/pos/typeclass-encoding.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 } =
Expand Down
2 changes: 1 addition & 1 deletion tests/run-separate-compilation/tasty-positioned.check
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion tests/run/generic/SearchResult.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion tests/run/t6090.scala
Original file line number Diff line number Diff line change
@@ -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)))
}