Skip to content

Commit 4bc0a4a

Browse files
committed
Merge betterFors desugaring with the default implementation
1 parent 6ef7d8e commit 4bc0a4a

File tree

3 files changed

+98
-160
lines changed

3 files changed

+98
-160
lines changed

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

+97-158
Original file line numberDiff line numberDiff line change
@@ -1806,113 +1806,79 @@ object desugar {
18061806
* corresponding to whether this is a for-do or a for-yield.
18071807
* If betterFors are enabled, the creation performs the following rewrite rules:
18081808
*
1809-
* 1.
1809+
* 1. if betterFors is enabled:
18101810
*
1811-
* for (P <- G) do E ==> G.foreach (P => E)
1811+
* for () do E ==> E
1812+
* or
1813+
* for () yield E ==> E
18121814
*
1813-
* Here and in the following (P => E) is interpreted as the function (P => E)
1814-
* if P is a variable pattern and as the partial function { case P => E } otherwise.
1815+
* (Where empty for-comprehensions are excluded by the parser)
18151816
*
18161817
* 2.
18171818
*
1818-
* for (P <- G) yield P ==> G
1819-
*
1820-
* If P is a variable or a tuple of variables and G is not a withFilter.
1819+
* for (P <- G) do E ==> G.foreach (P => E)
18211820
*
1822-
* for (P <- G) yield E ==> G.map (P => E)
1823-
*
1824-
* Otherwise
1821+
* Here and in the following (P => E) is interpreted as the function (P => E)
1822+
* if P is a variable pattern and as the partial function { case P => E } otherwise.
18251823
*
18261824
* 3.
18271825
*
1828-
* for (P_1 <- G_1; P_2 <- G_2; ...) ...
1829-
* ==>
1830-
* G_1.flatMap (P_1 => for (P_2 <- G_2; ...) ...)
1831-
*
1832-
* 4.
1833-
*
1834-
* for (P <- G; if E; ...) ...
1835-
* ==>
1836-
* for (P <- G.withFilter (P => E); ...) ...
1837-
*
1838-
* 5. For any N:
1839-
*
1840-
* for (P <- G; P_1 = E_1; ... P_N = E_N; rest)
1841-
* ==>
1842-
* G.flatMap (P => for (P_1 = E_1; ... P_N = E_N; ...)) if rest contains (<-)
1843-
* G.map (P => for (P_1 = E_1; ... P_N = E_N; ...)) otherwise
1826+
* for (P <- G) yield P ==> G
18441827
*
1845-
* 6. For any N:
1828+
* If betterFors is enabled, P is a variable or a tuple of variables and G is not a withFilter.
18461829
*
1847-
* for (P <- G; P_1 = E_1; ... P_N = E_N; if E; ...)
1848-
* ==>
1849-
* for (TupleN(P, P_1, ... P_N) <-
1850-
* for (x @ P <- G) yield {
1851-
* val x_1 @ P_1 = E_2
1852-
* ...
1853-
* val x_N @ P_N = E_N
1854-
* TupleN(x, x_1, ..., x_N)
1855-
* }; if E; ...)
1856-
*
1857-
* If any of the P_i are variable patterns, the corresponding `x_i @ P_i` is not generated
1858-
* and the variable constituting P_i is used instead of x_i
1859-
*
1860-
* 7. For any N:
1861-
*
1862-
* for (P_1 = E_1; ... P_N = E_N; ...)
1863-
* ==>
1864-
* {
1865-
* val x_N @ P_N = E_N
1866-
* for (...)
1867-
* }
1868-
*
1869-
* 8.
1870-
* for () yield E ==> E
1871-
*
1872-
* (Where empty for-comprehensions are excluded by the parser)
1830+
* for (P <- G) yield E ==> G.map (P => E)
18731831
*
1874-
* If the aliases are not followed by a guard, otherwise an error.
1875-
*
1876-
* With betterFors disabled, the translation is as follows:
1877-
*
1878-
* 1.
1832+
* Otherwise
18791833
*
1880-
* for (P <- G) E ==> G.foreach (P => E)
1834+
* 4.
18811835
*
1882-
* Here and in the following (P => E) is interpreted as the function (P => E)
1883-
* if P is a variable pattern and as the partial function { case P => E } otherwise.
1836+
* for (P_1 <- G_1; P_2 <- G_2; ...) ...
1837+
* ==>
1838+
* G_1.flatMap (P_1 => for (P_2 <- G_2; ...) ...)
18841839
*
1885-
* 2.
1840+
* 5.
18861841
*
1887-
* for (P <- G) yield E ==> G.map (P => E)
1842+
* for (P <- G; if E; ...) ...
1843+
* ==>
1844+
* for (P <- G.withFilter (P => E); ...) ...
18881845
*
1889-
* 3.
1846+
* 6. For any N, if betterFors is enabled:
18901847
*
1891-
* for (P_1 <- G_1; P_2 <- G_2; ...) ...
1848+
* for (P <- G; P_1 = E_1; ... P_N = E_N; P1 <- G1; ...) ...
18921849
* ==>
1893-
* G_1.flatMap (P_1 => for (P_2 <- G_2; ...) ...)
1850+
* G.flatMap (P => for (P_1 = E_1; ... P_N = E_N; ...))
18941851
*
1895-
* 4.
1852+
* 7. For any N, if betterFors is enabled:
18961853
*
1897-
* for (P <- G; E; ...) ...
1898-
* =>
1899-
* for (P <- G.filter (P => E); ...) ...
1854+
* for (P <- G; P_1 = E_1; ... P_N = E_N) ...
1855+
* ==>
1856+
* G.map (P => for (P_1 = E_1; ... P_N = E_N) ...)
19001857
*
1901-
* 5. For any N:
1858+
* 8. For any N:
19021859
*
1903-
* 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; ...)
19041861
* ==>
1905-
* for (TupleN(P_1, P_2, ... P_N) <-
1906-
* for (x_1 @ P_1 <- G) yield {
1907-
* val x_2 @ P_2 = E_2
1862+
* for (TupleN(P, P_1, ... P_N) <-
1863+
* for (x @ P <- G) yield {
1864+
* val x_1 @ P_1 = E_2
19081865
* ...
1909-
* val x_N & P_N = E_N
1910-
* TupleN(x_1, ..., x_N)
1911-
* } ...)
1866+
* val x_N @ P_N = E_N
1867+
* TupleN(x, x_1, ..., x_N)
1868+
* }; if E; ...)
19121869
*
19131870
* If any of the P_i are variable patterns, the corresponding `x_i @ P_i` is not generated
19141871
* and the variable constituting P_i is used instead of x_i
19151872
*
1873+
* 9. For any N, if betterFors is enabled:
1874+
*
1875+
* for (P_1 = E_1; ... P_N = E_N; ...)
1876+
* ==>
1877+
* {
1878+
* val x_N @ P_N = E_N
1879+
* for (...)
1880+
* }
1881+
*
19161882
* @param mapName The name to be used for maps (either map or foreach)
19171883
* @param flatMapName The name to be used for flatMaps (either flatMap or foreach)
19181884
* @param enums The enumerators in the for expression
@@ -2037,86 +2003,59 @@ object desugar {
20372003
case (Tuple(ts1), Tuple(ts2)) => ts1.corresponds(ts2)(deepEquals)
20382004
case _ => false
20392005

2040-
if betterForsEnabled then
2041-
enums match {
2042-
case Nil => body
2043-
case (gen: GenFrom) :: Nil =>
2044-
if gen.checkMode != GenCheckMode.Filtered // results of withFilter have the wrong type
2045-
&& deepEquals(gen.pat, body)
2046-
then gen.expr // avoid a redundant map with identity
2047-
else Apply(rhsSelect(gen, mapName), makeLambda(gen, body))
2048-
case (gen: GenFrom) :: rest
2049-
if rest.dropWhile(_.isInstanceOf[GenAlias]).headOption.forall(e => e.isInstanceOf[GenFrom]) =>
2050-
val cont = makeFor(mapName, flatMapName, rest, body)
2051-
val selectName =
2052-
if rest.exists(_.isInstanceOf[GenFrom]) then flatMapName
2053-
else mapName
2054-
Apply(rhsSelect(gen, selectName), makeLambda(gen, cont))
2055-
case (gen: GenFrom) :: (rest @ GenAlias(_, _) :: _) =>
2056-
val (valeqs, rest1) = rest.span(_.isInstanceOf[GenAlias])
2057-
val pats = valeqs map { case GenAlias(pat, _) => pat }
2058-
val rhss = valeqs map { case GenAlias(_, rhs) => rhs }
2059-
val (defpat0, id0) = makeIdPat(gen.pat)
2060-
val (defpats, ids) = (pats map makeIdPat).unzip
2061-
val pdefs = valeqs.lazyZip(defpats).lazyZip(rhss).map { (valeq, defpat, rhs) =>
2062-
val mods = defpat match
2063-
case defTree: DefTree => defTree.mods
2064-
case _ => Modifiers()
2065-
makePatDef(valeq, mods, defpat, rhs)
2066-
}
2067-
val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom(defpat0, gen.expr, gen.checkMode) :: Nil, Block(pdefs, makeTuple(id0 :: ids)))
2068-
val allpats = gen.pat :: pats
2069-
val vfrom1 = GenFrom(makeTuple(allpats), rhs1, GenCheckMode.Ignore)
2070-
makeFor(mapName, flatMapName, vfrom1 :: rest1, body)
2071-
case (gen: GenFrom) :: test :: rest =>
2072-
val filtered = Apply(rhsSelect(gen, nme.withFilter), makeLambda(gen, test))
2073-
val genFrom = GenFrom(gen.pat, filtered, GenCheckMode.Filtered)
2074-
makeFor(mapName, flatMapName, genFrom :: rest, body)
2075-
case GenAlias(_, _) :: _ =>
2076-
val (valeqs, rest) = enums.span(_.isInstanceOf[GenAlias])
2077-
val pats = valeqs.map { case GenAlias(pat, _) => pat }
2078-
val rhss = valeqs.map { case GenAlias(_, rhs) => rhs }
2079-
val (defpats, ids) = pats.map(makeIdPat).unzip
2080-
val pdefs = valeqs.lazyZip(defpats).lazyZip(rhss).map { (valeq, defpat, rhs) =>
2081-
val mods = defpat match
2082-
case defTree: DefTree => defTree.mods
2083-
case _ => Modifiers()
2084-
makePatDef(valeq, mods, defpat, rhs)
2085-
}
2086-
Block(pdefs, makeFor(mapName, flatMapName, rest, body))
2087-
case _ =>
2088-
EmptyTree //may happen for erroneous input
2089-
}
2090-
else {
2091-
enums match {
2092-
case (gen: GenFrom) :: Nil =>
2093-
Apply(rhsSelect(gen, mapName), makeLambda(gen, body))
2094-
case (gen: GenFrom) :: (rest @ (GenFrom(_, _, _) :: _)) =>
2095-
val cont = makeFor(mapName, flatMapName, rest, body)
2096-
Apply(rhsSelect(gen, flatMapName), makeLambda(gen, cont))
2097-
case (gen: GenFrom) :: (rest @ GenAlias(_, _) :: _) =>
2098-
val (valeqs, rest1) = rest.span(_.isInstanceOf[GenAlias])
2099-
val pats = valeqs map { case GenAlias(pat, _) => pat }
2100-
val rhss = valeqs map { case GenAlias(_, rhs) => rhs }
2101-
val (defpat0, id0) = makeIdPat(gen.pat)
2102-
val (defpats, ids) = (pats map makeIdPat).unzip
2103-
val pdefs = valeqs.lazyZip(defpats).lazyZip(rhss).map { (valeq, defpat, rhs) =>
2104-
val mods = defpat match
2105-
case defTree: DefTree => defTree.mods
2106-
case _ => Modifiers()
2107-
makePatDef(valeq, mods, defpat, rhs)
2108-
}
2109-
val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom(defpat0, gen.expr, gen.checkMode) :: Nil, Block(pdefs, makeTuple(id0 :: ids)))
2110-
val allpats = gen.pat :: pats
2111-
val vfrom1 = GenFrom(makeTuple(allpats), rhs1, GenCheckMode.Ignore)
2112-
makeFor(mapName, flatMapName, vfrom1 :: rest1, body)
2113-
case (gen: GenFrom) :: test :: rest =>
2114-
val filtered = Apply(rhsSelect(gen, nme.withFilter), makeLambda(gen, test))
2115-
val genFrom = GenFrom(gen.pat, filtered, GenCheckMode.Ignore)
2116-
makeFor(mapName, flatMapName, genFrom :: rest, body)
2117-
case _ =>
2118-
EmptyTree //may happen for erroneous input
2119-
}
2006+
enums match {
2007+
case Nil if betterForsEnabled => body
2008+
case (gen: GenFrom) :: Nil =>
2009+
if betterForsEnabled
2010+
&& gen.checkMode != GenCheckMode.Filtered // results of withFilter have the wrong type
2011+
&& deepEquals(gen.pat, body)
2012+
then gen.expr // avoid a redundant map with identity
2013+
else Apply(rhsSelect(gen, mapName), makeLambda(gen, body))
2014+
case (gen: GenFrom) :: (rest @ (GenFrom(_, _, _) :: _)) =>
2015+
val cont = makeFor(mapName, flatMapName, rest, body)
2016+
Apply(rhsSelect(gen, flatMapName), makeLambda(gen, cont))
2017+
case (gen: GenFrom) :: rest
2018+
if betterForsEnabled
2019+
&& rest.dropWhile(_.isInstanceOf[GenAlias]).headOption.forall(e => e.isInstanceOf[GenFrom]) => // possible aliases followed by a generator or end of for
2020+
val cont = makeFor(mapName, flatMapName, rest, body)
2021+
val selectName =
2022+
if rest.exists(_.isInstanceOf[GenFrom]) then flatMapName
2023+
else mapName
2024+
Apply(rhsSelect(gen, selectName), makeLambda(gen, cont))
2025+
case (gen: GenFrom) :: (rest @ GenAlias(_, _) :: _) =>
2026+
val (valeqs, rest1) = rest.span(_.isInstanceOf[GenAlias])
2027+
val pats = valeqs map { case GenAlias(pat, _) => pat }
2028+
val rhss = valeqs map { case GenAlias(_, rhs) => rhs }
2029+
val (defpat0, id0) = makeIdPat(gen.pat)
2030+
val (defpats, ids) = (pats map makeIdPat).unzip
2031+
val pdefs = valeqs.lazyZip(defpats).lazyZip(rhss).map { (valeq, defpat, rhs) =>
2032+
val mods = defpat match
2033+
case defTree: DefTree => defTree.mods
2034+
case _ => Modifiers()
2035+
makePatDef(valeq, mods, defpat, rhs)
2036+
}
2037+
val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom(defpat0, gen.expr, gen.checkMode) :: Nil, Block(pdefs, makeTuple(id0 :: ids)))
2038+
val allpats = gen.pat :: pats
2039+
val vfrom1 = GenFrom(makeTuple(allpats), rhs1, GenCheckMode.Ignore)
2040+
makeFor(mapName, flatMapName, vfrom1 :: rest1, body)
2041+
case (gen: GenFrom) :: test :: rest =>
2042+
val filtered = Apply(rhsSelect(gen, nme.withFilter), makeLambda(gen, test))
2043+
val genFrom = GenFrom(gen.pat, filtered, if betterForsEnabled then GenCheckMode.Filtered else GenCheckMode.Ignore)
2044+
makeFor(mapName, flatMapName, genFrom :: rest, body)
2045+
case GenAlias(_, _) :: _ if betterForsEnabled =>
2046+
val (valeqs, rest) = enums.span(_.isInstanceOf[GenAlias])
2047+
val pats = valeqs.map { case GenAlias(pat, _) => pat }
2048+
val rhss = valeqs.map { case GenAlias(_, rhs) => rhs }
2049+
val (defpats, ids) = pats.map(makeIdPat).unzip
2050+
val pdefs = valeqs.lazyZip(defpats).lazyZip(rhss).map { (valeq, defpat, rhs) =>
2051+
val mods = defpat match
2052+
case defTree: DefTree => defTree.mods
2053+
case _ => Modifiers()
2054+
makePatDef(valeq, mods, defpat, rhs)
2055+
}
2056+
Block(pdefs, makeFor(mapName, flatMapName, rest, body))
2057+
case _ =>
2058+
EmptyTree //may happen for erroneous input
21202059
}
21212060
}
21222061

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
183183

184184
/** An enum to control checking or filtering of patterns in GenFrom trees */
185185
enum GenCheckMode {
186-
case Ignore // neither filter since pattern is trivially irrefutable
186+
case Ignore // neither filter nor check since pattern is trivially irrefutable
187187
case Filtered // neither filter nor check since filtering was done before
188188
case Check // check that pattern is irrefutable
189189
case CheckAndFilter // both check and filter (transitional period starting with 3.2)

compiler/src/dotty/tools/dotc/core/StdNames.scala

-1
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,6 @@ object StdNames {
435435
val asInstanceOfPM: N = "$asInstanceOf$"
436436
val assert_ : N = "assert"
437437
val assume_ : N = "assume"
438-
val betterFors: N = "betterFors"
439438
val box: N = "box"
440439
val break: N = "break"
441440
val build : N = "build"

0 commit comments

Comments
 (0)