Skip to content

Commit 9fd873c

Browse files
committed
Revert "Disallow : after infix operators"
This reverts commit 0bd9739. Change syntax and tests to allow `:` after operator. It turns out that the intent project of the CB already uses them in a way that looks quite reasonable.
1 parent 8cd6337 commit 9fd873c

File tree

6 files changed

+60
-39
lines changed

6 files changed

+60
-39
lines changed

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -934,6 +934,7 @@ object Parsers {
934934
val op = if (isType) typeIdent() else termIdent()
935935
val top1 = reduceStack(base, top, precedence(op.name), !op.name.isRightAssocOperatorName, op.name, isType)
936936
opStack = OpInfo(top1, op, in.offset) :: opStack
937+
colonAtEOLOpt()
937938
newLineOptWhenFollowing(canStartOperand)
938939
if (maybePostfix && !canStartOperand(in.token)) {
939940
val topInfo = opStack.head
@@ -2160,6 +2161,7 @@ object Parsers {
21602161
/** PostfixExpr ::= InfixExpr [id [nl]]
21612162
* InfixExpr ::= PrefixExpr
21622163
* | InfixExpr id [nl] InfixExpr
2164+
* | InfixExpr id `:` IndentedExpr
21632165
* | InfixExpr MatchClause
21642166
*/
21652167
def postfixExpr(location: Location = Location.ElseWhere): Tree =
@@ -2203,8 +2205,9 @@ object Parsers {
22032205
* | SimpleExpr `.` MatchClause
22042206
* | SimpleExpr (TypeArgs | NamedTypeArgs)
22052207
* | SimpleExpr1 ArgumentExprs
2206-
* | SimpleExpr1 :<<< (CaseClauses | Block) >>> -- under language.experimental.fewerBraces
2207-
* | SimpleExpr1 FunParams (‘=>’ | ‘?=>’) indent Block outdent -- under language.experimental.fewerBraces
2208+
* | SimpleExpr1 `:` IndentedExpr -- under language.experimental.fewerBraces
2209+
* | SimpleExpr1 FunParams (‘=>’ | ‘?=>’) IndentedExpr -- under language.experimental.fewerBraces
2210+
* IndentedExpr ::= indent (CaseClauses | Block) outdent
22082211
* Quoted ::= ‘'’ ‘{’ Block ‘}’
22092212
* | ‘'’ ‘[’ Type ‘]’
22102213
*/
@@ -2304,8 +2307,7 @@ object Parsers {
23042307
val arg = atSpan(start, in.skipToken()) {
23052308
if in.token != INDENT then
23062309
syntaxErrorOrIncomplete(i"indented expression expected, ${in} found")
2307-
val body = inDefScopeBraces(block(simplify = true))
2308-
Function(params, body)
2310+
Function(params, blockExpr())
23092311
}
23102312
Apply(t, arg)
23112313
}
@@ -2397,8 +2399,7 @@ object Parsers {
23972399
else fn
23982400
}
23992401

2400-
/** BlockExpr ::= `{' BlockExprContents `}'
2401-
* BlockExprContents ::= CaseClauses | Block
2402+
/** BlockExpr ::= <<< (CaseClauses | Block) >>>
24022403
*/
24032404
def blockExpr(): Tree = atSpan(in.offset) {
24042405
val simplify = in.token == INDENT

docs/docs/internals/syntax.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ Catches ::= ‘catch’ (Expr | ExprCaseClause)
227227
PostfixExpr ::= InfixExpr [id] PostfixOp(expr, op)
228228
InfixExpr ::= PrefixExpr
229229
| InfixExpr id [nl] InfixExpr InfixOp(expr, op, expr)
230+
| InfixExpr id ‘:’ IndentedExpr
230231
| InfixExpr MatchClause
231232
MatchClause ::= ‘match’ <<< CaseClauses >>> Match(expr, cases)
232233
PrefixExpr ::= [‘-’ | ‘+’ | ‘~’ | ‘!’] SimpleExpr PrefixOp(expr, op)
@@ -244,10 +245,11 @@ SimpleExpr ::= SimpleRef
244245
| SimpleExpr ‘.’ MatchClause
245246
| SimpleExpr TypeArgs TypeApply(expr, args)
246247
| SimpleExpr ArgumentExprs Apply(expr, args)
247-
| SimpleExpr1 :<<< (CaseClauses | Block) >>> -- under language.experimental.fewerBraces
248-
| SimpleExpr1 FunParams (‘=>’ | ‘?=>’) indent Block outdent -- under language.experimental.fewerBraces
248+
| SimpleExpr1 ‘:’ IndentedExpr -- under language.experimental.fewerBraces
249+
| SimpleExpr1 FunParams (‘=>’ | ‘?=>’) IndentedExpr -- under language.experimental.fewerBraces
249250
| SimpleExpr ‘_’ PostfixOp(expr, _) (to be dropped)
250251
| XmlExpr -- to be dropped
252+
IndentedExpr ::= indent CaseClauses | Block outdent
251253
Quoted ::= ‘'’ ‘{’ Block ‘}’
252254
| ‘'’ ‘[’ Type ‘]’
253255
ExprsInParens ::= ExprInParens {‘,’ ExprInParens}
@@ -257,7 +259,7 @@ ParArgumentExprs ::= ‘(’ [‘using’] ExprsInParens ‘)’
257259
| ‘(’ [ExprsInParens ‘,’] PostfixExpr ‘*’ ‘)’ exprs :+ Typed(expr, Ident(wildcardStar))
258260
ArgumentExprs ::= ParArgumentExprs
259261
| BlockExpr
260-
BlockExpr ::= <<< (CaseClauses | Block) >>>
262+
BlockExpr ::= <<< CaseClauses | Block >>>
261263
Block ::= {BlockStat semi} [BlockResult] Block(stats, expr?)
262264
BlockStat ::= Import
263265
| {Annotation {nl}} {LocalModifier} Def

docs/docs/reference/other-new-features/indentation-experimental.md

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@ times(10):
2323
println("ha")
2424
```
2525

26+
The colon can also follow an infix operator:
27+
28+
```scala
29+
credentials ++ :
30+
val file = Path.userHome / ".credentials"
31+
if file.exists
32+
then Seq(Credentials(file))
33+
else Seq()
34+
```
35+
2636
Function calls that take multiple argument lists can also be handled this way:
2737

2838
```scala
@@ -39,7 +49,7 @@ val firstLine = files.get(fileName).fold:
3949
4050
## Lambda Arguments Without Braces
4151
42-
Braces can also be omitted around multiple line function value arguments. Examples
52+
Braces can also be omitted around multiple line function value arguments:
4353
```scala
4454
val xs = elems.map x =>
4555
val y = x - 1
@@ -52,26 +62,21 @@ Braces can be omitted if the lambda starts with a parameter list and `=>` or `=>
5262
## Syntax Changes
5363
5464
```
55-
SimpleExpr ::= ...
56-
| SimpleExpr : indent (CaseClauses | Block) outdent
57-
| SimpleExpr FunParams (‘=>’ | ‘?=>’) indent Block outdent
65+
SimpleExpr ::= ...
66+
| SimpleExpr `:` IndentedArgument
67+
| SimpleExpr FunParams (‘=>’ | ‘?=>’) IndentedArgument
68+
InfixExpr ::= ...
69+
| InfixExpr id `:` IndentedArgument
70+
IndentedArgument ::= indent (CaseClauses | Block) outdent
5871
```
5972
60-
Note that indented blocks after `:` or `=>` only work when following a simple expression, they are not allowed after an infix operator. So the following examples
61-
would be incorrect:
62-
63-
```scala
64-
x + : // error
65-
y
66-
67-
f `andThen` y => // error
68-
y + 1
69-
```
70-
71-
Note also that a lambda argument must have the `=>` at the end of a line for braces
73+
Note that a lambda argument must have the `=>` at the end of a line for braces
7274
to be optional. For instance, the following would also be incorrect:
7375
7476
```scala
7577
xs.map x => x + 1 // error: braces or parentheses are required
78+
```
79+
The lambda has to be enclosed in braces or parentheses:
80+
```scala
7681
xs.map(x => x + 1) // ok
7782
```

tests/neg/indent-colons.scala

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

tests/neg/indent-experimental.scala

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,3 @@ val x =
66
else: // error
77
2
88

9-
10-
val credentials = List("OK")
11-
val all = credentials ++ : // error
12-
val file = "file" // error
13-
if file.isEmpty // error
14-
then Seq("none")
15-
else Seq(file)

tests/pos/indent-colons.scala

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,30 @@ val o =
139139
:
140140
x => x.toString
141141

142+
object Test23:
143+
val x = 1.+ : // ok
144+
2
145+
146+
val y = 1 + : // ok
147+
2
148+
149+
val r = 1 to:
150+
100
151+
152+
val credentials = List("OK")
153+
val all = credentials ++ :
154+
val file = "file"
155+
if file.isEmpty
156+
then Seq("none")
157+
else Seq(file)
158+
159+
extension (x: Boolean)
160+
infix def or (y: => Boolean) = x || y
161+
162+
def test24(x: Int, y: Int) =
163+
x < y or:
164+
x > y
165+
or:
166+
x == y
167+
168+

0 commit comments

Comments
 (0)