Skip to content

Commit c2db035

Browse files
committed
Make SIP-62 - betterFors a standard feature
1 parent 7d79c56 commit c2db035

File tree

8 files changed

+19
-28
lines changed

8 files changed

+19
-28
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import NameKinds.{UniqueName, ContextBoundParamName, ContextFunctionParamName, D
1111
import typer.{Namer, Checking}
1212
import util.{Property, SourceFile, SourcePosition, SrcPos, Chars}
1313
import config.{Feature, Config}
14-
import config.Feature.{sourceVersion, migrateTo3, enabled, betterForsEnabled}
14+
import config.Feature.{sourceVersion, migrateTo3, enabled}
1515
import config.SourceVersion.*
1616
import collection.mutable
1717
import reporting.*
@@ -1953,9 +1953,9 @@ object desugar {
19531953
/** Create tree for for-comprehension `<for (enums) do body>` or
19541954
* `<for (enums) yield body>` where mapName and flatMapName are chosen
19551955
* corresponding to whether this is a for-do or a for-yield.
1956-
* If betterFors are enabled, the creation performs the following rewrite rules:
1956+
* If sourceVersion >= 3.7 are enabled, the creation performs the following rewrite rules:
19571957
*
1958-
* 1. if betterFors is enabled:
1958+
* 1. if sourceVersion >= 3.7:
19591959
*
19601960
* for () do E ==> E
19611961
* or
@@ -1986,13 +1986,13 @@ object desugar {
19861986
* ==>
19871987
* for (P <- G.withFilter (P => E); ...) ...
19881988
*
1989-
* 6. For any N, if betterFors is enabled:
1989+
* 6. For any N, if sourceVersion >= 3.7:
19901990
*
19911991
* for (P <- G; P_1 = E_1; ... P_N = E_N; P1 <- G1; ...) ...
19921992
* ==>
19931993
* G.flatMap (P => for (P_1 = E_1; ... P_N = E_N; ...))
19941994
*
1995-
* 7. For any N, if betterFors is enabled:
1995+
* 7. For any N, if sourceVersion >= 3.7:
19961996
*
19971997
* for (P <- G; P_1 = E_1; ... P_N = E_N) ...
19981998
* ==>
@@ -2013,7 +2013,7 @@ object desugar {
20132013
* If any of the P_i are variable patterns, the corresponding `x_i @ P_i` is not generated
20142014
* and the variable constituting P_i is used instead of x_i
20152015
*
2016-
* 9. For any N, if betterFors is enabled:
2016+
* 9. For any N, if sourceVersion >= 3.7:
20172017
*
20182018
* for (P_1 = E_1; ... P_N = E_N; ...)
20192019
* ==>
@@ -2147,15 +2147,15 @@ object desugar {
21472147
case _ => false
21482148

21492149
def markTrailingMap(aply: Apply, gen: GenFrom, selectName: TermName): Unit =
2150-
if betterForsEnabled
2150+
if sourceVersion.isAtLeast(`3.7`)
21512151
&& selectName == mapName
21522152
&& gen.checkMode != GenCheckMode.Filtered // results of withFilter have the wrong type
21532153
&& (deepEquals(gen.pat, body) || deepEquals(body, Tuple(Nil)))
21542154
then
21552155
aply.putAttachment(TrailingForMap, ())
21562156

21572157
enums match {
2158-
case Nil if betterForsEnabled => body
2158+
case Nil if sourceVersion.isAtLeast(`3.7`) => body
21592159
case (gen: GenFrom) :: Nil =>
21602160
val aply = Apply(rhsSelect(gen, mapName), makeLambda(gen, body))
21612161
markTrailingMap(aply, gen, mapName)
@@ -2164,7 +2164,7 @@ object desugar {
21642164
val cont = makeFor(mapName, flatMapName, rest, body)
21652165
Apply(rhsSelect(gen, flatMapName), makeLambda(gen, cont))
21662166
case (gen: GenFrom) :: rest
2167-
if betterForsEnabled
2167+
if sourceVersion.isAtLeast(`3.7`)
21682168
&& rest.dropWhile(_.isInstanceOf[GenAlias]).headOption.forall(e => e.isInstanceOf[GenFrom]) => // possible aliases followed by a generator or end of for
21692169
val cont = makeFor(mapName, flatMapName, rest, body)
21702170
val selectName =
@@ -2191,9 +2191,9 @@ object desugar {
21912191
makeFor(mapName, flatMapName, vfrom1 :: rest1, body)
21922192
case (gen: GenFrom) :: test :: rest =>
21932193
val filtered = Apply(rhsSelect(gen, nme.withFilter), makeLambda(gen, test))
2194-
val genFrom = GenFrom(gen.pat, filtered, if betterForsEnabled then GenCheckMode.Filtered else GenCheckMode.Ignore)
2194+
val genFrom = GenFrom(gen.pat, filtered, if sourceVersion.isAtLeast(`3.7`) then GenCheckMode.Filtered else GenCheckMode.Ignore)
21952195
makeFor(mapName, flatMapName, genFrom :: rest, body)
2196-
case GenAlias(_, _) :: _ if betterForsEnabled =>
2196+
case GenAlias(_, _) :: _ if sourceVersion.isAtLeast(`3.7`) =>
21972197
val (valeqs, rest) = enums.span(_.isInstanceOf[GenAlias])
21982198
val pats = valeqs.map { case GenAlias(pat, _) => pat }
21992199
val rhss = valeqs.map { case GenAlias(_, rhs) => rhs }

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ object Feature:
3737
val modularity = experimental("modularity")
3838
val betterMatchTypeExtractors = experimental("betterMatchTypeExtractors")
3939
val quotedPatternsWithPolymorphicFunctions = experimental("quotedPatternsWithPolymorphicFunctions")
40-
val betterFors = experimental("betterFors")
4140
val packageObjectValues = experimental("packageObjectValues")
4241

4342
def experimentalAutoEnableFeatures(using Context): List[TermName] =
@@ -66,8 +65,7 @@ object Feature:
6665
(into, "Allow into modifier on parameter types"),
6766
(namedTuples, "Allow named tuples"),
6867
(modularity, "Enable experimental modularity features"),
69-
(betterMatchTypeExtractors, "Enable better match type extractors"),
70-
(betterFors, "Enable improvements in `for` comprehensions")
68+
(betterMatchTypeExtractors, "Enable better match type extractors")
7169
)
7270

7371
// legacy language features from Scala 2 that are no longer supported.
@@ -122,8 +120,6 @@ object Feature:
122120

123121
def namedTypeArgsEnabled(using Context) = enabled(namedTypeArguments)
124122

125-
def betterForsEnabled(using Context) = enabled(betterFors)
126-
127123
def genericNumberLiteralsEnabled(using Context) = enabled(genericNumberLiterals)
128124

129125
def scala2ExperimentalMacroEnabled(using Context) = enabled(scala2macros)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2949,7 +2949,7 @@ object Parsers {
29492949
/** Enumerators ::= Generator {semi Enumerator | Guard}
29502950
*/
29512951
def enumerators(): List[Tree] =
2952-
if in.featureEnabled(Feature.betterFors) then
2952+
if sourceVersion.isAtLeast(`3.7`) then
29532953
aliasesUntilGenerator() ++ enumeratorsRest()
29542954
else
29552955
generator() :: enumeratorsRest()

docs/_docs/reference/experimental/better-fors.md renamed to docs/_docs/reference/changed-features/better-fors.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
---
22
layout: doc-page
33
title: "Better fors"
4-
nightlyOf: https://docs.scala-lang.org/scala3/reference/experimental/better-fors.html
4+
nightlyOf: https://docs.scala-lang.org/scala3/reference/changed-features/better-fors.html
55
---
66

7-
The `betterFors` language extension improves the usability of `for`-comprehensions.
8-
9-
The extension is enabled by the language import `import scala.language.experimental.betterFors` or by setting the command line option `-language:experimental.betterFors`.
7+
Starting in Scala `3.7`, the usability of `for`-comprehensions is improved.
108

119
The biggest user facing change is the new ability to start `for`-comprehensions with aliases. This means that the following previously invalid code is now valid:
1210

@@ -30,11 +28,11 @@ for
3028
yield a + b
3129
```
3230

33-
Additionally this extension changes the way `for`-comprehensions are desugared. The desugaring is now done in a more intuitive way and the desugared code can be more efficient, because it avoids some unnecessary method calls. There are two main changes in the desugaring:
31+
Additionally, this extension changes the way `for`-comprehensions are desugared. The desugaring is now done in a more intuitive way and the desugared code can be more efficient, because it avoids some unnecessary method calls. There are two main changes in the desugaring:
3432

3533
1. **Simpler Desugaring for Pure Aliases**:
3634
When an alias is not followed by a guard, the desugaring is simplified. The last generator and the aliases don't have to be wrapped in a tuple, and instead the aliases are simply introduced as local variables in a block with the next generator.
37-
**Current Desugaring**:
35+
**Previous Desugaring**:
3836
```scala
3937
for {
4038
a <- doSth(arg)

docs/sidebar.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ subsection:
115115
- page: reference/changed-features/lazy-vals-init.md
116116
- page: reference/changed-features/main-functions.md
117117
- page: reference/changed-features/interpolation-escapes.md
118+
- page: reference/changed-features/better-fors.md
118119
- title: Dropped Features
119120
index: reference/dropped-features/dropped-features.md
120121
subsection:
@@ -162,7 +163,6 @@ subsection:
162163
- page: reference/experimental/modularity.md
163164
- page: reference/experimental/typeclasses.md
164165
- page: reference/experimental/runtimeChecked.md
165-
- page: reference/experimental/better-fors.md
166166
- page: reference/experimental/unrolled-defs.md
167167
- page: reference/experimental/package-object-values.md
168168
- page: reference/syntax.md

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ object language:
139139
* @see [[https://github.com/scala/improvement-proposals/pull/79]]
140140
*/
141141
@compileTimeOnly("`betterFors` can only be used at compile time in import statements")
142+
@deprecated("The `experimental.betterFors` language import is no longer needed since the feature is now standard", since = "3.7")
142143
object betterFors
143144

144145
/** Experimental support for package object values

tests/run/better-fors.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import scala.language.experimental.betterFors
2-
31
def for1 =
42
for {
53
a = 1

tests/run/fors.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,6 @@ object Test extends App {
113113

114114
/////////////////// elimination of map ///////////////////
115115

116-
import scala.language.experimental.betterFors
117-
118116
@tailrec
119117
def pair[B](xs: List[Int], ys: List[B], n: Int): List[(Int, B)] =
120118
if n == 0 then xs.zip(ys)

0 commit comments

Comments
 (0)