Skip to content

Harden erasure of TermRefs #15658

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

Merged
merged 2 commits into from
Jul 14, 2022
Merged

Harden erasure of TermRefs #15658

merged 2 commits into from
Jul 14, 2022

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Jul 12, 2022

If a getter TermRef has a MethodType, erase it to the erasure of the method
result type.

Fixes #15649

Since the fault in #15649 is highly non-deterministic, I can only guess what the reason
was. I think what happened was that the TermRef was created very late, when the TermRef
was already a getter. I.e. after phase Getters, which is itself after Erasure. The
whole thing was launched from the code that generates static forwarders in the backend.

Type erasure is run at erasure phase, but if there is no previous denotation of the TermRef,
it will keep the first one it read, which would have the MethodType as underlying type.
The end result was that the TermRef was erased to a method type, where it should have
been erased to the result type. Consequently, we ended up with a MethodType as the
parameter type of another method, which is unexpected.

But all that is just a guess. I am not even sure this PR will fix the problem since it
comes up so rarely.

If a getter TermRef has a MethodType, erase it to the erasure of the method
result type.

Fixes scala#15649

Since the fault in scala#15649 is highly non-deterministic, I can only guess what the reason
was. I think what happened was that the TermRef was created very late, when the TermRef
was already a getter. I.e. after phase `Getters`, which is itself after `Erasure`. The
whole thing was launched from the code that generates static forwarders in the backend.

Type erasure is run at erasure phase, but if there is no previous denotation of the `TermRef`,
it will keep the first one it read, which would have the `MethodType` as underlying type.
The end result was that the `TermRef` was erased to a method type, where it should have
been erased to the result type. Consequently, we ended up with a MethodType as the
parameter type of another method, which is unexpected.

But all that is just a guess. I am not even sure this PR will fix the problem since it
comes up so rarely.
@odersky
Copy link
Contributor Author

odersky commented Jul 12, 2022

I think in general it's a bad idea to do static forwarder generation in the backend. It should be a proper miniphase, then we would most likely avoid problems like this one.

@odersky odersky requested a review from griggt July 12, 2022 15:12
@@ -687,6 +689,10 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
tp
}

private def underlyingOfTermRef(tp: TermRef)(using Context) = tp.widen match
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably deserves a comment referencing the issue. Otherwise someone will come here later, figure that this is useless, and remove it.

Copy link
Contributor

@griggt griggt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested this extensively, and was unable to get the reproducer test case to crash with this change in place. The community project from which it was minimized, zio-config, also compiles again with this change.

So at least in that sense, this PR seems to fix the problem.

I was also able to confirm that the getter TermRef has its denotation replaced with a new UniqueRefDenotation using the logic added in e609851, which as far as I can tell is what caused this problem to appear.

I agree with the suggestion to add a code comment referencing the issue.

@griggt griggt added the backport:nominated If we agree to backport this PR, replace this tag with "backport:accepted", otherwise delete it. label Jul 13, 2022
@griggt griggt assigned odersky and unassigned griggt Jul 13, 2022
@odersky odersky merged commit abc8cac into scala:main Jul 14, 2022
@odersky odersky deleted the fix-15649 branch July 14, 2022 15:03
@griggt griggt added backport:accepted This PR needs to be backported, once it's been backported replace this tag by "backport:done" and removed backport:nominated If we agree to backport this PR, replace this tag with "backport:accepted", otherwise delete it. labels Jul 14, 2022
@Kordyjan Kordyjan added this to the 3.2.0 backports milestone Jul 26, 2022
@Kordyjan Kordyjan added backport:done This PR was successfully backported. and removed backport:accepted This PR needs to be backported, once it's been backported replace this tag by "backport:done" labels Jul 26, 2022
Kordyjan added a commit that referenced this pull request Jul 27, 2022
@Kordyjan Kordyjan modified the milestones: 3.2.0 backports, 3.2.1 Aug 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport:done This PR was successfully backported.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Assertion failure in TypeErasure#sigName: "no sig for MethodType"
4 participants