Skip to content

Commit 13e75d8

Browse files
committed
Allow with after class
1 parent 504b9dd commit 13e75d8

File tree

319 files changed

+872
-853
lines changed

Some content is hidden

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

319 files changed

+872
-853
lines changed

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

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,7 +1288,7 @@ object Parsers {
12881288
else
12891289
in.nextToken()
12901290
if in.token != INDENT && in.token != LBRACE then
1291-
syntaxErrorOrIncomplete(i"indented definitions expected, ${in}")
1291+
syntaxErrorOrIncomplete(i"indented definitions expected, ${in} found")
12921292
else
12931293
newLineOptWhenFollowedBy(LBRACE)
12941294

@@ -2315,7 +2315,7 @@ object Parsers {
23152315
possibleTemplateStart()
23162316
val parents =
23172317
if in.isNestedStart then Nil
2318-
else constrApps(commaOK = false)
2318+
else constrApp() :: withConstrApps()
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(commaOK = true)
3497+
constrApps()
34983498
}
34993499
else Nil
35003500
Template(constr, parents, Nil, EmptyValDef, Nil)
@@ -3626,24 +3626,37 @@ object Parsers {
36263626
// Using Ident(tpnme.ERROR) to avoid causing cascade errors on non-user-written code
36273627
if in.token == LPAREN then parArgumentExprss(wrapNew(t)) else t
36283628

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

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

36413643
/** `{`with` ConstrApp} but no EOL allowed after `with`.
36423644
*/
36433645
def withConstrApps(): List[Tree] =
36443646
def isTemplateStart =
36453647
val la = in.lookahead
3646-
la.isAfterLineEnd || la.token == LBRACE
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+
}
36473660
if in.token == WITH && !isTemplateStart then
36483661
in.nextToken()
36493662
constrApp() :: withConstrApps()
@@ -3662,7 +3675,7 @@ object Parsers {
36623675
in.sourcePos())
36633676
Nil
36643677
}
3665-
else constrApps(commaOK = true)
3678+
else constrApps()
36663679
}
36673680
else Nil
36683681
newLinesOptWhenFollowedBy(nme.derives)
@@ -3806,7 +3819,16 @@ object Parsers {
38063819
}
38073820
else {
38083821
stats += first
3809-
acceptStatSepUnlessAtEnd(stats)
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)
38103832
}
38113833
}
38123834
var exitOnError = false

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1338,7 +1338,7 @@ object Scanners {
13381338
* InBraces a pair of braces { ... }
13391339
* Indented a pair of <indent> ... <outdent> tokens
13401340
*/
1341-
abstract class Region:
1341+
abstract class Region(val code: String):
13421342
/** The region enclosing this one, or `null` for the outermost region */
13431343
def outer: Region | Null
13441344

@@ -1367,17 +1367,17 @@ object Scanners {
13671367
knownWidth = enclosing.knownWidth
13681368
end Region
13691369

1370-
case class InString(multiLine: Boolean, outer: Region) extends Region
1371-
case class InParens(prefix: Token, outer: Region) extends Region
1372-
case class InBraces(outer: Region) extends Region
1373-
case class InCase(outer: Region) extends Region
1370+
case class InString(multiLine: Boolean, outer: Region) extends Region("IS")
1371+
case class InParens(prefix: Token, outer: Region) extends Region("IP")
1372+
case class InBraces(outer: Region) extends Region("IB")
1373+
case class InCase(outer: Region) extends Region("IC")
13741374

13751375
/** A class describing an indentation region.
13761376
* @param width The principal indendation width
13771377
* @param others Other indendation widths > width of lines in the same region
13781378
* @param prefix The token before the initial <indent> of the region
13791379
*/
1380-
case class Indented(width: IndentWidth, others: Set[IndentWidth], prefix: Token, outer: Region | Null) extends Region:
1380+
case class Indented(width: IndentWidth, others: Set[IndentWidth], prefix: Token, outer: Region | Null) extends Region("II"):
13811381
knownWidth = width
13821382

13831383
def topLevelRegion(width: IndentWidth) = Indented(width, Set(), EMPTY, null)

docs/docs/internals/syntax.md

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ 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"
8786
```
8887

8988
## Keywords
@@ -218,9 +217,8 @@ SimpleExpr ::= SimpleRef
218217
| ‘$’ ‘{’ Block ‘}’
219218
| Quoted
220219
| quoteId -- only inside splices
221-
| ‘new’ ConstrApp {‘with’ ConstrApp} New(constr | templ)
222-
[[colonEol] TemplateBody
223-
| ‘new’ [colonEol] TemplateBody
220+
| ‘new’ ConstrApp {‘with’ ConstrApp} [TemplateBody] New(constr | templ)
221+
| ‘new’ TemplateBody
224222
| ‘(’ ExprsInParens ‘)’ Parens(exprs)
225223
| SimpleExpr ‘.’ id Select(expr, id)
226224
| SimpleExpr ‘.’ MatchClause
@@ -386,23 +384,23 @@ ClassDef ::= id ClassConstr [Template]
386384
ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsParamClauses with DefDef(_, <init>, Nil, vparamss, EmptyTree, EmptyTree) as first stat
387385
ConstrMods ::= {Annotation} [AccessModifier]
388386
ObjectDef ::= id [Template] ModuleDef(mods, name, template) // no constructor
389-
EnumDef ::= id ClassConstr InheritClauses [colonEol] EnumBody
387+
EnumDef ::= id ClassConstr InheritClauses EnumBody
390388
GivenDef ::= [GivenSig] (Type [‘=’ Expr] | StructuralInstance)
391389
GivenSig ::= [id] [DefTypeParamClause] {UsingParamClause} ‘:’ -- one of `id`, `DefParamClause`, `UsingParamClause` must be present
392-
StructuralInstance ::= ConstrApp {‘with’ ConstrApp} ‘with’ TemplateBody
390+
StructuralInstance ::= ConstrApp {‘with’ ConstrApp} TemplateBody
393391
Extension ::= ‘extension’ [DefTypeParamClause] ‘(’ DefParam ‘)’
394392
{UsingParamClause}] ExtMethods
395393
ExtMethods ::= ExtMethod | [nl] ‘{’ ExtMethod {semi ExtMethod ‘}’
396394
ExtMethod ::= {Annotation [nl]} {Modifier} ‘def’ DefDef
397-
Template ::= InheritClauses [colonEol] [TemplateBody] Template(constr, parents, self, stats)
395+
Template ::= InheritClauses [TemplateBody] Template(constr, parents, self, stats)
398396
InheritClauses ::= [‘extends’ ConstrApps] [‘derives’ QualId {‘,’ QualId}]
399397
ConstrApps ::= ConstrApp ({‘,’ ConstrApp} | {‘with’ ConstrApp})
400398
ConstrApp ::= SimpleType1 {Annotation} {ParArgumentExprs} Apply(tp, args)
401399
ConstrExpr ::= SelfInvocation
402400
| ‘{’ SelfInvocation {semi BlockStat} ‘}’
403401
SelfInvocation ::= ‘this’ ArgumentExprs {ArgumentExprs}
404402
405-
TemplateBody ::= [nl] ‘{’ [SelfType] TemplateStat {semi TemplateStat} ‘}’
403+
TemplateBody ::= [nl | ‘with’] ‘{’ [SelfType] TemplateStat {semi TemplateStat} ‘}’
406404
TemplateStat ::= Import
407405
| Export
408406
| {Annotation [nl]} {Modifier} Def
@@ -414,7 +412,7 @@ TemplateStat ::= Import
414412
SelfType ::= id [‘:’ InfixType] ‘=>’ ValDef(_, name, tpt, _)
415413
| ‘this’ ‘:’ InfixType ‘=>’
416414
417-
EnumBody ::= [nl] ‘{’ [SelfType] EnumStat {semi EnumStat} ‘}’
415+
EnumBody ::= [nl | ‘with’] ‘{’ [SelfType] EnumStat {semi EnumStat} ‘}’
418416
EnumStat ::= TemplateStat
419417
| {Annotation [nl]} {Modifier} EnumCase
420418
EnumCase ::= ‘case’ (id ClassConstr [‘extends’ ConstrApps]] | ids)
@@ -428,7 +426,7 @@ TopStat ::= Import
428426
| PackageObject
429427
| EndMarker
430428
|
431-
Packaging ::= ‘package’ QualId [nl | colonEol] ‘{’ TopStatSeq ‘}’ Package(qid, stats)
429+
Packaging ::= ‘package’ QualId [nl| ‘with’] ‘{’ TopStatSeq ‘}’ Package(qid, stats)
432430
PackageObject ::= ‘package’ ‘object’ ObjectDef object with package in mods.
433431
434432
CompilationUnit ::= {‘package’ QualId semi} TopStatSeq Package(qid, stats)

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

Lines changed: 3 additions & 3 deletions
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:
65+
class DivideZero extends StandardPlugin with
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:
72+
class DivideZeroPhase extends PluginPhase with
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:
111+
class DummyResearchPlugin extends ResearchPlugin with
112112
val name: String = "dummy"
113113
override val description: String = "dummy research plugin"
114114

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

Lines changed: 1 addition & 1 deletion
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]:
19+
abstract class Conversion[-T, +U] extends Function1[T, U] with
2020
def apply(x: T): U
2121
```
2222

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

Lines changed: 1 addition & 1 deletion
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:
64+
final class happyBirthday with
6565
import scala.util.{CommandLineParser => CLP}
6666
<static> def main(args: Array[String]): Unit =
6767
try

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

Lines changed: 3 additions & 3 deletions
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):
133+
case class BigFloat(mantissa: BigInt, exponent: Int) with
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:
148+
object BigFloat with
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]:
209+
class FromDigits extends FromDigits.Floating[BigFloat] with
210210
def fromDigits(digits: String) = apply(digits)
211211

212212
given FromDigits with

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

Lines changed: 2 additions & 2 deletions
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:
124+
class FirstChars(s: String) extends Product with
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):
150+
class Nat(val x: Int) with
151151
def get: Int = x
152152
def isEmpty = x < 0
153153

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

Lines changed: 4 additions & 4 deletions
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:
37+
class Record(elems: (String, Any)*) extends Selectable with
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:
85+
class FileInputStream with
8686
def close(): Unit
8787

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

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

Lines changed: 2 additions & 2 deletions
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:
70+
class Table with
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:
75+
class Row with
7676
val cells = new ArrayBuffer[Cell]
7777
def add(c: Cell): Unit = cells += c
7878
override def toString = cells.mkString("Row(", ", ", ")")

0 commit comments

Comments
 (0)