Skip to content

Commit 9ab1842

Browse files
authored
Merge pull request #8009 from dotty-staging/class-syntax-colon
Drop "extended with" syntax
2 parents 58cc3f6 + 10b7c63 commit 9ab1842

Some content is hidden

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

48 files changed

+311
-281
lines changed

compiler/src/dotty/tools/dotc/core/StdNames.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,6 @@ object StdNames {
457457
val eval: N = "eval"
458458
val eqlAny: N = "eqlAny"
459459
val ex: N = "ex"
460-
val extended: N = "extended"
461460
val extension: N = "extension"
462461
val experimental: N = "experimental"
463462
val f: N = "f"

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

Lines changed: 74 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -913,7 +913,10 @@ object Parsers {
913913
lookahead.nextToken()
914914
if lookahead.token == IDENTIFIER then
915915
lookahead.nextToken()
916-
lookahead.token == COLON
916+
if lookahead.token == COLON then
917+
lookahead.nextToken()
918+
!lookahead.isAfterLineEnd
919+
else false
917920
else false
918921
else false
919922

@@ -943,7 +946,10 @@ object Parsers {
943946
lookahead.nextToken()
944947
while lookahead.token == LPAREN || lookahead.token == LBRACKET do
945948
lookahead.skipParens()
946-
lookahead.token == COLON || lookahead.token == SUBTYPE
949+
if lookahead.token == COLON then
950+
lookahead.nextToken()
951+
!lookahead.isAfterLineEnd
952+
else lookahead.token == SUBTYPE
947953

948954
def followingIsExtension() =
949955
val lookahead = in.LookaheadScanner()
@@ -1304,7 +1310,12 @@ object Parsers {
13041310
}
13051311

13061312
def possibleTemplateStart(isNew: Boolean = false): Unit =
1307-
if in.token == WITH then
1313+
in.observeColonEOL()
1314+
if in.token == COLONEOL then
1315+
in.nextToken()
1316+
if in.token != INDENT then
1317+
syntaxError(i"indented definitions expected")
1318+
else if in.token == WITH then
13081319
in.nextToken()
13091320
if in.token != LBRACE && in.token != INDENT then
13101321
syntaxError(i"indented definitions or `{` expected")
@@ -1458,7 +1469,7 @@ object Parsers {
14581469
def infixTypeRest(t: Tree): Tree =
14591470
infixOps(t, canStartTypeTokens, refinedType, isType = true, isOperator = !isPostfixStar)
14601471

1461-
/** RefinedType ::= WithType {[nl | `with'] Refinement}
1472+
/** RefinedType ::= WithType {[nl] Refinement}
14621473
*/
14631474
val refinedType: () => Tree = () => refinedTypeRest(withType())
14641475

@@ -2082,7 +2093,8 @@ object Parsers {
20822093
}
20832094
else simpleExpr()
20842095

2085-
/** SimpleExpr ::= ‘new’ (ConstrApp [[‘with’] TemplateBody] | TemplateBody)
2096+
/** SimpleExpr ::= ‘new’ ConstrApp {`with` ConstrApp} [TemplateBody]
2097+
* | ‘new’ TemplateBody
20862098
* | BlockExpr
20872099
* | ‘$’ ‘{’ Block ‘}’
20882100
* | Quoted
@@ -2177,7 +2189,7 @@ object Parsers {
21772189
}
21782190
}
21792191

2180-
/** SimpleExpr ::= ‘new’ ConstrApp {`with` ConstrApp} [[‘with’] TemplateBody]
2192+
/** SimpleExpr ::= ‘new’ ConstrApp {`with` ConstrApp} [TemplateBody]
21812193
* | ‘new’ TemplateBody
21822194
*/
21832195
def newExpr(): Tree =
@@ -3352,7 +3364,7 @@ object Parsers {
33523364
syntaxError(s"Only access modifiers are allowed on enum $where")
33533365
mods1
33543366

3355-
/** EnumDef ::= id ClassConstr InheritClauses [‘with’] EnumBody
3367+
/** EnumDef ::= id ClassConstr InheritClauses EnumBody
33563368
*/
33573369
def enumDef(start: Offset, mods: Modifiers): TypeDef = atSpan(start, nameStart) {
33583370
val mods1 = checkAccessOnly(mods, "definitions")
@@ -3415,8 +3427,7 @@ object Parsers {
34153427
}
34163428

34173429
/** GivenDef ::= [GivenSig (‘:’ | <:)] {FunArgTypes ‘=>’} AnnotType ‘=’ Expr
3418-
* | [GivenSig ‘:’] {FunArgTypes ‘=>’} ConstrApps [[‘with’] TemplateBody]
3419-
* | [id ‘:’] ExtParamClause {GivenParamClause} ‘extended’ ‘with’ ExtMethods
3430+
* | [GivenSig ‘:’] {FunArgTypes ‘=>’} ConstrApps [TemplateBody]
34203431
* GivenSig ::= [id] [DefTypeParamClause] {GivenParamClause}
34213432
* ExtParamClause ::= [DefTypeParamClause] DefParamClause
34223433
* ExtMethods ::= [nl] ‘{’ ‘def’ DefDef {semi ‘def’ DefDef} ‘}’
@@ -3458,83 +3469,68 @@ object Parsers {
34583469
if in.token == LPAREN && followingIsParamOrGivenType()
34593470
then paramClauses() // todo: ONLY admit a single paramClause
34603471
else Nil
3461-
val isExtension = isIdent(nme.extended)
34623472
def checkAllGivens(vparamss: List[List[ValDef]], what: String) =
34633473
vparamss.foreach(_.foreach(vparam =>
34643474
if !vparam.mods.is(Given) then syntaxError(em"$what must be `given`", vparam.span)))
3465-
if isExtension then
3466-
if !name.isEmpty && !hasLabel then
3467-
syntaxError(em"name $name of extension clause must be followed by `:`", nameStart)
3468-
vparamss match
3469-
case (vparam :: Nil) :: vparamss1 if !vparam.mods.is(Given) =>
3470-
checkAllGivens(vparamss1, "follow-on parameter in extension clause")
3471-
case _ =>
3472-
syntaxError("extension clause must start with a single regular parameter", paramsStart)
3473-
in.nextToken()
3474-
accept(WITH)
3475-
val (self, stats) = templateBody()
3476-
stats.foreach(checkExtensionMethod(tparams, _))
3477-
ModuleDef(name, Template(makeConstructor(tparams, vparamss), Nil, Nil, self, stats))
3478-
else
3479-
def makeGiven(params: List[ValDef]): List[ValDef] =
3480-
params.map(param => param.withMods(param.mods | Given))
3481-
def conditionalParents(): List[Tree] =
3482-
accept(ARROW)
3483-
if in.token == LPAREN && followingIsParam() then
3484-
vparamss = vparamss :+ makeGiven(paramClause(vparamss.flatten.length))
3485-
conditionalParents()
3486-
else
3487-
val constrs = constrApps(commaOK = true, templateCanFollow = true)
3488-
if in.token == ARROW && constrs.forall(_.isType) then
3489-
vparamss = vparamss
3490-
:+ typesToGivenParams(constrs, ofClass = false, vparamss.flatten.length)
3491-
conditionalParents()
3492-
else constrs
3493-
3494-
val isConditional =
3495-
in.token == ARROW
3496-
&& vparamss.length == 1
3497-
&& (hasLabel || name.isEmpty && tparams.isEmpty)
3498-
if !isConditional then checkAllGivens(vparamss, "parameter of given instance")
3499-
val parents =
3500-
if in.token == SUBTYPE && !hasLabel then
3501-
if !mods.is(Inline) then
3502-
syntaxError("`<:` is only allowed for given with `inline` modifier")
3503-
in.nextToken()
3504-
TypeBoundsTree(EmptyTree, annotType()) :: Nil
3505-
else if isConditional then
3506-
vparamss = vparamss.map(makeGiven)
3475+
def makeGiven(params: List[ValDef]): List[ValDef] =
3476+
params.map(param => param.withMods(param.mods | Given))
3477+
def conditionalParents(): List[Tree] =
3478+
accept(ARROW)
3479+
if in.token == LPAREN && followingIsParam() then
3480+
vparamss = vparamss :+ makeGiven(paramClause(vparamss.flatten.length))
3481+
conditionalParents()
3482+
else
3483+
val constrs = constrApps(commaOK = true, templateCanFollow = true)
3484+
if in.token == ARROW && constrs.forall(_.isType) then
3485+
vparamss = vparamss
3486+
:+ typesToGivenParams(constrs, ofClass = false, vparamss.flatten.length)
35073487
conditionalParents()
3508-
else
3509-
if !hasLabel && !(name.isEmpty && tparams.isEmpty && vparamss.isEmpty) then
3510-
accept(COLON)
3511-
val constrs = constrApps(commaOK = true, templateCanFollow = true)
3512-
if in.token == ARROW && vparamss.isEmpty && constrs.forall(_.isType) then
3513-
vparamss = typesToGivenParams(constrs, ofClass = false, 0) :: Nil
3514-
conditionalParents()
3515-
else
3516-
constrs
3517-
3518-
if in.token == EQUALS && parents.length == 1 && parents.head.isType then
3488+
else constrs
3489+
3490+
val isConditional =
3491+
in.token == ARROW
3492+
&& vparamss.length == 1
3493+
&& (hasLabel || name.isEmpty && tparams.isEmpty)
3494+
if !isConditional then checkAllGivens(vparamss, "parameter of given instance")
3495+
val parents =
3496+
if in.token == SUBTYPE && !hasLabel then
3497+
if !mods.is(Inline) then
3498+
syntaxError("`<:` is only allowed for given with `inline` modifier")
35193499
in.nextToken()
3520-
mods1 |= Final
3521-
DefDef(name, tparams, vparamss, parents.head, subExpr())
3500+
TypeBoundsTree(EmptyTree, annotType()) :: Nil
3501+
else if isConditional then
3502+
vparamss = vparamss.map(makeGiven)
3503+
conditionalParents()
35223504
else
3523-
parents match
3524-
case TypeBoundsTree(_, _) :: _ => syntaxError("`=` expected")
3525-
case _ =>
3526-
possibleTemplateStart()
3527-
val tparams1 = tparams.map(tparam => tparam.withMods(tparam.mods | PrivateLocal))
3528-
val vparamss1 = vparamss.map(_.map(vparam =>
3529-
vparam.withMods(vparam.mods &~ Param | ParamAccessor | PrivateLocal)))
3530-
val templ = templateBodyOpt(makeConstructor(tparams1, vparamss1), parents, Nil)
3531-
if tparams.isEmpty && vparamss.isEmpty then ModuleDef(name, templ)
3532-
else TypeDef(name.toTypeName, templ)
3505+
if !hasLabel && !(name.isEmpty && tparams.isEmpty && vparamss.isEmpty) then
3506+
accept(COLON)
3507+
val constrs = constrApps(commaOK = true, templateCanFollow = true)
3508+
if in.token == ARROW && vparamss.isEmpty && constrs.forall(_.isType) then
3509+
vparamss = typesToGivenParams(constrs, ofClass = false, 0) :: Nil
3510+
conditionalParents()
3511+
else
3512+
constrs
3513+
3514+
if in.token == EQUALS && parents.length == 1 && parents.head.isType then
3515+
in.nextToken()
3516+
mods1 |= Final
3517+
DefDef(name, tparams, vparamss, parents.head, subExpr())
3518+
else
3519+
parents match
3520+
case TypeBoundsTree(_, _) :: _ => syntaxError("`=` expected")
3521+
case _ =>
3522+
possibleTemplateStart()
3523+
val tparams1 = tparams.map(tparam => tparam.withMods(tparam.mods | PrivateLocal))
3524+
val vparamss1 = vparamss.map(_.map(vparam =>
3525+
vparam.withMods(vparam.mods &~ Param | ParamAccessor | PrivateLocal)))
3526+
val templ = templateBodyOpt(makeConstructor(tparams1, vparamss1), parents, Nil)
3527+
if tparams.isEmpty && vparamss.isEmpty then ModuleDef(name, templ)
3528+
else TypeDef(name.toTypeName, templ)
35333529
}
35343530
finalizeDef(gdef, mods1, start)
35353531
}
35363532

3537-
/** ExtensionDef ::= [id] ‘of’ ExtParamClause {GivenParamClause} ‘with’ ExtMethods
3533+
/** ExtensionDef ::= [id] ‘on’ ExtParamClause {GivenParamClause} ExtMethods
35383534
*/
35393535
def extensionDef(start: Offset, mods: Modifiers): ModuleDef =
35403536
in.nextToken()
@@ -3580,7 +3576,7 @@ object Parsers {
35803576
else Nil
35813577
t :: ts
35823578

3583-
/** Template ::= InheritClauses [[‘with’] TemplateBody]
3579+
/** Template ::= InheritClauses [TemplateBody]
35843580
* InheritClauses ::= [‘extends’ ConstrApps] [‘derives’ QualId {‘,’ QualId}]
35853581
*/
35863582
def template(constr: DefDef, isEnum: Boolean = false): Template = {
@@ -3650,7 +3646,7 @@ object Parsers {
36503646
case x: RefTree => atSpan(start, pointOffset(pkg))(PackageDef(x, stats))
36513647
}
36523648

3653-
/** Packaging ::= package QualId [nl | `with'] `{' TopStatSeq `}'
3649+
/** Packaging ::= package QualId [nl] `{' TopStatSeq `}'
36543650
*/
36553651
def packaging(start: Int): Tree = {
36563652
val pkg = qualId()

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

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,13 @@ object Scanners {
550550
|Previous indent : $lastWidth
551551
|Latest indent : $nextWidth"""
552552

553+
def observeColonEOL(): Unit =
554+
if token == COLON then
555+
lookahead()
556+
val atEOL = isAfterLineEnd
557+
reset()
558+
if atEOL then token = COLONEOL
559+
553560
def observeIndented(): Unit =
554561
if indentSyntax && isNewLine then
555562
val nextWidth = indentWidth(next.offset)
@@ -575,19 +582,21 @@ object Scanners {
575582
insert(OUTDENT, offset)
576583
case _ =>
577584

585+
def lookahead() = {
586+
prev.copyFrom(this)
587+
lastOffset = lastCharOffset
588+
fetchToken()
589+
}
590+
591+
def reset() = {
592+
next.copyFrom(this)
593+
this.copyFrom(prev)
594+
}
595+
578596
/** - Join CASE + CLASS => CASECLASS, CASE + OBJECT => CASEOBJECT, SEMI + ELSE => ELSE, COLON + <EOL> => COLONEOL
579597
* - Insert missing OUTDENTs at EOF
580598
*/
581599
def postProcessToken(): Unit = {
582-
def lookahead() = {
583-
prev.copyFrom(this)
584-
lastOffset = lastCharOffset
585-
fetchToken()
586-
}
587-
def reset() = {
588-
next.copyFrom(this)
589-
this.copyFrom(prev)
590-
}
591600
def fuse(tok: Int) = {
592601
token = tok
593602
offset = prev.offset
@@ -611,10 +620,7 @@ object Scanners {
611620
/* skip the trailing comma */
612621
} else reset()
613622
case COLON =>
614-
lookahead()
615-
val atEOL = isAfterLineEnd
616-
reset()
617-
if (colonSyntax && atEOL) token = COLONEOL
623+
if colonSyntax then observeColonEOL()
618624
case EOF | RBRACE =>
619625
currentRegion match {
620626
case r: Indented if !r.isOutermost =>

docs/docs/internals/syntax.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ FunArgTypes ::= InfixType
149149
TypedFunParam ::= id ‘:’ Type
150150
MatchType ::= InfixType `match` ‘{’ TypeCaseClauses ‘}’
151151
InfixType ::= RefinedType {id [nl] RefinedType} InfixOp(t1, op, t2)
152-
RefinedType ::= WithType {[nl | ‘with’] Refinement} RefinedTypeTree(t, ds)
152+
RefinedType ::= WithType {[nl] Refinement} RefinedTypeTree(t, ds)
153153
WithType ::= AnnotType {‘with’ AnnotType} (deprecated)
154154
AnnotType ::= SimpleType {Annotation} Annotated(t, annot)
155155
SimpleType ::= SimpleType TypeArgs AppliedTypeTree(t, args)
@@ -214,7 +214,7 @@ SimpleExpr ::= Path
214214
| ‘$’ ‘{’ Block ‘}’
215215
| Quoted
216216
| quoteId // only inside splices
217-
| ‘new’ ConstrApp {‘with’ ConstrApp} [[‘with’] TemplateBody] New(constr | templ)
217+
| ‘new’ ConstrApp {‘with’ ConstrApp} [TemplateBody] New(constr | templ)
218218
| ‘new’ TemplateBody
219219
| ‘(’ ExprsInParens ‘)’ Parens(exprs)
220220
| SimpleExpr ‘.’ id Select(expr, id)
@@ -383,16 +383,16 @@ ClassDef ::= id ClassConstr [Template]
383383
ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsParamClauses with DefDef(_, <init>, Nil, vparamss, EmptyTree, EmptyTree) as first stat
384384
ConstrMods ::= {Annotation} [AccessModifier]
385385
ObjectDef ::= id [Template] ModuleDef(mods, name, template) // no constructor
386-
EnumDef ::= id ClassConstr InheritClauses [‘with’] EnumBody EnumDef(mods, name, tparams, template)
386+
EnumDef ::= id ClassConstr InheritClauses EnumBody EnumDef(mods, name, tparams, template)
387387
GivenDef ::= [GivenSig (‘:’ | <:)] {FunArgTypes ‘=>’}
388388
AnnotType ‘=’ Expr
389389
| [GivenSig ‘:’] {FunArgTypes ‘=>’}
390-
ConstrApps [[‘with’] TemplateBody]
390+
ConstrApps [TemplateBody]
391391
GivenSig ::= [id] [DefTypeParamClause] {GivenParamClause}
392-
ExtensionDef ::= [id] ‘of’ ExtParamClause {GivenParamClause} ExtMethods
392+
ExtensionDef ::= [id] ‘on’ ExtParamClause {GivenParamClause} ExtMethods
393393
ExtMethods ::= [nl] ‘{’ ‘def’ DefDef {semi ‘def’ DefDef} ‘}’
394394
ExtParamClause ::= [DefTypeParamClause] ‘(’ DefParam ‘)’
395-
Template ::= InheritClauses [[‘with’] TemplateBody] Template(constr, parents, self, stats)
395+
Template ::= InheritClauses [TemplateBody] Template(constr, parents, self, stats)
396396
InheritClauses ::= [‘extends’ ConstrApps] [‘derives’ QualId {‘,’ QualId}]
397397
ConstrApps ::= ConstrApp {(‘,’ | ‘with’) ConstrApp}
398398
ConstrApp ::= AnnotType {ParArgumentExprs} Apply(tp, args)
@@ -410,7 +410,7 @@ TemplateStat ::= Import
410410
SelfType ::= id [‘:’ InfixType] ‘=>’ ValDef(_, name, tpt, _)
411411
| ‘this’ ‘:’ InfixType ‘=>’
412412
413-
EnumBody ::= [nl | ‘with’] ‘{’ [SelfType] EnumStat {semi EnumStat} ‘}’
413+
EnumBody ::= [nl] ‘{’ [SelfType] EnumStat {semi EnumStat} ‘}’
414414
EnumStat ::= TemplateStat
415415
| {Annotation [nl]} {Modifier} EnumCase
416416
EnumCase ::= ‘case’ (id ClassConstr [‘extends’ ConstrApps]] | ids)
@@ -422,7 +422,7 @@ TopStat ::= Import
422422
| Packaging
423423
| PackageObject
424424
|
425-
Packaging ::= ‘package’ QualId [nl | ‘with’] ‘{’ TopStatSeq ‘}’ Package(qid, stats)
425+
Packaging ::= ‘package’ QualId [nl] ‘{’ TopStatSeq ‘}’ Package(qid, stats)
426426
PackageObject ::= ‘package’ ‘object’ ObjectDef object with package in mods.
427427
428428
CompilationUnit ::= {‘package’ QualId semi} TopStatSeq Package(qid, stats)

docs/docs/reference/other-new-features/opaques.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ object Logarithms {
2020
}
2121

2222
// Extension methods define opaque types' public APIs
23-
given logarithmOps: (x: Logarithm) extended with {
23+
extension logarithmOps on (x: Logarithm) {
2424
def toDouble: Double = math.exp(x)
2525
def + (y: Logarithm): Logarithm = Logarithm(math.exp(x) + math.exp(y))
2626
def * (y: Logarithm): Logarithm = x + y

0 commit comments

Comments
 (0)