Skip to content

Commit

Permalink
WIP Reconsider contracts for derived type bindings
Browse files Browse the repository at this point in the history
may eventually resolve eclipse-jdt#2210

+ revert part of eclipse-jdt#2173
+ play with annotated TVB as the 'original' type
  • Loading branch information
stephan-herrmann committed Mar 24, 2024
1 parent aeefecb commit d762639
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 28 deletions.
Expand Up @@ -2323,7 +2323,17 @@ public void addResolutionListener(IQualifiedTypeResolutionListener resolutionLis


public TypeBinding getUnannotatedType(TypeBinding typeBinding) {
return this.typeSystem.getUnannotatedType(typeBinding);
TypeBinding unannotatedType = this.typeSystem.getUnannotatedType(typeBinding);
if (typeBinding.getClass() == TypeVariableBinding.class && unannotatedType.hasTypeAnnotations()) {
for (TypeBinding derived : this.typeSystem.getAnnotatedTypes(unannotatedType)) {
if (!derived.hasTypeAnnotations())
return derived;
}
TypeBinding clone = ((TypeVariableBinding) unannotatedType).clone(null);
this.typeSystem.cacheDerivedType(unannotatedType, unannotatedType, clone);
return clone;
}
return unannotatedType;
}

// Given a type, return all its variously annotated versions.
Expand Down
Expand Up @@ -20,7 +20,6 @@
package org.eclipse.jdt.internal.compiler.lookup;

import java.util.HashMap;
import java.util.function.Consumer;

import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
Expand Down Expand Up @@ -83,26 +82,11 @@ public PTBKey(ReferenceBinding type, TypeBinding[] arguments, ReferenceBinding e
if (type instanceof UnresolvedReferenceBinding)
((UnresolvedReferenceBinding) type).addWrapper(this, environment);
if (arguments != null) {
for (int i = 0; i < arguments.length; i++) {
TypeBinding argument = arguments[i];
for (TypeBinding argument : arguments) {
if (argument instanceof UnresolvedReferenceBinding)
((UnresolvedReferenceBinding) argument).addWrapper(this, environment);
if (argument.hasNullTypeAnnotations())
this.tagBits |= TagBits.HasNullTypeAnnotation;
if (argument.getClass() == TypeVariableBinding.class) {
final int idx = i;
TypeVariableBinding typeVariableBinding = (TypeVariableBinding) argument;
Consumer<TypeVariableBinding> previousConsumer = typeVariableBinding.updateWhenSettingTypeAnnotations;
typeVariableBinding.updateWhenSettingTypeAnnotations = (newTvb) -> {
// update the TVB argument and simulate a re-hash:
ParameterizedTypeBinding[] value = HashedParameterizedTypes.this.hashedParameterizedTypes.get(this);
arguments[idx] = newTvb;
HashedParameterizedTypes.this.hashedParameterizedTypes.put(this, value);
// for the unlikely case of multiple PTBKeys referring to this TVB chain to the next consumer:
if (previousConsumer != null)
previousConsumer.accept(newTvb);
};
}
}
}
}
Expand Down Expand Up @@ -240,6 +224,18 @@ public final TypeBinding getUnannotatedType(TypeBinding type) {
type = resolvedType;
}
}
if (type.getClass() == TypeVariableBinding.class) {
// register the type as normal ...
if (type.id == TypeIds.NoId) {
int typesLength = this.types.length;
if (this.typeid == typesLength)
System.arraycopy(this.types, 0, this.types = new TypeBinding[typesLength * 2][], 0, typesLength);
this.types[type.id = this.typeid++] = new TypeBinding[4];
this.types[type.id][0] = type;
}
// ... but rely on prototype() for getting the "original" type as per the type parameter declaration
return type.prototype();
}
try {
if (type.id == TypeIds.NoId) {
if (type.hasTypeAnnotations())
Expand Down Expand Up @@ -269,16 +265,13 @@ public final TypeBinding getUnannotatedType(TypeBinding type) {
* If it itself is already registered as the key unannotated type of its family,
* create a clone to play that role from now on and swap types in the types cache.
*/
public void forceRegisterAsDerived(TypeVariableBinding derived) {
public void forceRegisterAsDerived(TypeBinding derived) {
int id = derived.id;
if (id != TypeIds.NoId && this.types[id] != null) {
TypeBinding unannotated = this.types[id][0];
if (unannotated == derived) { //$IDENTITY-COMPARISON$
// was previously registered as unannotated, replace by a fresh clone to remain unannotated:
this.types[id][0] = unannotated = derived.clone(null);
if (derived.updateWhenSettingTypeAnnotations != null) {
derived.updateWhenSettingTypeAnnotations.accept((TypeVariableBinding) unannotated);
}
}
// proceed as normal:
cacheDerivedType(unannotated, derived);
Expand Down
Expand Up @@ -44,7 +44,6 @@

import java.util.Arrays;
import java.util.Set;
import java.util.function.Consumer;

import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
Expand Down Expand Up @@ -78,13 +77,10 @@ public class TypeVariableBinding extends ReferenceBinding {
public char[] genericTypeSignature;
LookupEnvironment environment;

/*
* In one particular situation a TVB will be cloned and the clone will be used as the 'naked' type
* within TypeSystem. This may require some updating inside TypeSystem's hash structure.
*/
Consumer<TypeVariableBinding> updateWhenSettingTypeAnnotations;
private ReferenceBinding prototype;

public TypeVariableBinding(char[] sourceName, Binding declaringElement, int rank, LookupEnvironment environment) {
this.prototype = this;
this.sourceName = sourceName;
this.declaringElement = declaringElement;
this.rank = rank;
Expand All @@ -97,6 +93,7 @@ public TypeVariableBinding(char[] sourceName, Binding declaringElement, int rank

// for subclass CaptureBinding
protected TypeVariableBinding(char[] sourceName, LookupEnvironment environment) {
this.prototype = this;
this.sourceName = sourceName;
this.modifiers = ClassFileConstants.AccPublic | ExtraCompilerModifiers.AccGenericSignature; // treat type var as public
this.tagBits |= TagBits.HasTypeVariable;
Expand All @@ -122,8 +119,13 @@ public TypeVariableBinding(TypeVariableBinding prototype) {
this.environment = prototype.environment;
prototype.tagBits |= TagBits.HasAnnotatedVariants;
this.tagBits &= ~TagBits.HasAnnotatedVariants;
this.prototype = prototype.prototype;
}

@Override
public TypeBinding prototype() {
return this.prototype;
}
/**
* Returns true if the argument type satisfies all bounds of the type parameter
* @param location if non-null this may be used for reporting errors relating to null type annotations (if enabled)
Expand Down

0 comments on commit d762639

Please sign in to comment.