Skip to content

Fix #8799: Make sure signatures are computed before erasure #8819

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 5 commits into from
May 24, 2020

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Apr 28, 2020

Some symbols change their signatures after erasure,
e.g. getters with Unit type or constructors taking an outer parameter.
Since signatures are assumed to be stable for a complete run,
we need to always compute signatures for NamedTypes before erasure.

val lastd = lastDenotation
if (lastd != null) lastd.signature
val isErased = ctx.erasedTypes
if lastd != null && !isErased then lastd.signature
Copy link
Member

Choose a reason for hiding this comment

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

ctx.erasedTypes being false does not mean that lastd itself is before erasure, for that one would have to check last.validFor.firstPhaseId < ctx.erasurePhase.id I think (this might be off by one).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, good point. I have fixed it now.

else symbol.asSeenFrom(prefix).signature
}

/** The signature of the current denotation if it is known without forcing.
* Otherwise the signature of the current symbol if it is known without forcing.
* Otherwise NotAMethod.
*/
private def currentSignature(implicit ctx: Context): Signature =
Copy link
Member

Choose a reason for hiding this comment

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

currentSignature is passed as an argument to disambiguate which passes it to Denotation#atSignature. If we're after erasure and the signature of the denotation is different from the pre-erasure signature that currentSignature, then atSignature would fail to match anything, wouldn't it? Or is it this OK because overloaded denotations do not appear after erasure at all? If so then currentSignature wouldn't need to do anything special.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, after erasure all references should be symbolic, so there's no need to do overloading resolution.

@smarter smarter assigned odersky and unassigned smarter Apr 29, 2020
@odersky odersky assigned smarter and unassigned odersky May 3, 2020
Copy link
Member

@smarter smarter left a comment

Choose a reason for hiding this comment

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

I'll try to add a test for this PR tomorrow

@odersky
Copy link
Contributor Author

odersky commented May 5, 2020

@smarter I am done with it (meaning both I think it's finished for now and I don't want to do anything further on this). OK with you to merge ?

@smarter
Copy link
Member

smarter commented May 5, 2020

I'd like to add a test before merging, I'll take care of it.

@smarter
Copy link
Member

smarter commented May 7, 2020

Just pushed a test which runs into another issue: after the getters phase, vals become defs, which means their signature changes from Signature.NotAMethod to something else. Should we change sigFromDenot to always travel to a pre-getters phase, or should we try to change signature computation to handle getters specially?

@smarter
Copy link
Member

smarter commented May 7, 2020

Should we change sigFromDenot to always travel to a pre-getters phas

Ah, but this isn't that easy since we use currentSignature to do overload resolution, so it has to match the signatures we see in the current phase which is why the previous PR was problematic: #8813 (comment)

@smarter
Copy link
Member

smarter commented May 9, 2020

Other possible fix: always return NotAMethod for the signature of an ExprType, this way there's no difference before and after getters. I tried it and all our tests still pass so it might be viable.

@smarter
Copy link
Member

smarter commented May 10, 2020

@odersky Please have a look at the latest commit: d02cbe1, there's one remaining issue related to CompleteJavaEnums, but I'm not familiar with that phase, do you see any reason it could not be run after erasure?

odersky and others added 5 commits May 22, 2020 16:19
Some symbols change their signatures after erasure,
e.g. getters with Unit type or constructors taking an outer parameter.
Since signatures are assumed to be stable for a complete run,
we need to always compute signatures for NamedTypes before ersure.
Getters will replace `val x: Int`, by `def x: Int`, before this commit,
this lead to the signature of `x` changing from `Signature.NotAMethod`
to `Signature(Nil, scala.Int)` but we need signatures to be stable
pre-erasure to disambiguate overloads. This commit fixes this by
changing ExprType#signature to always return `NotAMethod`, this should
not break anything since we do not allow overloads which only differ in
their result type anyway.

This commit also adds tests to make sure that the invariants related to
signatures are not violated, currently there is one class of failure
related to enums which is fixed in the next commit.
CompleteJavaEnums changes some signatures (it adds extra constructor
parameters to classes extending java.lang.Enum), so it is not allowed to
run before Erasure (this is enforced by the check added in TreeChecker
in the previous commit).

Moving CompleteJavaEnums after Erasure required one change, prior to
this commit, constructor parameter were added to enum cases in two
different places:
- `def $new(...) = { new E { ... } }` was handled by transformDefDef
- `val Foo = new E { ... }` was handled by transformTemplate

It turns out that we can just let transformTemplate handle both cases,
this simplifies the code and means that the Mixin phase can run after
CompleteJavaEnums in the same group and see the transformed
constructors.
Copy link
Member

@smarter smarter left a comment

Choose a reason for hiding this comment

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

@odersky please have a look at the latest commit which fixed the issue with the enum phase

@smarter smarter removed their assignment May 22, 2020
@odersky
Copy link
Contributor Author

odersky commented May 24, 2020

Last commit LGTM

@odersky odersky merged commit 2975434 into scala:master May 24, 2020
@odersky odersky deleted the fix-#8799-v2 branch May 24, 2020 11:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Signatures cached in NamedType can become stale, some cache invalidation is needed
2 participants