Skip to content

Commit 43e3b7c

Browse files
committed
Make fewerBraces a standard feature
Enables fewerBraces as a standard feature from 3.3 on. No language import is needed.
1 parent 275cfa8 commit 43e3b7c

23 files changed

+87
-116
lines changed

compiler/src/dotty/tools/dotc/config/Feature.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,11 @@ object Feature:
101101
case Some(v) => v
102102
case none => sourceVersionSetting
103103

104-
def migrateTo3(using Context): Boolean = sourceVersion == `3.0-migration`
104+
def migrateTo3(using Context): Boolean =
105+
sourceVersion == `3.0-migration`
106+
107+
def fewerBracesEnabled(using Context) =
108+
sourceVersion.isAtLeast(`3.3`) || enabled(fewerBraces)
105109

106110
/** If current source migrates to `version`, issue given warning message
107111
* and return `true`, otherwise return `false`.

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ trait AllScalaSettings extends CommonScalaSettings, PluginSettings, VerboseSetti
6464
val oldSyntax: Setting[Boolean] = BooleanSetting("-old-syntax", "Require `(...)` around conditions.")
6565
val indent: Setting[Boolean] = BooleanSetting("-indent", "Together with -rewrite, remove {...} syntax when possible due to significant indentation.")
6666
val noindent: Setting[Boolean] = BooleanSetting("-no-indent", "Require classical {...} syntax, indentation is not significant.", aliases = List("-noindent"))
67-
val YindentColons: Setting[Boolean] = BooleanSetting("-Yindent-colons", "(disabled: use -language:experimental.fewerBraces instead)")
6867

6968
/* Decompiler settings */
7069
val printTasty: Setting[Boolean] = BooleanSetting("-print-tasty", "Prints the raw tasty.", aliases = List("--print-tasty"))

compiler/src/dotty/tools/dotc/config/SourceVersion.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import util.Property
88
enum SourceVersion:
99
case `3.0-migration`, `3.0`, `3.1` // Note: do not add `3.1-migration` here, 3.1 is the same language as 3.0.
1010
case `3.2-migration`, `3.2`
11+
case `3.3-migration`, `3.3`
1112
case `future-migration`, `future`
1213

1314
val isMigrating: Boolean = toString.endsWith("-migration")

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -778,15 +778,14 @@ object Parsers {
778778
}
779779
})
780780
canRewrite &= (in.isAfterLineEnd || statCtdTokens.contains(in.token)) // test (5)
781-
if (canRewrite && (!underColonSyntax || in.fewerBracesEnabled)) {
781+
if canRewrite && (!underColonSyntax || Feature.fewerBracesEnabled) then
782782
val openingPatchStr =
783783
if !colonRequired then ""
784784
else if testChar(startOpening - 1, Chars.isOperatorPart(_)) then " :"
785785
else ":"
786786
val (startClosing, endClosing) = closingElimRegion()
787787
patch(source, Span(startOpening, endOpening), openingPatchStr)
788788
patch(source, Span(startClosing, endClosing), "")
789-
}
790789
t
791790
}
792791

