Skip to content

Commit 4732e78

Browse files
committed
Revert "Allow self types after with"
This reverts commit 4da2806.
1 parent 9584970 commit 4732e78

File tree

7 files changed

+40
-131
lines changed

7 files changed

+40
-131
lines changed

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

Lines changed: 32 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,6 @@ object Parsers {
196196
def isTemplateIntro = templateIntroTokens contains in.token
197197
def isDclIntro = dclIntroTokens contains in.token
198198
def isStatSeqEnd = in.isNestedEnd || in.token == EOF || in.token == RPAREN
199-
def isTemplateBodyStart = in.token == WITH || in.isNestedStart
200199
def mustStartStat = mustStartStatTokens contains in.token
201200

202201
/** Is current token a hard or soft modifier (in modifier position or not)? */
@@ -920,39 +919,6 @@ object Parsers {
920919
val next = in.lookahead.token
921920
next == LBRACKET || next == LPAREN
922921

923-
/** Does a template start after `with`? This is the case if either
924-
* - the next token is `{`
925-
* - the `with` is at the end of a line
926-
* (except for source = 3.0-migration, when a warning is issued)
927-
* - the next tokens is `<ident>` or `this` and the one after it is `:` or `=>`
928-
* (i.e. we see the start of a self type)
929-
*/
930-
def followingIsTemplateStart() =
931-
val lookahead = in.LookaheadScanner()
932-
lookahead.nextToken()
933-
lookahead.token == LBRACE
934-
|| lookahead.isAfterLineEnd
935-
&& {
936-
if migrateTo3 then
937-
warning(
938-
em"""In Scala 3, `with` at the end of a line will start definitions,
939-
|so it cannot be used in front of a parent constructor anymore.
940-
|Place the `with` at the beginning of the next line instead.""")
941-
false
942-
else
943-
true
944-
}
945-
|| (lookahead.isIdent || lookahead.token == THIS)
946-
&& {
947-
lookahead.nextToken()
948-
lookahead.token == COLON
949-
&& { // needed only as long as we support significant colon at eol
950-
lookahead.nextToken()
951-
!lookahead.isAfterLineEnd
952-
}
953-
|| lookahead.token == ARROW
954-
}
955-
956922
/* --------- OPERAND/OPERATOR STACK --------------------------------------- */
957923

958924
var opStack: List[OpInfo] = Nil
@@ -1315,14 +1281,14 @@ object Parsers {
13151281
in.sourcePos())
13161282
patch(source, Span(in.offset), " ")
13171283

1318-
def possibleTemplateStart(): Unit =
1284+
def possibleTemplateStart(isNew: Boolean = false): Unit =
13191285
in.observeColonEOL()
1320-
if in.token == COLONEOL then
1286+
if in.token == COLONEOL || in.token == WITH then
13211287
if in.lookahead.isIdent(nme.end) then in.token = NEWLINE
13221288
else
13231289
in.nextToken()
13241290
if in.token != INDENT && in.token != LBRACE then
1325-
syntaxErrorOrIncomplete(ExpectedTokenButFound(INDENT, in.token))
1291+
syntaxErrorOrIncomplete(i"indented definitions expected, ${in} found")
13261292
else
13271293
newLineOptWhenFollowedBy(LBRACE)
13281294

@@ -2347,11 +2313,13 @@ object Parsers {
23472313
val start = in.skipToken()
23482314
def reposition(t: Tree) = t.withSpan(Span(start, in.lastOffset))
23492315
possibleTemplateStart()
2350-
val parents = if isTemplateBodyStart then Nil else constrApp() :: withConstrApps()
2316+
val parents =
2317+
if in.isNestedStart then Nil
2318+
else constrApp() :: withConstrApps()
23512319
colonAtEOLOpt()
2352-
possibleTemplateStart()
2320+
possibleTemplateStart(isNew = true)
23532321
parents match {
2354-
case parent :: Nil if !isTemplateBodyStart =>
2322+
case parent :: Nil if !in.isNestedStart =>
23552323
reposition(if (parent.isType) ensureApplied(wrapNew(parent)) else parent)
23562324
case _ =>
23572325
New(reposition(templateBodyOpt(emptyConstructor, parents, Nil)))
@@ -3675,7 +3643,21 @@ object Parsers {
36753643
/** `{`with` ConstrApp} but no EOL allowed after `with`.
36763644
*/
36773645
def withConstrApps(): List[Tree] =
3678-
if in.token == WITH && !followingIsTemplateStart() then
3646+
def isTemplateStart =
3647+
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+
}
3660+
if in.token == WITH && !isTemplateStart then
36793661
in.nextToken()
36803662
constrApp() :: withConstrApps()
36813663
else Nil
@@ -3719,66 +3701,32 @@ object Parsers {
37193701
template(constr)
37203702
else
37213703
possibleTemplateStart()
3722-
if isTemplateBodyStart then
3704+
if in.isNestedStart then
37233705
template(constr)
37243706
else
37253707
checkNextNotIndented()
37263708
Template(constr, Nil, Nil, EmptyValDef, Nil)
37273709

3728-
/** TemplateBody ::= [nl | ‘with’] `{' TemplateStatSeq `}'
3729-
* | ‘with’ [SelfType] indent TemplateStats outdent
3730-
* EnumBody ::= [nl | ‘with’] ‘{’ [SelfType] EnumStats ‘}’
3731-
* | ‘with’ [SelfType] indent EnumStats outdent
3710+
/** TemplateBody ::= [nl] `{' TemplateStatSeq `}'
3711+
* EnumBody ::= [nl] ‘{’ [SelfType] EnumStat {semi EnumStat} ‘}’
37323712
*/
37333713
def templateBodyOpt(constr: DefDef, parents: List[Tree], derived: List[Tree]): Template =
37343714
val (self, stats) =
3735-
if isTemplateBodyStart then
3715+
if in.isNestedStart then
37363716
templateBody()
37373717
else
37383718
checkNextNotIndented()
37393719
(EmptyValDef, Nil)
37403720
Template(constr, parents, derived, self, stats)
37413721

37423722
def templateBody(): (ValDef, List[Tree]) =
3743-
val givenSelf =
3744-
if in.token == WITH then
3745-
in.nextToken()
3746-
selfDefOpt()
3747-
else EmptyValDef
3748-
val r = inDefScopeBraces(templateStatSeq(givenSelf), rewriteWithColon = true)
3723+
val r = inDefScopeBraces(templateStatSeq(), rewriteWithColon = true)
37493724
if in.token == WITH then
37503725
syntaxError(EarlyDefinitionsNotSupported())
37513726
in.nextToken()
37523727
template(emptyConstructor)
37533728
r
37543729

3755-
/** SelfType ::= id [‘:’ InfixType] ‘=>’
3756-
* | ‘this’ ‘:’ InfixType ‘=>’
3757-
* Only called immediately after a `with`, in which case it must in turn
3758-
* be followed by `INDENT`.
3759-
*/
3760-
def selfDefOpt(): ValDef = atSpan(in.offset) {
3761-
val vd =
3762-
if in.isIdent then
3763-
val selfName = ident()
3764-
if in.token == COLON then
3765-
in.nextToken()
3766-
makeSelfDef(selfName, infixType())
3767-
else
3768-
makeSelfDef(selfName, TypeTree())
3769-
else if in.token == THIS then
3770-
in.nextToken()
3771-
accept(COLON)
3772-
makeSelfDef(nme.WILDCARD, infixType())
3773-
else
3774-
EmptyValDef
3775-
if !vd.isEmpty then
3776-
accept(ARROW)
3777-
if in.token != INDENT then
3778-
syntaxErrorOrIncomplete(ExpectedTokenButFound(INDENT, in.token))
3779-
vd
3780-
}
3781-
37823730
/** with Template, with EOL <indent> interpreted */
37833731
def withTemplate(constr: DefDef, parents: List[Tree]): Template =
37843732
if in.token != WITH then syntaxError(em"`with` expected")
@@ -3852,10 +3800,10 @@ object Parsers {
38523800
* EnumStat ::= TemplateStat
38533801
* | Annotations Modifiers EnumCase
38543802
*/
3855-
def templateStatSeq(givenSelf: ValDef = EmptyValDef): (ValDef, List[Tree]) = checkNoEscapingPlaceholders {
3856-
var self = givenSelf
3803+
def templateStatSeq(): (ValDef, List[Tree]) = checkNoEscapingPlaceholders {
3804+
var self: ValDef = EmptyValDef
38573805
val stats = new ListBuffer[Tree]
3858-
if (self.isEmpty && isExprIntro && !isDefIntro(modifierTokens)) {
3806+
if (isExprIntro && !isDefIntro(modifierTokens)) {
38593807
val first = expr1()
38603808
if (in.token == ARROW) {
38613809
first match {
@@ -4008,7 +3956,7 @@ object Parsers {
40083956
possibleTemplateStart()
40093957
if in.token == EOF then
40103958
ts += makePackaging(start, pkg, List())
4011-
else if isTemplateBodyStart then
3959+
else if in.isNestedStart then
40123960
ts += inDefScopeBraces(makePackaging(start, pkg, topStatSeq()), rewriteWithColon = true)
40133961
continue = true
40143962
else
@@ -4046,7 +3994,6 @@ object Parsers {
40463994
}
40473995

40483996
override def templateBody(): (ValDef, List[Thicket]) = {
4049-
if in.token == WITH then in.nextToken()
40503997
skipBraces()
40513998
(EmptyValDef, List(EmptyTree))
40523999
}

compiler/src/dotty/tools/dotc/reporting/messages.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1126,7 +1126,6 @@ import transform.SymUtils._
11261126
def msg =
11271127
val expectedText =
11281128
if (Tokens.isIdentifier(expected)) "an identifier"
1129-
else if expected == Tokens.INDENT then "indented definitions"
11301129
else Tokens.showToken(expected)
11311130
em"""${expectedText} expected, but ${foundText} found"""
11321131

docs/docs/internals/syntax.md

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ FunParamClause ::= ‘(’ TypedFunParam {‘,’ TypedFunParam } ‘)’
148148
TypedFunParam ::= id ‘:’ Type
149149
MatchType ::= InfixType `match` ‘{’ TypeCaseClauses ‘}’
150150
InfixType ::= RefinedType {id [nl] RefinedType} InfixOp(t1, op, t2)
151-
RefinedType ::= WithType {[nl | ‘with’] Refinement} RefinedTypeTree(t, ds)
151+
RefinedType ::= WithType {[nl] Refinement} RefinedTypeTree(t, ds)
152152
WithType ::= AnnotType {‘with’ AnnotType} (deprecated)
153153
AnnotType ::= SimpleType {Annotation} Annotated(t, annot)
154154
@@ -401,7 +401,6 @@ ConstrExpr ::= SelfInvocation
401401
SelfInvocation ::= ‘this’ ArgumentExprs {ArgumentExprs}
402402
403403
TemplateBody ::= [nl | ‘with’] ‘{’ [SelfType] TemplateStat {semi TemplateStat} ‘}’
404-
| ‘with’ [SelfType] indent TemplateStats outdent
405404
TemplateStat ::= Import
406405
| Export
407406
| {Annotation [nl]} {Modifier} Def
@@ -413,9 +412,7 @@ TemplateStat ::= Import
413412
SelfType ::= id [‘:’ InfixType] ‘=>’ ValDef(_, name, tpt, _)
414413
| ‘this’ ‘:’ InfixType ‘=>’
415414
416-
EnumBody ::= [nl | ‘with’] ‘{’ [SelfType] EnumStats ‘}’
417-
| ‘with’ [SelfType] indent EnumStats outdent
418-
EnumStats ::= EnumStat {semi EnumStat}
415+
EnumBody ::= [nl | ‘with’] ‘{’ [SelfType] EnumStat {semi EnumStat} ‘}’
419416
EnumStat ::= TemplateStat
420417
| {Annotation [nl]} {Modifier} EnumCase
421418
EnumCase ::= ‘case’ (id ClassConstr [‘extends’ ConstrApps]] | ids)

tests/neg/with-template.check

Lines changed: 0 additions & 22 deletions
This file was deleted.

tests/neg/with-template.scala

Lines changed: 0 additions & 14 deletions
This file was deleted.

tests/pos/i10080.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
1+
trait Foo with
2+
end Foo
3+
14
trait Bar
25
end Bar

tests/pos/indent.scala

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ object Test with
8282
x < 10
8383
do ()
8484

85-
class Test2 with self: Test2 =>
85+
class Test2 with
86+
self =>
8687
def foo(x: Int) =
8788
if x < 0 then throw
8889
val ex = new AssertionError()
@@ -97,11 +98,9 @@ class Test2 with self: Test2 =>
9798
end Test2
9899

99100
class Test3 with
100-
self =>
101+
self =>
101102
def foo = 1
102103

103-
class Test4 with { val x = 5 }
104-
105104
import collection.mutable.HashMap
106105

107106
class Coder(words: List[String]) with

0 commit comments

Comments
 (0)