From d76263903d6bdc61b3fff287cbf7683a80cd6898 Mon Sep 17 00:00:00 2001 From: Stephan Herrmann Date: Sun, 24 Mar 2024 13:58:20 +0100 Subject: [PATCH] WIP Reconsider contracts for derived type bindings may eventually resolve #2210 + revert part of #2173 + play with annotated TVB as the 'original' type --- .../compiler/lookup/LookupEnvironment.java | 12 ++++++- .../internal/compiler/lookup/TypeSystem.java | 35 ++++++++----------- .../compiler/lookup/TypeVariableBinding.java | 14 ++++---- 3 files changed, 33 insertions(+), 28 deletions(-) diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java index d8b4f992c7c..00a577f073d 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java @@ -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. diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java index df729cb7d29..287fcb68287 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java @@ -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; @@ -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 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); - }; - } } } } @@ -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()) @@ -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); diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java index f7ef22e0f74..44f0e2afd34 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java @@ -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; @@ -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 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; @@ -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; @@ -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)