Skip to content

Commit d431149

Browse files
committed
Make treatment of do language version dependent
`do` can start an expression or a statement only under -language:Scala2. Maintaining this distinction is important in order not to insert spurious newlines in front of `do` in a `while` or `for`.
1 parent ebcc91d commit d431149

File tree

5 files changed

+46
-26
lines changed

5 files changed

+46
-26
lines changed

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

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ object Parsers {
207207
} && !in.isSoftModifierInModifierPosition
208208

209209
def isExprIntro: Boolean =
210-
canStartExpressionTokens.contains(in.token) && !in.isSoftModifierInModifierPosition
210+
in.canStartExprTokens.contains(in.token) && !in.isSoftModifierInModifierPosition
211211

212212
def isDefIntro(allowedMods: BitSet, excludedSoftModifiers: Set[TermName] = Set.empty): Boolean =
213213
in.token == AT ||
@@ -1655,11 +1655,13 @@ object Parsers {
16551655
}
16561656

16571657
/** A then part can start after `)` if the next token can start a statement
1658-
* and is not a leading infix operator.
1658+
* and is not a leading infix operator. In Scala-2 mode, a then part always
1659+
* starts after `)`.
16591660
*/
16601661
def canStartThenPart =
1661-
canStartStatTokens.contains(in.token)
1662-
&& !in.isLeadingInfixOperator(inConditional = true)
1662+
in.isScala2Mode
1663+
|| canStartStatTokens3.contains(in.token)
1664+
&& !in.isLeadingInfixOperator(inConditional = true)
16631665

