-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Rewrite right-associative rewrite #7741
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 2.13.x
Are you sure you want to change the base?
Conversation
ff38712
to
6e754c2
Compare
@lrytz thx for bumping this on the one-year anniversary. |
🎈 |
Here's an example that shows the issue with this approach: class A {
def /: (z: A)(op: Int): A = ???
def self = this
def bar(x: A, y: A) = (x.self /: y.self)(1)
} in
Calling
Just putting the typer in Names and defaults has the same problem, and does it with a lot of complexity (it builds a block for the inner Apply, then takes it apart for outer Applys and inserts them into the block). Here, it should be possible to avoid this complexity and just build the block at the very end, after type checking the full application ( |
A different issue caused by this PR is that we get a lint warning on
before the parser would spit out
but now it's |
Thanks @lrytz for the insight. If I wake up later today, I will try to grok it. I wasn't sure if returning to this PR was worth the communal trouble; should I change the title to "Complexify right-associative rewrite"? If we had mini-phases, we could have a mini-phase called There's a similar challenge in the stabilization PR about whether to muck with trees in-flight, though there the effect is artificial rather than actual order of evaluation. |
I like the the simplification, it seems more tractable
Yeah.. I'm looking at scala/bug#11756 tomorrow, I think it would be good to have in 2.13.2, maybe just a minimal fix without changing the strategy. |
6e754c2
to
7d8ebee
Compare
@lrytz A year later, I piggybacked on your fix for stabilization. Edit: I see the
|
The previous easy tweak worked, but now:
I'll try a local bootstrap after all. ...oh I guess it's fatal on CI now. More late pandemic brain fog. Except for the part where
Rebroke this:
|
effa62a
to
8dd8424
Compare
b6afeeb
to
c646f90
Compare
Reviewing previous comments, I see the initial effort in 2019 needed Currently, there are a few old TODO comments I wouldn't mind addressing that are out of scope;
|
Does anyone get the Merriam-Webster email? Today's word is "steadfast". Their quiz:
|
c646f90
to
1261ad5
Compare
Parser marks application as right-associative. Typer identifies subexpressions to pre-compute in order to preserve left-to-right evaluation.
2883426
to
92bd67a
Compare
cb5f090
to
15b6afb
Compare
Rebased and followed up on the items. Did not split the first commit. Did remove the two special |
def isStab(x: Tree) = x match { case ValDef(_, nm, _, _) => nm.startsWith(nme.STABILIZER_PREFIX) case _ => false } | ||
val (stabs, rassocs) = all.partition(isStab) | ||
context.pendingStabilizers = Nil | ||
Block(rassocs ++ stabs.reverse, expr).setPos(expr.pos).setType(expr.tpe) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can there be multiple in rassocs
? reverse?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, and this is correctly ordered, as I'm sure a test demonstrates.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
def f = hashCode :: toString :: Nil
def f: List[Any] = {
final <synthetic> <artifact> val rassoc$2: Int = C.this.hashCode();
final <synthetic> <artifact> val rassoc$1: String = C.this.toString();
scala.`package`.Nil.::[String](rassoc$1).::[Any](rassoc$2)
};
case view @ Apply(coercion, coerced :: Nil) if view.hasAttachment[AppliedImplicitView.type] && shouldInsertRassocs => | ||
treeCopy.Apply(view, coercion, addStabilizers(coerced) :: Nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this piece made me wonder.
so the example is this
class L
object E extends L
class C(val h: Int, val t: L) extends L
class D(val l: () => L) {
def #:: (o: Int): L = new C(o, l())
}
object T {
implicit def toD(l: => L): D = new D(() => l)
}
a #:: b #:: E
When the outer implicit conversion is typed (adaptToMember, T.toD(T.toD(E).#::(rassoc$1))
)
- we end up in
typedApply
as expected. The argumentT.toD(E).#::(rassoc$1)
is typed withoutAPPSELmode
, that flag is removed intypedArg
. - but the argument tree is already typed, and importantly,
context.pendingStabilizers
is already populated withrassoc$1
- at the beginning of
def typed
shouldInsertStabilizers
is true, we save the pending one in a local and setcontext.pendingStabilizers = Nil
- this means the stabilizer is not added by mistake. the logic around that in
def typed
doesn't work with trees that are already typed
we can probably fix that instead of the special case here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no emoji reaction with blurry eyes, but I'll think about it later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll try turning context.pendingStabilizers
into a tree attachment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a commit, but it's not replacing context.pendingStabilizers
unfortunately. Maybe you have a better idea, I added some comments to try to explain what this is about.
5839607
to
9240ec7
Compare
9240ec7
to
4bb452f
Compare
Bug found while trying stuff
The rassoc transformation is not done (not in your version, and not with my commit on top). |
OK, I'm awake. Thanks for the code comments, which I read, it's useful to have a published paper that explains the theoretical basis. I see why you didn't like the "special case" (I don't think you liked it two years ago). I'll have a second coffee before applying myself to review. My first thought was that the new attachment is a different way to pronounce "tomato", but it's probably also a cleaner basis for fixing bugs in the general approach. |
What would really help: a single test file for everything around stabilizers and rassocs, their combinations, interaction with implicit params and conversions (and other features?). Scala 3 seems to get it all right, at least the few examples I tried. Can we align with the way it's implemented there? I didn't take a look. |
Defer any rewriting from parser to typedApply.
The application is typechecked in the normal way
and evaluation order rejiggered after. In particular,
there is no need to re-typecheck after re-inlining,
for more precise types.
Original intention was to piggyback on the fix for 1980 by inlining a bit more, but typing is largely done by the time the rewrite is rewritten. This is retronym's suggested follow-up, perhaps.
Fixes scala/bug#4518
Fixes scala/bug#5073
Fixes scala/bug#10693
Fixes scala/bug#11117
Aggravates bugs 5073 (pos/tcpoly_ticket2096.scala) and maybe 11397 (run/t4225e.scala, which demonstrates 10693).