@@ -11,6 +11,7 @@ import NameKinds.{UniqueName, ContextBoundParamName, ContextFunctionParamName, D
11
11
import typer .{Namer , Checking }
12
12
import util .{Property , SourceFile , SourcePosition , SrcPos , Chars }
13
13
import config .{Feature , Config }
14
+ import config .Feature .{sourceVersion , migrateTo3 , enabled , betterForsEnabled }
14
15
import config .SourceVersion .*
15
16
import collection .mutable
16
17
import reporting .*
@@ -1815,46 +1816,81 @@ object desugar {
1815
1816
/** Create tree for for-comprehension `<for (enums) do body>` or
1816
1817
* `<for (enums) yield body>` where mapName and flatMapName are chosen
1817
1818
* corresponding to whether this is a for-do or a for-yield.
1818
- * The creation performs the following rewrite rules:
1819
+ * If betterFors are enabled, the creation performs the following rewrite rules:
1819
1820
*
1820
- * 1.
1821
+ * 1. if betterFors is enabled:
1821
1822
*
1822
- * for (P <- G) E ==> G.foreach (P => E)
1823
+ * for () do E ==> E
1824
+ * or
1825
+ * for () yield E ==> E
1823
1826
*
1824
- * Here and in the following (P => E) is interpreted as the function (P => E)
1825
- * if P is a variable pattern and as the partial function { case P => E } otherwise.
1827
+ * (Where empty for-comprehensions are excluded by the parser)
1826
1828
*
1827
1829
* 2.
1828
1830
*
1829
- * for (P <- G) yield E ==> G.map (P => E)
1831
+ * for (P <- G) do E ==> G.foreach (P => E)
1832
+ *
1833
+ * Here and in the following (P => E) is interpreted as the function (P => E)
1834
+ * if P is a variable pattern and as the partial function { case P => E } otherwise.
1830
1835
*
1831
1836
* 3.
1832
1837
*
1838
+ * for (P <- G) yield P ==> G
1839
+ *
1840
+ * If betterFors is enabled, P is a variable or a tuple of variables and G is not a withFilter.
1841
+ *
1842
+ * for (P <- G) yield E ==> G.map (P => E)
1843
+ *
1844
+ * Otherwise
1845
+ *
1846
+ * 4.
1847
+ *
1833
1848
* for (P_1 <- G_1; P_2 <- G_2; ...) ...
1834
1849
* ==>
1835
1850
* G_1.flatMap (P_1 => for (P_2 <- G_2; ...) ...)
1836
1851
*
1837
- * 4 .
1852
+ * 5 .
1838
1853
*
1839
- * for (P <- G; E; ...) ...
1840
- * =>
1841
- * for (P <- G.filter (P => E); ...) ...
1854
+ * for (P <- G; if E; ...) ...
1855
+ * == >
1856
+ * for (P <- G.withFilter (P => E); ...) ...
1842
1857
*
1843
- * 5 . For any N:
1858
+ * 6 . For any N, if betterFors is enabled :
1844
1859
*
1845
- * for (P_1 <- G; P_2 = E_2; val P_N = E_N; ...)
1860
+ * for (P <- G; P_1 = E_1; ... P_N = E_N; P1 <- G1; ...) ...
1846
1861
* ==>
1847
- * for (TupleN(P_1, P_2, ... P_N) <-
1848
- * for (x_1 @ P_1 <- G) yield {
1849
- * val x_2 @ P_2 = E_2
1862
+ * G.flatMap (P => for (P_1 = E_1; ... P_N = E_N; ...))
1863
+ *
1864
+ * 7. For any N, if betterFors is enabled:
1865
+ *
1866
+ * for (P <- G; P_1 = E_1; ... P_N = E_N) ...
1867
+ * ==>
1868
+ * G.map (P => for (P_1 = E_1; ... P_N = E_N) ...)
1869
+ *
1870
+ * 8. For any N:
1871
+ *
1872
+ * for (P <- G; P_1 = E_1; ... P_N = E_N; ...)
1873
+ * ==>
1874
+ * for (TupleN(P, P_1, ... P_N) <-
1875
+ * for (x @ P <- G) yield {
1876
+ * val x_1 @ P_1 = E_2
1850
1877
* ...
1851
- * val x_N & P_N = E_N
1852
- * TupleN(x_1, ..., x_N)
1853
- * } ...)
1878
+ * val x_N @ P_N = E_N
1879
+ * TupleN(x, x_1, ..., x_N)
1880
+ * }; if E; ...)
1854
1881
*
1855
1882
* If any of the P_i are variable patterns, the corresponding `x_i @ P_i` is not generated
1856
1883
* and the variable constituting P_i is used instead of x_i
1857
1884
*
1885
+ * 9. For any N, if betterFors is enabled:
1886
+ *
1887
+ * for (P_1 = E_1; ... P_N = E_N; ...)
1888
+ * ==>
1889
+ * {
1890
+ * val x_N @ P_N = E_N
1891
+ * for (...)
1892
+ * }
1893
+ *
1858
1894
* @param mapName The name to be used for maps (either map or foreach)
1859
1895
* @param flatMapName The name to be used for flatMaps (either flatMap or foreach)
1860
1896
* @param enums The enumerators in the for expression
@@ -1963,7 +1999,7 @@ object desugar {
1963
1999
case GenCheckMode .FilterAlways => false // pattern was prefixed by `case`
1964
2000
case GenCheckMode .FilterNow | GenCheckMode .CheckAndFilter => isVarBinding(gen.pat) || isIrrefutable(gen.pat, gen.expr)
1965
2001
case GenCheckMode .Check => true
1966
- case GenCheckMode .Ignore => true
2002
+ case GenCheckMode .Ignore | GenCheckMode . Filtered => true
1967
2003
1968
2004
/** rhs.name with a pattern filter on rhs unless `pat` is irrefutable when
1969
2005
* matched against `rhs`.
@@ -1973,12 +2009,31 @@ object desugar {
1973
2009
Select (rhs, name)
1974
2010
}
1975
2011
2012
+ def deepEquals (t1 : Tree , t2 : Tree ): Boolean =
2013
+ (unsplice(t1), unsplice(t2)) match
2014
+ case (Ident (n1), Ident (n2)) => n1 == n2
2015
+ case (Tuple (ts1), Tuple (ts2)) => ts1.corresponds(ts2)(deepEquals)
2016
+ case _ => false
2017
+
1976
2018
enums match {
2019
+ case Nil if betterForsEnabled => body
1977
2020
case (gen : GenFrom ) :: Nil =>
1978
- Apply (rhsSelect(gen, mapName), makeLambda(gen, body))
2021
+ if betterForsEnabled
2022
+ && gen.checkMode != GenCheckMode .Filtered // results of withFilter have the wrong type
2023
+ && deepEquals(gen.pat, body)
2024
+ then gen.expr // avoid a redundant map with identity
2025
+ else Apply (rhsSelect(gen, mapName), makeLambda(gen, body))
1979
2026
case (gen : GenFrom ) :: (rest @ (GenFrom (_, _, _) :: _)) =>
1980
2027
val cont = makeFor(mapName, flatMapName, rest, body)
1981
2028
Apply (rhsSelect(gen, flatMapName), makeLambda(gen, cont))
2029
+ case (gen : GenFrom ) :: rest
2030
+ if betterForsEnabled
2031
+ && rest.dropWhile(_.isInstanceOf [GenAlias ]).headOption.forall(e => e.isInstanceOf [GenFrom ]) => // possible aliases followed by a generator or end of for
2032
+ val cont = makeFor(mapName, flatMapName, rest, body)
2033
+ val selectName =
2034
+ if rest.exists(_.isInstanceOf [GenFrom ]) then flatMapName
2035
+ else mapName
2036
+ Apply (rhsSelect(gen, selectName), makeLambda(gen, cont))
1982
2037
case (gen : GenFrom ) :: (rest @ GenAlias (_, _) :: _) =>
1983
2038
val (valeqs, rest1) = rest.span(_.isInstanceOf [GenAlias ])
1984
2039
val pats = valeqs map { case GenAlias (pat, _) => pat }
@@ -1997,8 +2052,20 @@ object desugar {
1997
2052
makeFor(mapName, flatMapName, vfrom1 :: rest1, body)
1998
2053
case (gen : GenFrom ) :: test :: rest =>
1999
2054
val filtered = Apply (rhsSelect(gen, nme.withFilter), makeLambda(gen, test))
2000
- val genFrom = GenFrom (gen.pat, filtered, GenCheckMode .Ignore )
2055
+ val genFrom = GenFrom (gen.pat, filtered, if betterForsEnabled then GenCheckMode . Filtered else GenCheckMode .Ignore )
2001
2056
makeFor(mapName, flatMapName, genFrom :: rest, body)
2057
+ case GenAlias (_, _) :: _ if betterForsEnabled =>
2058
+ val (valeqs, rest) = enums.span(_.isInstanceOf [GenAlias ])
2059
+ val pats = valeqs.map { case GenAlias (pat, _) => pat }
2060
+ val rhss = valeqs.map { case GenAlias (_, rhs) => rhs }
2061
+ val (defpats, ids) = pats.map(makeIdPat).unzip
2062
+ val pdefs = valeqs.lazyZip(defpats).lazyZip(rhss).map { (valeq, defpat, rhs) =>
2063
+ val mods = defpat match
2064
+ case defTree : DefTree => defTree.mods
2065
+ case _ => Modifiers ()
2066
+ makePatDef(valeq, mods, defpat, rhs)
2067
+ }
2068
+ Block (pdefs, makeFor(mapName, flatMapName, rest, body))
2002
2069
case _ =>
2003
2070
EmptyTree // may happen for erroneous input
2004
2071
}
0 commit comments