16641666
/** Does the current conditional expression continue after
16651667
* the initially parsed (...) region?
@@ -1891,20 +1893,20 @@ object Parsers {
18911893
}
18921894
}
18931895
case _ =>
1894-
if (isIdent(nme.inline) && !in.inModifierPosition() && in.lookaheadIn(canStartExpressionTokens)) {
1896+
if isIdent(nme.inline)
1897+
&& !in.inModifierPosition()
1898+
&& in.lookaheadIn(in.canStartExprTokens)
1899+
then
18951900
val start = in.skipToken()
1896-
in.token match {
1901+
in.token match
18971902
case IF =>
18981903
ifExpr(start, InlineIf)
18991904
case _ =>
19001905
val t = postfixExpr()
19011906
if (in.token == MATCH) matchExpr(t, start, InlineMatch)
1902-
else {
1907+
else
19031908
syntaxErrorOrIncomplete(i"`match` or `if` expected but ${in.token} found")
19041909
t
1905-
}
1906-
}
1907-
}
19081910
else expr1Rest(postfixExpr(), location)
19091911
}
19101912

@@ -2051,7 +2053,7 @@ object Parsers {
20512053
def postfixExpr(): Tree = postfixExprRest(prefixExpr())
20522054

20532055
def postfixExprRest(t: Tree): Tree =
2054-
infixOps(t, canStartExpressionTokens, prefixExpr, maybePostfix = true)
2056+
infixOps(t, in.canStartExprTokens, prefixExpr, maybePostfix = true)
20552057

20562058
/** PrefixExpr ::= [`-' | `+' | `~' | `!'] SimpleExpr
20572059
*/
@@ -2248,7 +2250,7 @@ object Parsers {
22482250
lookahead.nextToken()
22492251
lookahead.token != COLON
22502252
}
2251-
else canStartExpressionTokens.contains(lookahead.token)
2253+
else in.canStartExprTokens.contains(lookahead.token)
22522254
}
22532255
}
22542256
if (in.token == LPAREN && (!inClassConstrAnnots || isLegalAnnotArg))
@@ -2523,7 +2525,7 @@ object Parsers {
25232525
/** InfixPattern ::= SimplePattern {id [nl] SimplePattern}
25242526
*/
25252527
def infixPattern(): Tree =
2526-
infixOps(simplePattern(), canStartExpressionTokens, simplePattern, isOperator = in.name != nme.raw.BAR)
2528+
infixOps(simplePattern(), in.canStartExprTokens, simplePattern, isOperator = in.name != nme.raw.BAR)
25272529

25282530
/** SimplePattern ::= PatVar
25292531
* | Literal

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

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -495,10 +495,11 @@ object Scanners {
495495
indentPrefix = LBRACE
496496
case _ =>
497497
}
498-
if (newlineIsSeparating &&
499-
canEndStatTokens.contains(lastToken) &&
500-
canStartStatTokens.contains(token) &&
501-
!isLeadingInfixOperator())
498+
if newlineIsSeparating
499+
&& canEndStatTokens.contains(lastToken)
500+
&& canStartStatTokens.contains(token)
501+
&& !isLeadingInfixOperator()
502+
then
502503
insert(if (pastBlankLine) NEWLINES else NEWLINE, lineOffset)
503504
else if indentIsSignificant then
504505
if nextWidth < lastWidth
@@ -1001,6 +1002,12 @@ object Scanners {
10011002
def isNestedStart = token == LBRACE || token == INDENT
10021003
def isNestedEnd = token == RBRACE || token == OUTDENT
10031004

1005+
def canStartStatTokens =
1006+
if isScala2Mode then canStartStatTokens2 else canStartStatTokens3
1007+
1008+
def canStartExprTokens =
1009+
if isScala2Mode then canStartExprTokens2 else canStartExprTokens3
1010+
10041011
// Literals -----------------------------------------------------------------
10051012

10061013
private def getStringLit() = {

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,10 @@ object Tokens extends TokensCommon {
219219
final val atomicExprTokens: TokenSet = literalTokens | identifierTokens | BitSet(
220220
USCORE, NULL, THIS, SUPER, TRUE, FALSE, RETURN, QUOTEID, XMLSTART)
221221

222-
final val canStartExpressionTokens: TokenSet = atomicExprTokens | BitSet(
223-
LBRACE, LPAREN, INDENT, QUOTE, IF, DO, WHILE, FOR, NEW, TRY, THROW)
222+
final val canStartExprTokens3: TokenSet = atomicExprTokens | BitSet(
223+
LBRACE, LPAREN, INDENT, QUOTE, IF, WHILE, FOR, NEW, TRY, THROW)
224+
225+
final val canStartExprTokens2: TokenSet = canStartExprTokens3 | BitSet(DO)
224226

225227
final val canStartTypeTokens: TokenSet = literalTokens | identifierTokens | BitSet(
226228
THIS, SUPER, USCORE, LPAREN, AT)
@@ -247,7 +249,9 @@ object Tokens extends TokensCommon {
247249
/** Is token only legal as start of statement (eof also included)? */
248250
final val mustStartStatTokens: TokenSet = defIntroTokens | modifierTokens | BitSet(IMPORT, EXPORT, PACKAGE)
249251

250-
final val canStartStatTokens: TokenSet = canStartExpressionTokens | mustStartStatTokens | BitSet(
252+
final val canStartStatTokens2: TokenSet = canStartExprTokens2 | mustStartStatTokens | BitSet(
253+
AT, CASE)
254+
final val canStartStatTokens3: TokenSet = canStartExprTokens3 | mustStartStatTokens | BitSet(
251255
AT, CASE)
252256

253257
final val canEndStatTokens: TokenSet = atomicExprTokens | BitSet(
@@ -285,10 +289,6 @@ object Tokens extends TokensCommon {
285289
*/
286290
final val startParamOrGivenTypeTokens: BitSet = startParamTokens | BitSet(GIVEN, ERASED)
287291

288-
final val noIndentTemplateTokens = BitSet(EXTENDS)
289-
final val noIndentAfterConditionTokens = BitSet(THEN, DO)
290-
final val noIndentAfterEnumeratorTokens = BitSet(YIELD, DO)
291-
292292
final val scala3keywords = BitSet(ENUM, ERASED, GIVEN)
293293

294294
final val softModifierNames = Set(nme.inline, nme.opaque)

compiler/src/dotty/tools/dotc/util/kwords.sc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ object kwords {
1313
//| atch, lazy, then, forSome, _, :, =, <-, =>, ';', ';', <:, >:, #, @, <%)
1414
keywords.toList.filter(kw => tokenString(kw) == null)
1515
//> res1: List[Int] = List()
16-
canStartStatTokens contains CASE //> res2: Boolean = false
17-
16+
canStartStatTokens3 contains CASE //> res2: Boolean = false
17+
1818
}

tests/pos/indent4.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,14 @@ object testindent
2222
val y = x
2323
println(y)
2424

25+
while true
26+
do println(1)
27+
28+
for i <- List(1, 2, 3)
29+
do println(i)
30+
31+
while (true)
32+
do println(1)
33+
34+
for (i <- List(1, 2, 3))
35+
do println(i)

0 commit comments

Comments
 (0)