@@ -11,6 +11,7 @@ import NameKinds.{UniqueName, ContextBoundParamName, ContextFunctionParamName, D
1111import typer .{Namer , Checking }
1212import util .{Property , SourceFile , SourcePosition , SrcPos , Chars }
1313import config .{Feature , Config }
14+ import config .Feature .{sourceVersion , migrateTo3 , enabled , betterForsEnabled }
1415import config .SourceVersion .*
1516import collection .mutable
1617import reporting .*
@@ -1815,46 +1816,81 @@ object desugar {
18151816 /** Create tree for for-comprehension `<for (enums) do body>` or
18161817 * `<for (enums) yield body>` where mapName and flatMapName are chosen
18171818 * 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:
18191820 *
1820- * 1.
1821+ * 1. if betterFors is enabled:
18211822 *
1822- * for (P <- G) E ==> G.foreach (P => E)
1823+ * for () do E ==> E
1824+ * or
1825+ * for () yield E ==> E
18231826 *
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)
18261828 *
18271829 * 2.
18281830 *
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.
18301835 *
18311836 * 3.
18321837 *
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+ *
18331848 * for (P_1 <- G_1; P_2 <- G_2; ...) ...
18341849 * ==>
18351850 * G_1.flatMap (P_1 => for (P_2 <- G_2; ...) ...)
18361851 *
1837- * 4 .
1852+ * 5 .
18381853 *
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); ...) ...
18421857 *
1843- * 5 . For any N:
1858+ * 6 . For any N, if betterFors is enabled :
18441859 *
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; ...) ...
18461861 * ==>
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
18501877 * ...
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; ...)
18541881 *
18551882 * If any of the P_i are variable patterns, the corresponding `x_i @ P_i` is not generated
18561883 * and the variable constituting P_i is used instead of x_i
18571884 *
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+ *
18581894 * @param mapName The name to be used for maps (either map or foreach)
18591895 * @param flatMapName The name to be used for flatMaps (either flatMap or foreach)
18601896 * @param enums The enumerators in the for expression
@@ -1963,7 +1999,7 @@ object desugar {
19631999 case GenCheckMode .FilterAlways => false // pattern was prefixed by `case`
19642000 case GenCheckMode .FilterNow | GenCheckMode .CheckAndFilter => isVarBinding(gen.pat) || isIrrefutable(gen.pat, gen.expr)
19652001 case GenCheckMode .Check => true
1966- case GenCheckMode .Ignore => true
2002+ case GenCheckMode .Ignore | GenCheckMode . Filtered => true
19672003
19682004 /** rhs.name with a pattern filter on rhs unless `pat` is irrefutable when
19692005 * matched against `rhs`.
@@ -1973,12 +2009,31 @@ object desugar {
19732009 Select (rhs, name)
19742010 }
19752011
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+
19762018 enums match {
2019+ case Nil if betterForsEnabled => body
19772020 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))
19792026 case (gen : GenFrom ) :: (rest @ (GenFrom (_, _, _) :: _)) =>
19802027 val cont = makeFor(mapName, flatMapName, rest, body)
19812028 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))
19822037 case (gen : GenFrom ) :: (rest @ GenAlias (_, _) :: _) =>
19832038 val (valeqs, rest1) = rest.span(_.isInstanceOf [GenAlias ])
19842039 val pats = valeqs map { case GenAlias (pat, _) => pat }
@@ -1997,8 +2052,20 @@ object desugar {
19972052 makeFor(mapName, flatMapName, vfrom1 :: rest1, body)
19982053 case (gen : GenFrom ) :: test :: rest =>
19992054 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 )
20012056 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))
20022069 case _ =>
20032070 EmptyTree // may happen for erroneous input
20042071 }
0 commit comments