Skip to content
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

Reconsider contracts for derived type bindings #2210

Open
stephan-herrmann opened this issue Mar 24, 2024 · 1 comment · May be fixed by #2211
Open

Reconsider contracts for derived type bindings #2210

stephan-herrmann opened this issue Mar 24, 2024 · 1 comment · May be fixed by #2211
Assignees

Comments

@stephan-herrmann
Copy link
Contributor

Follow-up from #2173:

Before JSR 308, the contract of type bindings was simply: the 'same' type is always represented by the same instance of TypeBinding, allowing for == to be used for checking type equality.

With type annotations in the picture, and specifically with the compiler's interest to fully evaluate those for null analysis, identity of type bindings has become a more complex topic.

The new methods TypeBinding.equalsEquals() and TypeBinding.notEquals() consider those types as equal that have the same id. The intention is that types that differ only in type annotations should share the same id.

Internally, methods like TypeSystem.getUnannotatedType() are based on the invariant that each array TypeSystem.types[id] has the "unannotated" type at position 0.

Caveat: while all types with the same id appear in the same TypeSystem.types[id], that array may also contain other derived types with different id, e.g., array, parameterized, raw types of the generic type.

That invariant may be broken, when a type variable has an annotation (semantically a declaration annotation on the type parameter, but technically a type annotation). In this case the type at position 0 is "the original type", which may get annotations set, possibly after the type has been registered in the AnnotatableTypeSystem. For that situation TypeSystem.forceRegisterAsDerived() implements an artificial swap, inserting a clone without annotations into position 0 and moving "the original type" to position 1. This caused problems when the original type was already used in a PTBKey - the problem locally fixed in #2173 .

Additionally, we have the concept of TypeBinding.prototype(). Normally this.prototype() == this, but when an annotated variant is created by ATS, then a clone is created, which remembers the original as its "prototype".

Hence we have an interesting (non-trivial) relationship between TypeSystem.getUnannotatedType() and TypeBinding.prototype(), which deserves a fresh look.

In this issue I plan to investigate the relationships between "unannotated type", "originally declared type" and "prototype". The initial question will be: Is it suitable to use the "unannotated type" as the primordial concept or should a type variable with an annotation (technically type annotation, semantically declaration annotation, see above) be considered the primordial thing, and the unannotated variant a derived thing in this case?

If these things can be clearly separated, then all magic in TypeSystem.forceRegisterAsDerived() plus the fix in #2173 could become obsolete, hopefully providing a more consistent overall story.

@stephan-herrmann
Copy link
Contributor Author

@srikanth-sankaran feel free to join me at your leisure

stephan-herrmann added a commit to stephan-herrmann/eclipse.jdt.core that referenced this issue Mar 24, 2024
may eventually resolve eclipse-jdt#2210

+ revert part of eclipse-jdt#2173
+ play with annotated TVB as the 'original' type
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 a pull request may close this issue.

1 participant