@@ -1025,7 +1024,7 @@ object Parsers {
10251024
* body
10261025
*/
10271026
def isColonLambda =
1028-
in.fewerBracesEnabled && in.token == COLONfollow && followingIsLambdaAfterColon()
1027+
Feature.fewerBracesEnabled && in.token == COLONfollow && followingIsLambdaAfterColon()
10291028

10301029
/** operand { infixop operand | MatchClause } [postfixop],
10311030
*
@@ -2370,7 +2369,7 @@ object Parsers {
23702369
/** PostfixExpr ::= InfixExpr [id [nl]]
23712370
* InfixExpr ::= PrefixExpr
23722371
* | InfixExpr id [nl] InfixExpr
2373-
* | InfixExpr id `:` IndentedExpr
2372+
* | InfixExpr id ColonArgument
23742373
* | InfixExpr MatchClause
23752374
*/
23762375
def postfixExpr(location: Location = Location.ElseWhere): Tree =
@@ -2414,10 +2413,11 @@ object Parsers {
24142413
* | SimpleExpr `.` MatchClause
24152414
* | SimpleExpr (TypeArgs | NamedTypeArgs)
24162415
* | SimpleExpr1 ArgumentExprs
2417-
* | SimpleExpr1 `:` ColonArgument -- under language.experimental.fewerBraces
2418-
* ColonArgument ::= indent (CaseClauses | Block) outdent
2419-
* | FunParams (‘=>’ | ‘?=>’) ColonArgBody
2420-
* | HkTypeParamClause ‘=>’ ColonArgBody
2416+
* | SimpleExpr1 ColonArgument
2417+
* ColonArgument ::= colon [LambdaStart]
2418+
* indent (CaseClauses | Block) outdent
2419+
* LambdaStart ::= FunParams (‘=>’ | ‘?=>’)
2420+
* | HkTypeParamClause ‘=>’
24212421
* ColonArgBody ::= indent (CaseClauses | Block) outdent
24222422
* Quoted ::= ‘'’ ‘{’ Block ‘}’
24232423
* | ‘'’ ‘[’ Type ‘]’

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

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import scala.collection.mutable
1717
import scala.collection.immutable.SortedMap
1818
import rewrites.Rewrites.patch
1919
import config.Feature
20-
import config.Feature.migrateTo3
20+
import config.Feature.{migrateTo3, fewerBracesEnabled}
2121
import config.SourceVersion.`3.0`
2222
import reporting.{NoProfile, Profile}
2323

@@ -202,25 +202,6 @@ object Scanners {
202202
def featureEnabled(name: TermName) = Feature.enabled(name)(using languageImportContext)
203203
def erasedEnabled = featureEnabled(Feature.erasedDefinitions)
204204

205-
private inline val fewerBracesByDefault = false
206-
// turn on to study impact on codebase if `fewerBraces` was the default
207-
208-
private var fewerBracesEnabledCache = false
209-
private var fewerBracesEnabledCtx: Context = NoContext
210-
211-
def fewerBracesEnabled =
212-
if fewerBracesEnabledCtx ne myLanguageImportContext then
213-
fewerBracesEnabledCache =
214-
featureEnabled(Feature.fewerBraces)
215-
|| fewerBracesByDefault && indentSyntax && !migrateTo3
216-
// ensure that fewer braces is not the default for 3.0-migration since
217-
// { x: T =>
218-
// expr
219-
// }
220-
// would be ambiguous
221-
fewerBracesEnabledCtx = myLanguageImportContext
222-
fewerBracesEnabledCache
223-
224205
private var postfixOpsEnabledCache = false
225206
private var postfixOpsEnabledCtx: Context = NoContext
226207

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

Lines changed: 54 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,60 @@ Refinement ::= :<<< [RefineDcl] {semi [RefineDcl]} >>>
186186
Packaging ::= ‘package’ QualId :<<< TopStats >>>
187187
```
188188
189+
## Optional Braces for Method Arguments
190+
191+
Starting with Scala 3.3, a `<colon>` token is also recognized where a function argument would be expected. Examples:
192+
193+
```scala
194+
times(10):
195+
println("ah")
196+
println("ha")
197+
```
198+
199+
or
200+
201+
```scala
202+
credentials `++`:
203+
val file = Path.userHome / ".credentials"
204+
if file.exists
205+
then Seq(Credentials(file))
206+
else Seq()
207+
```
208+
209+
or
210+
211+
```scala
212+
xs.map:
213+
x =>
214+
val y = x - 1
215+
y * y
216+
```
217+
What's more, a `:` in these settings can also be followed on the same line by the parameter part and arrow of a lambda. So the last example could be compressed to this:
218+
219+
```scala
220+
xs.map: x =>
221+
val y = x - 1
222+
y * y
223+
```
224+
and the following would also be legal:
225+
```scala
226+
xs.foldLeft(0): (x, y) =>
227+
x + y
228+
```
229+
230+
The grammar changes for optional braces around arguments are as follows.
231+
232+
```
233+
SimpleExpr ::= ...
234+
| SimpleExpr ColonArgument
235+
InfixExpr ::= ...
236+
| InfixExpr id ColonArgument
237+
ColonArgument ::= colon [LambdaStart]
238+
indent (CaseClauses | Block) outdent
239+
LambdaStart ::= FunParams (‘=>’ | ‘?=>’)
240+
| HkTypeParamClause ‘=>’
241+
```
242+
189243
## Spaces vs Tabs
190244
191245
Indentation prefixes can consist of spaces and/or tabs. Indentation widths are the indentation prefixes themselves, ordered by the string prefix relation. So, so for instance "2 tabs, followed by 4 spaces" is strictly less than "2 tabs, followed by 5 spaces", but "2 tabs, followed by 4 spaces" is incomparable to "6 tabs" or to "4 spaces, followed by 2 tabs". It is an error if the indentation width of some line is incomparable with the indentation width of the region that's current at that point. To avoid such errors, it is a good idea not to mix spaces and tabs in the same source file.
@@ -448,62 +502,3 @@ indented regions where possible. When invoked with options `-rewrite -no-indent`
448502
The `-indent` option only works on [new-style syntax](./control-syntax.md). So to go from old-style syntax to new-style indented code one has to invoke the compiler twice, first with options `-rewrite -new-syntax`, then again with options
449503
`-rewrite -indent`. To go in the opposite direction, from indented code to old-style syntax, it's `-rewrite -no-indent`, followed by `-rewrite -old-syntax`.
450504

451-
## Variant: Indentation Marker `:` for Arguments
452-
453-
Generally, the possible indentation regions coincide with those regions where braces `{...}` are also legal, no matter whether the braces enclose an expression or a set of definitions. There is one exception, though: Arguments to functions can be enclosed in braces but they cannot be simply indented instead. Making indentation always significant for function arguments would be too restrictive and fragile.
454-
455-
To allow such arguments to be written without braces, a variant of the indentation scheme is implemented under language import
456-
```scala
457-
import language.experimental.fewerBraces
458-
```
459-
In this variant, a `<colon>` token is also recognized where function argument would be expected. Examples:
460-
461-
```scala
462-
times(10):
463-
println("ah")
464-
println("ha")
465-
```
466-
467-
or
468-
469-
```scala
470-
credentials `++`:
471-
val file = Path.userHome / ".credentials"
472-
if file.exists
473-
then Seq(Credentials(file))
474-
else Seq()
475-
```
476-
477-
or
478-
479-
```scala
480-
xs.map:
481-
x =>
482-
val y = x - 1
483-
y * y
484-
```
485-
What's more, a `:` in these settings can also be followed on the same line by the parameter part and arrow of a lambda. So the last example could be compressed to this:
486-
487-
```scala
488-
xs.map: x =>
489-
val y = x - 1
490-
y * y
491-
```
492-
and the following would also be legal:
493-
```scala
494-
xs.foldLeft(0): (x, y) =>
495-
x + y
496-
```
497-
498-
The grammar changes for this variant are as follows.
499-
500-
```
501-
SimpleExpr ::= ...
502-
| SimpleExpr ColonArgument
503-
InfixExpr ::= ...
504-
| InfixExpr id ColonArgument
505-
ColonArgument ::= colon [LambdaStart]
506-
indent (CaseClauses | Block) outdent
507-
LambdaStart ::= FunParams (‘=>|?=>’)
508-
| HkTypeParamClause=>
509-
```

docs/_docs/reference/syntax.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ Catches ::= ‘catch’ (Expr | ExprCaseClause)
249249
PostfixExpr ::= InfixExpr [id] -- only if language.postfixOperators is enabled
250250
InfixExpr ::= PrefixExpr
251251
| InfixExpr id [nl] InfixExpr
252+
| InfixExpr id ColonArgument
252253
| InfixExpr MatchClause
253254
MatchClause ::= ‘match’ <<< CaseClauses >>>
254255
PrefixExpr ::= [PrefixOperator] SimpleExpr
@@ -267,6 +268,11 @@ SimpleExpr ::= SimpleRef
267268
| SimpleExpr ‘.’ MatchClause
268269
| SimpleExpr TypeArgs
269270
| SimpleExpr ArgumentExprs
271+
| SimpleExpr ColonArgument
272+
ColonArgument ::= colon [LambdaStart]
273+
indent (CaseClauses | Block) outdent
274+
LambdaStart ::= FunParams (‘=>’ | ‘?=>’)
275+
| HkTypeParamClause ‘=>’
270276
Quoted ::= ‘'’ ‘{’ Block ‘}’
271277
| ‘'’ ‘[’ Type ‘]’
272278
ExprSplice ::= spliceId -- if inside quoted block

library/src/scala/runtime/stdLibPatches/language.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ object language:
5151
/** Experimental support for using indentation for arguments
5252
*/
5353
@compileTimeOnly("`fewerBraces` can only be used at compile time in import statements")
54+
@deprecated("`fewerBraces` is now standard, no language import is needed", since = "3.3")
5455
object fewerBraces
5556

5657
/** Experimental support for typechecked exception capabilities
@@ -192,7 +193,6 @@ object language:
192193
@compileTimeOnly("`3.2` can only be used at compile time in import statements")
193194
object `3.2`
194195

195-
/* This can be added when we go to 3.3
196196
/** Set source version to 3.3-migration.
197197
*
198198
* @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]]
@@ -206,5 +206,5 @@ object language:
206206
*/
207207
@compileTimeOnly("`3.3` can only be used at compile time in import statements")
208208
object `3.3`
209-
*/
209+
210210
end language

tests/neg-custom-args/no-experimental/experimental-nested-imports-2.scala

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,27 @@
11
import annotation.experimental
22

33
class Class1:
4-
import language.experimental.fewerBraces // error
54
import language.experimental.namedTypeArguments // error
65
import language.experimental.genericNumberLiterals // error
76
import language.experimental.erasedDefinitions // ok: only check at erased definition
87
@experimental def f = 1
98
def g = 1
109

1110
object Object1:
12-
import language.experimental.fewerBraces // error
1311
import language.experimental.namedTypeArguments // error
1412
import language.experimental.genericNumberLiterals // error
1513
import language.experimental.erasedDefinitions // ok: only check at erased definition
1614
@experimental def f = 1
1715
def g = 1
1816

1917
def fun1 =
20-
import language.experimental.fewerBraces // error
2118
import language.experimental.namedTypeArguments // error
2219
import language.experimental.genericNumberLiterals // error
2320
import language.experimental.erasedDefinitions // ok: only check at erased definition
2421
@experimental def f = 1
2522
def g = 1
2623

2724
val value1 =
28-
import language.experimental.fewerBraces // error
2925
import language.experimental.namedTypeArguments // error
3026
import language.experimental.genericNumberLiterals // error
3127
import language.experimental.erasedDefinitions // ok: only check at erased definition
Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,21 @@
11
import annotation.experimental
22

33
class Class1:
4-
import language.experimental.fewerBraces // error
54
import language.experimental.namedTypeArguments // error
65
import language.experimental.genericNumberLiterals // error
76
import language.experimental.erasedDefinitions // ok: only check at erased definition
87

98
object Object1:
10-
import language.experimental.fewerBraces // error
119
import language.experimental.namedTypeArguments // error
1210
import language.experimental.genericNumberLiterals // error
1311
import language.experimental.erasedDefinitions // ok: only check at erased definition
1412

1513
def fun1 =
16-
import language.experimental.fewerBraces // error
1714
import language.experimental.namedTypeArguments // error
1815
import language.experimental.genericNumberLiterals // error
1916
import language.experimental.erasedDefinitions // ok: only check at erased definition
2017

2118
val value1 =
22-
import language.experimental.fewerBraces // error
2319
import language.experimental.namedTypeArguments // error
2420
import language.experimental.genericNumberLiterals // error
2521
import language.experimental.erasedDefinitions // ok: only check at erased definition

tests/neg-custom-args/no-experimental/experimental-nested-imports.scala

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,24 @@
11
import annotation.experimental
22

33
class Class1:
4-
import language.experimental.fewerBraces // error
54
import language.experimental.namedTypeArguments // error
65
import language.experimental.genericNumberLiterals // error
76
import language.experimental.erasedDefinitions // ok: only check at erased definition
87
@experimental def f = 1
98

109
object Object1:
11-
import language.experimental.fewerBraces // error
1210
import language.experimental.namedTypeArguments // error
1311
import language.experimental.genericNumberLiterals // error
1412
import language.experimental.erasedDefinitions // ok: only check at erased definition
1513
@experimental def f = 1
1614

1715
def fun1 =
18-
import language.experimental.fewerBraces // error
1916
import language.experimental.namedTypeArguments // error
2017
import language.experimental.genericNumberLiterals // error
2118
import language.experimental.erasedDefinitions // ok: only check at erased definition
2219
@experimental def f = 1
2320

2421
val value1 =
25-
import language.experimental.fewerBraces // error
2622
import language.experimental.namedTypeArguments // error
2723
import language.experimental.genericNumberLiterals // error
2824
import language.experimental.erasedDefinitions // ok: only check at erased definition

tests/neg-custom-args/no-experimental/experimental-package-imports.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import annotation.experimental
22

33
package foo {
4-
import language.experimental.fewerBraces // error
54
import language.experimental.namedTypeArguments // error
65
import language.experimental.genericNumberLiterals // error
76
import language.experimental.erasedDefinitions // ok: only check at erased definition
@@ -13,7 +12,6 @@ package foo {
1312

1413
package foo2 {
1514
// ok: all definitions are top-level @experimental
16-
import language.experimental.fewerBraces
1715
import language.experimental.namedTypeArguments
1816
import language.experimental.genericNumberLiterals
1917
import language.experimental.erasedDefinitions

tests/neg/closure-args.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import language.experimental.fewerBraces
1+
import language.`3.3`
22

33
val x = List(1).map: (x: => Int) => // error
44
???

tests/neg/i10943.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import language.experimental.fewerBraces
1+
import language.`3.3`
22

33
object T:
44
class A

0 commit comments

Comments
 (0)