Skip to content

Commit 945ff14

Browse files
committed
Revert "Allow with after class"
This reverts commit acdee20. # Conflicts: # docs/docs/internals/syntax.md
1 parent 4732e78 commit 945ff14

File tree

318 files changed

+847
-866
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

318 files changed

+847
-866
lines changed

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

+11-33
Original file line numberDiff line numberDiff line change
@@ -2315,7 +2315,7 @@ object Parsers {
23152315
possibleTemplateStart()
23162316
val parents =
23172317
if in.isNestedStart then Nil
2318-
else constrApp() :: withConstrApps()
2318+
else constrApps(commaOK = false)
23192319
colonAtEOLOpt()
23202320
possibleTemplateStart(isNew = true)
23212321
parents match {
@@ -3494,7 +3494,7 @@ object Parsers {
34943494
val parents =
34953495
if (in.token == EXTENDS) {
34963496
in.nextToken()
3497-
constrApps()
3497+
constrApps(commaOK = true)
34983498
}
34993499
else Nil
35003500
Template(constr, parents, Nil, EmptyValDef, Nil)
@@ -3628,35 +3628,22 @@ object Parsers {
36283628

36293629
/** ConstrApps ::= ConstrApp ({‘,’ ConstrApp} | {‘with’ ConstrApp})
36303630
*/
3631-
def constrApps(): List[Tree] =
3631+
def constrApps(commaOK: Boolean): List[Tree] =
36323632
val t = constrApp()
3633-
val ts = if in.token == COMMA then commaConstrApps() else withConstrApps()
3633+
val ts =
3634+
if in.token == WITH || commaOK && in.token == COMMA then
3635+
in.nextToken()
3636+
constrApps(commaOK)
3637+
else Nil
36343638
t :: ts
36353639

3636-
/** `{`,` ConstrApp} */
3637-
def commaConstrApps(): List[Tree] =
3638-
if in.token == COMMA then
3639-
in.nextToken()
3640-
constrApp() :: commaConstrApps()
3641-
else Nil
36423640

36433641
/** `{`with` ConstrApp} but no EOL allowed after `with`.
36443642
*/
36453643
def withConstrApps(): List[Tree] =
36463644
def isTemplateStart =
36473645
val la = in.lookahead
3648-
la.token == LBRACE
3649-
|| la.isAfterLineEnd
3650-
&& {
3651-
if migrateTo3 then
3652-
warning(
3653-
em"""In Scala 3, `with` at the end of a line will start definitions,
3654-
|so it cannot be used in front of a parent constructor anymore.
3655-
|Place the `with` at the beginning of the next line instead.""")
3656-
false
3657-
else
3658-
true
3659-
}
3646+
la.isAfterLineEnd || la.token == LBRACE
36603647
if in.token == WITH && !isTemplateStart then
36613648
in.nextToken()
36623649
constrApp() :: withConstrApps()
@@ -3675,7 +3662,7 @@ object Parsers {
36753662
in.sourcePos())
36763663
Nil
36773664
}
3678-
else constrApps()
3665+
else constrApps(commaOK = true)
36793666
}
36803667
else Nil
36813668
newLinesOptWhenFollowedBy(nme.derives)
@@ -3819,16 +3806,7 @@ object Parsers {
38193806
}
38203807
else {
38213808
stats += first
3822-
if in.token == WITH then
3823-
syntaxError(
3824-
i"""end of statement expected but ${showToken(WITH)} found
3825-
|
3826-
|Maybe you meant to write a mixin in an extends clause?
3827-
|Note that this requires the `with` to come first now.
3828-
|I.e.
3829-
|
3830-
| with $first""")
3831-
else acceptStatSepUnlessAtEnd(stats)
3809+
acceptStatSepUnlessAtEnd(stats)
38323810
}
38333811
}
38343812
var exitOnError = false

docs/docs/internals/syntax.md

+10-8
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ comment ::= ‘/*’ “any sequence of characters; nested comments ar
8383
8484
nl ::= “new line character”
8585
semi ::= ‘;’ | nl {nl}
86+
colonEol ::= ": at end of line that can start a template body"
8687
```
8788

8889
## Keywords
@@ -217,8 +218,9 @@ SimpleExpr ::= SimpleRef
217218
| ‘$’ ‘{’ Block ‘}’
218219
| Quoted
219220
| quoteId -- only inside splices
220-
| ‘new’ ConstrApp {‘with’ ConstrApp} [TemplateBody] New(constr | templ)
221-
| ‘new’ TemplateBody
221+
| ‘new’ ConstrApp {‘with’ ConstrApp} New(constr | templ)
222+
[[colonEol] TemplateBody
223+
| ‘new’ [colonEol] TemplateBody
222224
| ‘(’ ExprsInParens ‘)’ Parens(exprs)
223225
| SimpleExpr ‘.’ id Select(expr, id)
224226
| SimpleExpr ‘.’ MatchClause
@@ -384,23 +386,23 @@ ClassDef ::= id ClassConstr [Template]
384386
ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsParamClauses with DefDef(_, <init>, Nil, vparamss, EmptyTree, EmptyTree) as first stat
385387
ConstrMods ::= {Annotation} [AccessModifier]
386388
ObjectDef ::= id [Template] ModuleDef(mods, name, template) // no constructor
387-
EnumDef ::= id ClassConstr InheritClauses EnumBody
389+
EnumDef ::= id ClassConstr InheritClauses [colonEol] EnumBody
388390
GivenDef ::= [GivenSig] (AnnotType [‘=’ Expr] | StructuralInstance)
389391
GivenSig ::= [id] [DefTypeParamClause] {UsingParamClause} ‘:’ -- one of `id`, `DefParamClause`, `UsingParamClause` must be present
390-
StructuralInstance ::= ConstrApp {‘with’ ConstrApp} TemplateBody
392+
StructuralInstance ::= ConstrApp {‘with’ ConstrApp} ‘with’ TemplateBody
391393
Extension ::= ‘extension’ [DefTypeParamClause] ‘(’ DefParam ‘)’
392394
{UsingParamClause}] ExtMethods
393395
ExtMethods ::= ExtMethod | [nl] ‘{’ ExtMethod {semi ExtMethod ‘}’
394396
ExtMethod ::= {Annotation [nl]} {Modifier} ‘def’ DefDef
395-
Template ::= InheritClauses [TemplateBody] Template(constr, parents, self, stats)
397+
Template ::= InheritClauses [colonEol] [TemplateBody] Template(constr, parents, self, stats)
396398
InheritClauses ::= [‘extends’ ConstrApps] [‘derives’ QualId {‘,’ QualId}]
397399
ConstrApps ::= ConstrApp ({‘,’ ConstrApp} | {‘with’ ConstrApp})
398400
ConstrApp ::= SimpleType1 {Annotation} {ParArgumentExprs} Apply(tp, args)
399401
ConstrExpr ::= SelfInvocation
400402
| ‘{’ SelfInvocation {semi BlockStat} ‘}’
401403
SelfInvocation ::= ‘this’ ArgumentExprs {ArgumentExprs}
402404
403-
TemplateBody ::= [nl | ‘with’] ‘{’ [SelfType] TemplateStat {semi TemplateStat} ‘}’
405+
TemplateBody ::= [nl] ‘{’ [SelfType] TemplateStat {semi TemplateStat} ‘}’
404406
TemplateStat ::= Import
405407
| Export
406408
| {Annotation [nl]} {Modifier} Def
@@ -412,7 +414,7 @@ TemplateStat ::= Import
412414
SelfType ::= id [‘:’ InfixType] ‘=>’ ValDef(_, name, tpt, _)
413415
| ‘this’ ‘:’ InfixType ‘=>’
414416
415-
EnumBody ::= [nl | ‘with’] ‘{’ [SelfType] EnumStat {semi EnumStat} ‘}’
417+
EnumBody ::= [nl] ‘{’ [SelfType] EnumStat {semi EnumStat} ‘}’
416418
EnumStat ::= TemplateStat
417419
| {Annotation [nl]} {Modifier} EnumCase
418420
EnumCase ::= ‘case’ (id ClassConstr [‘extends’ ConstrApps]] | ids)
@@ -426,7 +428,7 @@ TopStat ::= Import
426428
| PackageObject
427429
| EndMarker
428430
|
429-
Packaging ::= ‘package’ QualId [nl| ‘with’] ‘{’ TopStatSeq ‘}’ Package(qid, stats)
431+
Packaging ::= ‘package’ QualId [nl | colonEol] ‘{’ TopStatSeq ‘}’ Package(qid, stats)
430432
PackageObject ::= ‘package’ ‘object’ ObjectDef object with package in mods.
431433
432434
CompilationUnit ::= {‘package’ QualId semi} TopStatSeq Package(qid, stats)

docs/docs/reference/changed-features/compiler-plugins.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,14 @@ import dotty.tools.dotc.core.Symbols._
6262
import dotty.tools.dotc.plugins.{PluginPhase, StandardPlugin}
6363
import dotty.tools.dotc.transform.{Pickler, Staging}
6464

65-
class DivideZero extends StandardPlugin with
65+
class DivideZero extends StandardPlugin:
6666
val name: String = "divideZero"
6767
override val description: String = "divide zero check"
6868

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

72-
class DivideZeroPhase extends PluginPhase with
72+
class DivideZeroPhase extends PluginPhase:
7373
import tpd._
7474

7575
val phaseName = "divideZero"
@@ -108,7 +108,7 @@ import dotty.tools.dotc.core.Contexts.Context
108108
import dotty.tools.dotc.core.Phases.Phase
109109
import dotty.tools.dotc.plugins.ResearchPlugin
110110

111-
class DummyResearchPlugin extends ResearchPlugin with
111+
class DummyResearchPlugin extends ResearchPlugin:
112112
val name: String = "dummy"
113113
override val description: String = "dummy research plugin"
114114

docs/docs/reference/changed-features/implicit-conversions-spec.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ The standard library defines an abstract class `Conversion`:
1616
```scala
1717
package scala
1818
@java.lang.FunctionalInterface
19-
abstract class Conversion[-T, +U] extends Function1[T, U] with
19+
abstract class Conversion[-T, +U] extends Function1[T, U]:
2020
def apply(x: T): U
2121
```
2222

docs/docs/reference/changed-features/main-functions.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ The Scala compiler generates a program from a `@main` method `f` as follows:
6161
For instance, the `happyBirthDay` method above would generate additional code equivalent to the following class:
6262

6363
```scala
64-
final class happyBirthday with
64+
final class happyBirthday:
6565
import scala.util.{CommandLineParser => CLP}
6666
<static> def main(args: Array[String]): Unit =
6767
try

docs/docs/reference/changed-features/numeric-literals.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ class MalformedNumber(msg: String = "malformed number literal") extends FromDigi
130130
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:
131131

132132
```scala
133-
case class BigFloat(mantissa: BigInt, exponent: Int) with
133+
case class BigFloat(mantissa: BigInt, exponent: Int):
134134
override def toString = s"${mantissa}e${exponent}"
135135
```
136136

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

147147
```scala
148-
object BigFloat with
148+
object BigFloat:
149149
import scala.util.FromDigits
150150

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

209-
class FromDigits extends FromDigits.Floating[BigFloat] with
209+
class FromDigits extends FromDigits.Floating[BigFloat]:
210210
def fromDigits(digits: String) = apply(digits)
211211

212212
given FromDigits with

docs/docs/reference/changed-features/pattern-matching.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ For example:
121121
<!-- To be kept in sync with tests/new/patmat-spec.scala -->
122122

123123
```scala
124-
class FirstChars(s: String) extends Product with
124+
class FirstChars(s: String) extends Product:
125125
def _1 = s.charAt(0)
126126
def _2 = s.charAt(1)
127127

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

149149
```scala
150-
class Nat(val x: Int) with
150+
class Nat(val x: Int):
151151
def get: Int = x
152152
def isEmpty = x < 0
153153

docs/docs/reference/changed-features/structural-types.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@ configure how fields and methods should be resolved.
3434
Here's an example of a structural type `Person`:
3535

3636
```scala
37-
class Record(elems: (String, Any)*) extends Selectable with
37+
class Record(elems: (String, Any)*) extends Selectable:
3838
private val fields = elems.toMap
3939
def selectDynamic(name: String): Any = fields(name)
4040

4141
type Person = Record { val name: String; val age: Int }
4242
```
43-
43+
4444
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
4545
program would print "Emma is 42 years old.":
4646

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

85-
class FileInputStream with
85+
class FileInputStream:
8686
def close(): Unit
8787

88-
class Channel with
88+
class Channel:
8989
def close(): Unit
9090
```
9191

docs/docs/reference/contextual/context-functions.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,12 @@ the aim is to construct tables like this:
6767
The idea is to define classes for `Table` and `Row` that allow the
6868
addition of elements via `add`:
6969
```scala
70-
class Table with
70+
class Table:
7171
val rows = new ArrayBuffer[Row]
7272
def add(r: Row): Unit = rows += r
7373
override def toString = rows.mkString("Table(", ", ", ")")
7474

75-
class Row with
75+
class Row:
7676
val cells = new ArrayBuffer[Cell]
7777
def add(c: Cell): Unit = cells += c
7878
override def toString = cells.mkString("Row(", ", ", ")")

docs/docs/reference/contextual/conversions.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ title: "Implicit Conversions"
66
Implicit conversions are defined by given instances of the `scala.Conversion` class.
77
This class is defined in package `scala` as follows:
88
```scala
9-
abstract class Conversion[-T, +U] extends (T => U) with
9+
abstract class Conversion[-T, +U] extends (T => U):
1010
def apply (x: T): U
1111
```
1212
For example, here is an implicit conversion from `String` to `Token`:
@@ -43,15 +43,15 @@ conversion from `Int` to `java.lang.Integer` can be defined as follows:
4343

4444
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:
4545
```scala
46-
object Completions with
46+
object Completions:
4747

4848
// The argument "magnet" type
49-
enum CompletionArg with
49+
enum CompletionArg:
5050
case Error(s: String)
5151
case Response(f: Future[HttpResponse])
5252
case Status(code: Future[StatusCode])
5353

54-
object CompletionArg with
54+
object CompletionArg:
5555

5656
// conversions defining the possible arguments to pass to `complete`
5757
// these always come with CompletionArg

docs/docs/reference/contextual/extension-methods.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -174,21 +174,21 @@ There are four possible ways for an extension method to be applicable:
174174
Here is an example for the first rule:
175175

176176
```scala
177-
trait IntOps with
177+
trait IntOps:
178178
extension (i: Int) def isZero: Boolean = i == 0
179179

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

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

191-
trait SafeDiv with
191+
trait SafeDiv:
192192
import IntOpsEx._ // brings safeDiv and safeMod into scope
193193

194194
extension (i: Int) def divide(d: Int): Option[(Int, Int)] =
@@ -209,9 +209,9 @@ given ops1: IntOps with {} // brings safeMod into scope
209209
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:
210210

211211
```scala
212-
class List[T] with
212+
class List[T]:
213213
...
214-
object List with
214+
object List:
215215
...
216216
extension [T](xs: List[List[T]])
217217
def flatten: List[T] = xs.foldLeft(Nil: List[T])(_ ++ _)

docs/docs/reference/contextual/givens.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Given instances (or, simply, "givens") define "canonical" values of certain type
77
that serve for synthesizing arguments to [context parameters](./using-clauses.md). Example:
88

99
```scala
10-
trait Ord[T] with
10+
trait Ord[T]:
1111
def compare(x: T, y: T): Int
1212
extension (x: T) def < (y: T) = compare(x, y) < 0
1313
extension (x: T) def > (y: T) = compare(x, y) > 0
@@ -130,7 +130,7 @@ import scala.util.NotGiven
130130
trait Tagged[A]
131131

132132
case class Foo[A](value: Boolean)
133-
object Foo with
133+
object Foo:
134134
given fooTagged[A](using Tagged[A]): Foo[A] = Foo(true)
135135
given fooNotTagged[A](using NotGiven[Tagged[A]]): Foo[A] = Foo(false)
136136

docs/docs/reference/contextual/multiversal-equality.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ we are dealing with a refinement of pre-existing, universal equality. It is best
172172

173173
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:
174174
```scala
175-
class List[+T] with
175+
class List[+T]:
176176
...
177177
def contains(x: Any): Boolean
178178
```

0 commit comments

Comments
 (0)