Skip to content

Commit

Permalink
Revert "Allow with after class"
Browse files Browse the repository at this point in the history
This reverts commit acdee20.

# Conflicts:
#	docs/docs/internals/syntax.md
  • Loading branch information
odersky committed Jan 25, 2021
1 parent 4732e78 commit 945ff14
Show file tree
Hide file tree
Showing 318 changed files with 847 additions and 866 deletions.
44 changes: 11 additions & 33 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2315,7 +2315,7 @@ object Parsers {
possibleTemplateStart()
val parents =
if in.isNestedStart then Nil
else constrApp() :: withConstrApps()
else constrApps(commaOK = false)
colonAtEOLOpt()
possibleTemplateStart(isNew = true)
parents match {
Expand Down Expand Up @@ -3494,7 +3494,7 @@ object Parsers {
val parents =
if (in.token == EXTENDS) {
in.nextToken()
constrApps()
constrApps(commaOK = true)
}
else Nil
Template(constr, parents, Nil, EmptyValDef, Nil)
Expand Down Expand Up @@ -3628,35 +3628,22 @@ object Parsers {

/** ConstrApps ::= ConstrApp ({‘,’ ConstrApp} | {‘with’ ConstrApp})
*/
def constrApps(): List[Tree] =
def constrApps(commaOK: Boolean): List[Tree] =
val t = constrApp()
val ts = if in.token == COMMA then commaConstrApps() else withConstrApps()
val ts =
if in.token == WITH || commaOK && in.token == COMMA then
in.nextToken()
constrApps(commaOK)
else Nil
t :: ts

/** `{`,` ConstrApp} */
def commaConstrApps(): List[Tree] =
if in.token == COMMA then
in.nextToken()
constrApp() :: commaConstrApps()
else Nil

/** `{`with` ConstrApp} but no EOL allowed after `with`.
*/
def withConstrApps(): List[Tree] =
def isTemplateStart =
val la = in.lookahead
la.token == LBRACE
|| la.isAfterLineEnd
&& {
if migrateTo3 then
warning(
em"""In Scala 3, `with` at the end of a line will start definitions,
|so it cannot be used in front of a parent constructor anymore.
|Place the `with` at the beginning of the next line instead.""")
false
else
true
}
la.isAfterLineEnd || la.token == LBRACE
if in.token == WITH && !isTemplateStart then
in.nextToken()
constrApp() :: withConstrApps()
Expand All @@ -3675,7 +3662,7 @@ object Parsers {
in.sourcePos())
Nil
}
else constrApps()
else constrApps(commaOK = true)
}
else Nil
newLinesOptWhenFollowedBy(nme.derives)
Expand Down Expand Up @@ -3819,16 +3806,7 @@ object Parsers {
}
else {
stats += first
if in.token == WITH then
syntaxError(
i"""end of statement expected but ${showToken(WITH)} found
|
|Maybe you meant to write a mixin in an extends clause?
|Note that this requires the `with` to come first now.
|I.e.
|
| with $first""")
else acceptStatSepUnlessAtEnd(stats)
acceptStatSepUnlessAtEnd(stats)
}
}
var exitOnError = false
Expand Down
18 changes: 10 additions & 8 deletions docs/docs/internals/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ comment ::= ‘/*’ “any sequence of characters; nested comments ar
nl ::= “new line character”
semi ::= ‘;’ | nl {nl}
colonEol ::= ": at end of line that can start a template body"
```

## Keywords
Expand Down Expand Up @@ -217,8 +218,9 @@ SimpleExpr ::= SimpleRef
| ‘$’ ‘{’ Block ‘}’
| Quoted
| quoteId -- only inside splices
| ‘new’ ConstrApp {‘with’ ConstrApp} [TemplateBody] New(constr | templ)
| ‘new’ TemplateBody
| ‘new’ ConstrApp {‘with’ ConstrApp} New(constr | templ)
[[colonEol] TemplateBody
| ‘new’ [colonEol] TemplateBody
| ‘(’ ExprsInParens ‘)’ Parens(exprs)
| SimpleExpr ‘.’ id Select(expr, id)
| SimpleExpr ‘.’ MatchClause
Expand Down Expand Up @@ -384,23 +386,23 @@ ClassDef ::= id ClassConstr [Template]
ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsParamClauses with DefDef(_, <init>, Nil, vparamss, EmptyTree, EmptyTree) as first stat
ConstrMods ::= {Annotation} [AccessModifier]
ObjectDef ::= id [Template] ModuleDef(mods, name, template) // no constructor
EnumDef ::= id ClassConstr InheritClauses EnumBody
EnumDef ::= id ClassConstr InheritClauses [colonEol] EnumBody
GivenDef ::= [GivenSig] (AnnotType [‘=’ Expr] | StructuralInstance)
GivenSig ::= [id] [DefTypeParamClause] {UsingParamClause} ‘:’ -- one of `id`, `DefParamClause`, `UsingParamClause` must be present
StructuralInstance ::= ConstrApp {‘with’ ConstrApp} TemplateBody
StructuralInstance ::= ConstrApp {‘with’ ConstrApp} ‘with’ TemplateBody
Extension ::= ‘extension’ [DefTypeParamClause] ‘(’ DefParam ‘)’
{UsingParamClause}] ExtMethods
ExtMethods ::= ExtMethod | [nl] ‘{’ ExtMethod {semi ExtMethod ‘}’
ExtMethod ::= {Annotation [nl]} {Modifier} ‘def’ DefDef
Template ::= InheritClauses [TemplateBody] Template(constr, parents, self, stats)
Template ::= InheritClauses [colonEol] [TemplateBody] Template(constr, parents, self, stats)
InheritClauses ::= [‘extends’ ConstrApps] [‘derives’ QualId {‘,’ QualId}]
ConstrApps ::= ConstrApp ({‘,’ ConstrApp} | {‘with’ ConstrApp})
ConstrApp ::= SimpleType1 {Annotation} {ParArgumentExprs} Apply(tp, args)
ConstrExpr ::= SelfInvocation
| ‘{’ SelfInvocation {semi BlockStat} ‘}’
SelfInvocation ::= ‘this’ ArgumentExprs {ArgumentExprs}
TemplateBody ::= [nl | ‘with’] ‘{’ [SelfType] TemplateStat {semi TemplateStat} ‘}’
TemplateBody ::= [nl] ‘{’ [SelfType] TemplateStat {semi TemplateStat} ‘}’
TemplateStat ::= Import
| Export
| {Annotation [nl]} {Modifier} Def
Expand All @@ -412,7 +414,7 @@ TemplateStat ::= Import
SelfType ::= id [‘:’ InfixType] ‘=>’ ValDef(_, name, tpt, _)
| ‘this’ ‘:’ InfixType ‘=>’
EnumBody ::= [nl | ‘with’] ‘{’ [SelfType] EnumStat {semi EnumStat} ‘}’
EnumBody ::= [nl] ‘{’ [SelfType] EnumStat {semi EnumStat} ‘}’
EnumStat ::= TemplateStat
| {Annotation [nl]} {Modifier} EnumCase
EnumCase ::= ‘case’ (id ClassConstr [‘extends’ ConstrApps]] | ids)
Expand All @@ -426,7 +428,7 @@ TopStat ::= Import
| PackageObject
| EndMarker
|
Packaging ::= ‘package’ QualId [nl| ‘with’] ‘{’ TopStatSeq ‘}’ Package(qid, stats)
Packaging ::= ‘package’ QualId [nl | colonEol] ‘{’ TopStatSeq ‘}’ Package(qid, stats)
PackageObject ::= ‘package’ ‘object’ ObjectDef object with package in mods.
CompilationUnit ::= {‘package’ QualId semi} TopStatSeq Package(qid, stats)
Expand Down
6 changes: 3 additions & 3 deletions docs/docs/reference/changed-features/compiler-plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,14 @@ import dotty.tools.dotc.core.Symbols._
import dotty.tools.dotc.plugins.{PluginPhase, StandardPlugin}
import dotty.tools.dotc.transform.{Pickler, Staging}

class DivideZero extends StandardPlugin with
class DivideZero extends StandardPlugin:
val name: String = "divideZero"
override val description: String = "divide zero check"

def init(options: List[String]): List[PluginPhase] =
(new DivideZeroPhase) :: Nil

class DivideZeroPhase extends PluginPhase with
class DivideZeroPhase extends PluginPhase:
import tpd._

val phaseName = "divideZero"
Expand Down Expand Up @@ -108,7 +108,7 @@ import dotty.tools.dotc.core.Contexts.Context
import dotty.tools.dotc.core.Phases.Phase
import dotty.tools.dotc.plugins.ResearchPlugin

class DummyResearchPlugin extends ResearchPlugin with
class DummyResearchPlugin extends ResearchPlugin:
val name: String = "dummy"
override val description: String = "dummy research plugin"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The standard library defines an abstract class `Conversion`:
```scala
package scala
@java.lang.FunctionalInterface
abstract class Conversion[-T, +U] extends Function1[T, U] with
abstract class Conversion[-T, +U] extends Function1[T, U]:
def apply(x: T): U
```

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/reference/changed-features/main-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ The Scala compiler generates a program from a `@main` method `f` as follows:
For instance, the `happyBirthDay` method above would generate additional code equivalent to the following class:

```scala
final class happyBirthday with
final class happyBirthday:
import scala.util.{CommandLineParser => CLP}
<static> def main(args: Array[String]): Unit =
try
Expand Down
6 changes: 3 additions & 3 deletions docs/docs/reference/changed-features/numeric-literals.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ class MalformedNumber(msg: String = "malformed number literal") extends FromDigi
As a fully worked out example, here is an implementation of a new numeric class, `BigFloat`, that accepts numeric literals. `BigFloat` is defined in terms of a `BigInt` mantissa and an `Int` exponent:

```scala
case class BigFloat(mantissa: BigInt, exponent: Int) with
case class BigFloat(mantissa: BigInt, exponent: Int):
override def toString = s"${mantissa}e${exponent}"
```

Expand All @@ -145,7 +145,7 @@ The companion object of `BigFloat` defines an `apply` constructor method to cons
from a `digits` string. Here is a possible implementation:

```scala
object BigFloat with
object BigFloat:
import scala.util.FromDigits

def apply(digits: String): BigFloat =
Expand Down Expand Up @@ -206,7 +206,7 @@ To do this, replace the `FromDigits` instance in the `BigFloat` object by the fo
object BigFloat:
...

class FromDigits extends FromDigits.Floating[BigFloat] with
class FromDigits extends FromDigits.Floating[BigFloat]:
def fromDigits(digits: String) = apply(digits)

given FromDigits with
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/reference/changed-features/pattern-matching.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ For example:
<!-- To be kept in sync with tests/new/patmat-spec.scala -->

```scala
class FirstChars(s: String) extends Product with
class FirstChars(s: String) extends Product:
def _1 = s.charAt(0)
def _2 = s.charAt(1)

Expand All @@ -147,7 +147,7 @@ object FirstChars:
<!-- To be kept in sync with tests/new/patmat-spec.scala -->

```scala
class Nat(val x: Int) with
class Nat(val x: Int):
def get: Int = x
def isEmpty = x < 0

Expand Down
8 changes: 4 additions & 4 deletions docs/docs/reference/changed-features/structural-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ configure how fields and methods should be resolved.
Here's an example of a structural type `Person`:

```scala
class Record(elems: (String, Any)*) extends Selectable with
class Record(elems: (String, Any)*) extends Selectable:
private val fields = elems.toMap
def selectDynamic(name: String): Any = fields(name)

type Person = Record { val name: String; val age: Int }
```

The type `Person` adds a _refinement_ to its parent type `Record` that defines the two fields `name` and `age`. We say the refinement is _structural_ since `name` and `age` are not defined in the parent type. But they exist nevertheless as members of class `Person`. For instance, the following
program would print "Emma is 42 years old.":

Expand Down Expand Up @@ -82,10 +82,10 @@ Structural types can also be accessed using [Java reflection](https://www.oracle
```scala
type Closeable = { def close(): Unit }

class FileInputStream with
class FileInputStream:
def close(): Unit

class Channel with
class Channel:
def close(): Unit
```

Expand Down
4 changes: 2 additions & 2 deletions docs/docs/reference/contextual/context-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ the aim is to construct tables like this:
The idea is to define classes for `Table` and `Row` that allow the
addition of elements via `add`:
```scala
class Table with
class Table:
val rows = new ArrayBuffer[Row]
def add(r: Row): Unit = rows += r
override def toString = rows.mkString("Table(", ", ", ")")

class Row with
class Row:
val cells = new ArrayBuffer[Cell]
def add(c: Cell): Unit = cells += c
override def toString = cells.mkString("Row(", ", ", ")")
Expand Down
8 changes: 4 additions & 4 deletions docs/docs/reference/contextual/conversions.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ title: "Implicit Conversions"
Implicit conversions are defined by given instances of the `scala.Conversion` class.
This class is defined in package `scala` as follows:
```scala
abstract class Conversion[-T, +U] extends (T => U) with
abstract class Conversion[-T, +U] extends (T => U):
def apply (x: T): U
```
For example, here is an implicit conversion from `String` to `Token`:
Expand Down Expand Up @@ -43,15 +43,15 @@ conversion from `Int` to `java.lang.Integer` can be defined as follows:

2. The "magnet" pattern is sometimes used to express many variants of a method. Instead of defining overloaded versions of the method, one can also let the method take one or more arguments of specially defined "magnet" types, into which various argument types can be converted. Example:
```scala
object Completions with
object Completions:

// The argument "magnet" type
enum CompletionArg with
enum CompletionArg:
case Error(s: String)
case Response(f: Future[HttpResponse])
case Status(code: Future[StatusCode])

object CompletionArg with
object CompletionArg:

// conversions defining the possible arguments to pass to `complete`
// these always come with CompletionArg
Expand Down
10 changes: 5 additions & 5 deletions docs/docs/reference/contextual/extension-methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,21 +174,21 @@ There are four possible ways for an extension method to be applicable:
Here is an example for the first rule:

```scala
trait IntOps with
trait IntOps:
extension (i: Int) def isZero: Boolean = i == 0

extension (i: Int) def safeMod(x: Int): Option[Int] =
// extension method defined in same scope IntOps
if x.isZero then None
else Some(i % x)

object IntOpsEx extends IntOps with
object IntOpsEx extends IntOps:
extension (i: Int) def safeDiv(x: Int): Option[Int] =
// extension method brought into scope via inheritance from IntOps
if x.isZero then None
else Some(i / x)

trait SafeDiv with
trait SafeDiv:
import IntOpsEx._ // brings safeDiv and safeMod into scope

extension (i: Int) def divide(d: Int): Option[(Int, Int)] =
Expand All @@ -209,9 +209,9 @@ given ops1: IntOps with {} // brings safeMod into scope
By the third and fourth rule, an extension method is available if it is in the implicit scope of the receiver type or in a given instance in that scope. Example:

```scala
class List[T] with
class List[T]:
...
object List with
object List:
...
extension [T](xs: List[List[T]])
def flatten: List[T] = xs.foldLeft(Nil: List[T])(_ ++ _)
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/reference/contextual/givens.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Given instances (or, simply, "givens") define "canonical" values of certain type
that serve for synthesizing arguments to [context parameters](./using-clauses.md). Example:

```scala
trait Ord[T] with
trait Ord[T]:
def compare(x: T, y: T): Int
extension (x: T) def < (y: T) = compare(x, y) < 0
extension (x: T) def > (y: T) = compare(x, y) > 0
Expand Down Expand Up @@ -130,7 +130,7 @@ import scala.util.NotGiven
trait Tagged[A]

case class Foo[A](value: Boolean)
object Foo with
object Foo:
given fooTagged[A](using Tagged[A]): Foo[A] = Foo(true)
given fooNotTagged[A](using NotGiven[Tagged[A]]): Foo[A] = Foo(false)

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/reference/contextual/multiversal-equality.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ we are dealing with a refinement of pre-existing, universal equality. It is best

Say you want to come up with a safe version of the `contains` method on `List[T]`. The original definition of `contains` in the standard library was:
```scala
class List[+T] with
class List[+T]:
...
def contains(x: Any): Boolean
```
Expand Down
Loading

0 comments on commit 945ff14

Please sign in to comment.