-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Closed
Description
Compiler version
3.7.0, 3.7.1-RC1, 3.7.2-RC1
Minimized example
//> using scala "3.7.2-RC1"
//> using options "-preview", "-Vprint:typer"
@main def main =
println:
for
a <- List(1)
b <- List(a)
yield bFor comparison, the same code with older compiler version:
//> using scala "3.6.4"
//> using options "-language:experimental.betterFors", "-Vprint:typer"
@main def main =
println:
for
a <- List(1)
b <- List(a)
yield bOutput
In 3.7.0, 3.7.1-RC1, 3.7.2-RC1 the trailing map is not removed:
@main def main: Unit =
println(
List.apply[Int]([1 : Int]*).flatMap[Int]((a: Int) =>
List.apply[Int]([a : Int]*).map[Int]((b: Int) => b))
)In 3.6.4 the trailing map is removed:
@main def main: Unit =
println(
List.apply[Int]([1 : Int]*).flatMap[Int]((a: Int) =>
List.apply[Int]([a : Int]*))
)Expectation
Have the trailing map removed.
Here is more complex case. The lack of trailing map removal causes 20% lower scores in this microbenchmark suite. Applies to all effect systems.
Activity
sjrd commentedon Jun 24, 2025
This transformation was moved to a later phase. If you print with
-Vprint:dropForMap, you will see that the call tomapis gone:WojciechMazur commentedon Jun 24, 2025
The mentioned change was introduce in #22619 - is it possible that cases in benchmarks where testing case where result of trailing map was different from previous transformation?
marcinzh commentedon Jun 24, 2025
The trailing map is present when compiled with 3.7.2-RC2:
The trailing map is removed when compiled with 3.6.4:
marcinzh commentedon Jun 24, 2025
@WojciechMazur I'm not sure. Some effect systems could be accused of doing something weird with the types. ZIO, Turbolift and Kyo rely on variance and intersection types. Also in Kyo and Turbolift
mapandflatMapare macros (a microoptimization to save an allocation).But the Cats-MTL case does none of these, yet it appears the
betterForproblem applies to it as well.som-snytt commentedon Jun 24, 2025
Debug for the failing test says it has the attachment but avoids changing the result type.
Probably it has to unwrap the conversion.
I haven't looked at what 3.6 does, but I will see what changed and update here.
sjrd commentedon Jun 24, 2025
3.6 blindly removed the
mapbased on syntax only, without type information. That caused a lot of regressions, so we changed the spec. Now typer always insertsmapand types it.dropForMapdrops the ones that do not break the inferred result type.som-snytt commentedon Jun 24, 2025
Thanks, I just saw. I'll see if there is a coping mechanism, after I finish this coffee.
(I was concerned I might have touched something in Desugar for linting pattern vars in for comprehensions, which also depends on attachments.)
marcinzh commentedon Jun 25, 2025
I wonder if the compiler considers types
Foo[T],Foo[T & Any]orFoo[T & T]as the same type, in the #22619 check?marcinzh commentedon Jun 25, 2025
As I understand, the #23416 fixes the Cats-MTL case.
ZIO, Turbolift and Kyo are quite different. I'm posting minimized versions for each of these effect systems, hoping it would help their cases get covered too:
ZIO:
Turbolift:
Kyo:
Additionally, here is a zero-dependency version that mimics the common typing technique used in each of those 3 effect systems:IGNORE! this minimization is incorrect
som-snytt commentedon Jun 26, 2025
Thanks for the minimization.
Am I right that you're asking about the residual flatMap? I looked briefly this morning before I was properly awake but didn't get back to it.
marcinzh commentedon Jun 26, 2025
My bad, the zero-dependency failed to be a minimization.
I suspected that the intersection type, which grows with each
flatMap(a common feature of ZIO, Turbolift and Kyo), might have been responsible for triggerring the "leave trailing map intact" path:marcinzh commentedon Jun 26, 2025
Another zero-dependency minimization:
The key is the implicit parameter in definition of
map.This applies to ZIO and Kyo: they use implicit parameter for stuff like type tags and tracing.
In Turbolift
mapdoesn't have implicit parameters, but it's aninlinefunction. Same in Kyo.som-snytt commentedon Jun 28, 2025
The second commit in the PR is for trailing implicit args following the function arg.
(That also drops the map in
for (x <- Future(42)) yield x.)I'll take a look at turbolift, but it involves transforming the inlined expression. Maybe that will prove easy enough.
(I made a start by re-using the existing proxy.)
som-snytt commentedon Jun 29, 2025
Worth mentioning I used to turn off directives by changing
usingtoabusing, but now I use the nicer technique of just adding a leading slash. It's a small inconvenience that directives must be on top lines and unmixed. (Partest would always examine 10 lines.)Now,
was 3.6
I'm not likely to look at kyo.