Skip to content

Commit 15ddef6

Browse files
committed
Make SIP-62 - betterFors a standard feature
1 parent cce70da commit 15ddef6

File tree

9 files changed

+31
-28
lines changed

9 files changed

+31
-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
@@ -35,7 +35,6 @@ object Feature:
3535
val into = experimental("into")
3636
val modularity = experimental("modularity")
3737
val quotedPatternsWithPolymorphicFunctions = experimental("quotedPatternsWithPolymorphicFunctions")
38-
val betterFors = experimental("betterFors")
3938
val packageObjectValues = experimental("packageObjectValues")
4039

4140
def experimentalAutoEnableFeatures(using Context): List[TermName] =
@@ -62,8 +61,7 @@ object Feature:
6261
(pureFunctions, "Enable pure functions for capture checking"),
6362
(captureChecking, "Enable experimental capture checking"),
6463
(into, "Allow into modifier on parameter types"),
65-
(modularity, "Enable experimental modularity features"),
66-
(betterFors, "Enable improvements in `for` comprehensions")
64+
(modularity, "Enable experimental modularity features")
6765
)
6866

6967
// legacy language features from Scala 2 that are no longer supported.
@@ -118,8 +116,6 @@ object Feature:
118116

119117
def namedTypeArgsEnabled(using Context) = enabled(namedTypeArguments)
120118

121-
def betterForsEnabled(using Context) = enabled(betterFors)
122-
123119
def genericNumberLiteralsEnabled(using Context) = enabled(genericNumberLiterals)
124120

125121
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
@@ -2956,7 +2956,7 @@ object Parsers {
29562956
/** Enumerators ::= Generator {semi Enumerator | Guard}
29572957
*/
29582958
def enumerators(): List[Tree] =
2959-
if in.featureEnabled(Feature.betterFors) then
2959+
if sourceVersion.isAtLeast(`3.7`) then
29602960
aliasesUntilGenerator() ++ enumeratorsRest()
29612961
else
29622962
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
@@ -116,6 +116,7 @@ subsection:
116116
- page: reference/changed-features/lazy-vals-init.md
117117
- page: reference/changed-features/main-functions.md
118118
- page: reference/changed-features/interpolation-escapes.md
119+
- page: reference/changed-features/better-fors.md
119120
- title: Dropped Features
120121
index: reference/dropped-features/dropped-features.md
121122
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
@@ -140,6 +140,7 @@ object language:
140140
* @see [[https://github.com/scala/improvement-proposals/pull/79]]
141141
*/
142142
@compileTimeOnly("`betterFors` can only be used at compile time in import statements")
143+
@deprecated("The `experimental.betterFors` language import is no longer needed since the feature is now standard", since = "3.7")
143144
object betterFors
144145

145146
/** Experimental support for package object values

tests/pos/i22727.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
object Main {
2+
type IXY = (Int, Int)
3+
4+
extension (xy: IXY) {
5+
def map(f: Int => Int): (Int, Int) = (f(xy._1), f(xy._2))
6+
}
7+
8+
def main(args: Array[String]): Unit = {
9+
val a = (0, 1)
10+
println(a)
11+
}
12+
}

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)