Skip to content

Commit

Permalink
* Review and incremental cleanup of sealed types implementation. (#3095)
Browse files Browse the repository at this point in the history
  • Loading branch information
srikanth-sankaran authored Oct 16, 2024
1 parent 126c7b6 commit 09f7d68
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,7 @@ else if (this.referenceBinding.isAnnotationType())
attributesNumber += generateBootstrapMethods(this.bootstrapMethods);
}
if (this.targetJDK >= ClassFileConstants.JDK17) {
// add record attributes
attributesNumber += generatePermittedTypeAttributes();
attributesNumber += generatePermittedSubclassesAttribute();
}
// Inner class attribute
int numberOfInnerClasses = this.innerClassesBindings == null ? 0 : this.innerClassesBindings.size();
Expand Down Expand Up @@ -2852,10 +2851,9 @@ private int generateNestAttributes() {
nAttrs += generateNestHostAttribute();
return nAttrs;
}
private int generatePermittedTypeAttributes() {
SourceTypeBinding type = this.referenceBinding;
private int generatePermittedSubclassesAttribute() {
int localContentsOffset = this.contentsOffset;
ReferenceBinding[] permittedTypes = type.permittedTypes();
ReferenceBinding[] permittedTypes = this.referenceBinding.permittedTypes();
int l = permittedTypes != null ? permittedTypes.length : 0;
if (l == 0)
return 0;
Expand All @@ -2864,6 +2862,14 @@ private int generatePermittedTypeAttributes() {
if (exSize + localContentsOffset >= this.contents.length) {
resizeContents(exSize);
}
/*
* PermittedSubclasses_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_classes;
u2 classes[number_of_classes];
}
*/
int attributeNameIndex =
this.constantPool.literalIndex(AttributeNamesConstants.PermittedSubclasses);
this.contents[localContentsOffset++] = (byte) (attributeNameIndex >> 8);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ void cachePartsFrom(IBinaryType binaryType, boolean needFieldsAndMethods) {
// and still want to use binaries passed that point (e.g. type hierarchy resolver, see bug 63748).
this.typeVariables = Binding.NO_TYPE_VARIABLES;
this.superInterfaces = Binding.NO_SUPERINTERFACES;
this.permittedTypes = Binding.NO_PERMITTEDTYPES;
this.permittedTypes = Binding.NO_PERMITTED_TYPES;

// must retrieve member types in case superclass/interfaces need them
this.memberTypes = Binding.NO_MEMBER_TYPES;
Expand Down Expand Up @@ -2632,7 +2632,7 @@ public String toString() {
}

if (this.permittedTypes != null) {
if (this.permittedTypes != Binding.NO_PERMITTEDTYPES) {
if (this.permittedTypes != Binding.NO_PERMITTED_TYPES) {
buffer.append("\n\tpermits : "); //$NON-NLS-1$
for (int i = 0, length = this.permittedTypes.length; i < length; i++) {
if (i > 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public abstract class Binding {
public static final ReferenceBinding[] ANY_EXCEPTION = new ReferenceBinding[] { null }; // special handler for all exceptions
public static final FieldBinding[] NO_FIELDS = new FieldBinding[0];
public static final MethodBinding[] NO_METHODS = new MethodBinding[0];
public static final ReferenceBinding[] NO_PERMITTEDTYPES = new ReferenceBinding[0];
public static final ReferenceBinding[] NO_PERMITTED_TYPES = new ReferenceBinding[0];
public static final ReferenceBinding[] NO_SUPERINTERFACES = new ReferenceBinding[0];
public static final ReferenceBinding[] NO_MEMBER_TYPES = new ReferenceBinding[0];
public static final TypeVariableBinding[] NO_TYPE_VARIABLES = new TypeVariableBinding[0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ void buildAnonymousTypeBinding(SourceTypeBinding enclosingType, ReferenceBinding
}
}
anonymousType.typeBits |= inheritedBits;
anonymousType.setPermittedTypes(Binding.NO_PERMITTEDTYPES); // JLS 15 JEP 360 Preview - Sec 15.9.5
anonymousType.setPermittedTypes(Binding.NO_PERMITTED_TYPES);
if (supertype.isInterface()) {
anonymousType.setSuperClass(getJavaLangObject());
anonymousType.setSuperInterfaces(new ReferenceBinding[] { supertype });
Expand All @@ -115,7 +115,8 @@ void buildAnonymousTypeBinding(SourceTypeBinding enclosingType, ReferenceBinding
} else {
anonymousType.setSuperClass(supertype);
anonymousType.setSuperInterfaces(Binding.NO_SUPERINTERFACES);
checkForEnumSealedPreview(supertype, anonymousType);
if (supertype.isEnum() && supertype instanceof SourceTypeBinding superEnum)
implicitlySealEnumHierarchy(superEnum, anonymousType);
TypeReference typeReference = this.referenceContext.allocation.type;
if (typeReference != null) { // no check for enum constant body
this.referenceContext.superclass = typeReference;
Expand Down Expand Up @@ -151,25 +152,19 @@ void buildAnonymousTypeBinding(SourceTypeBinding enclosingType, ReferenceBinding
anonymousType.verifyMethods(environment().methodVerifier());
}

private void checkForEnumSealedPreview(ReferenceBinding supertype, LocalTypeBinding anonymousType) {
if (!JavaFeature.SEALED_CLASSES.isSupported(compilerOptions())
|| !supertype.isEnum()
|| !(supertype instanceof SourceTypeBinding))
return;

SourceTypeBinding sourceSuperType = (SourceTypeBinding) supertype;
ReferenceBinding[] permTypes = sourceSuperType.permittedTypes();
int sz = permTypes == null ? 0 : permTypes.length;
if (sz == 0) {
permTypes = new ReferenceBinding[] {anonymousType};
} else {
System.arraycopy(permTypes, 0,
permTypes = new ReferenceBinding[sz + 1], 0,
sz);
permTypes[sz] = anonymousType;
private void implicitlySealEnumHierarchy(SourceTypeBinding superEnum, LocalTypeBinding anonymousType) {
if (JavaFeature.SEALED_CLASSES.isSupported(compilerOptions())) {
ReferenceBinding[] permittedTypes = superEnum.permittedTypes();
int sz = permittedTypes == null ? 0 : permittedTypes.length;
if (sz == 0) {
permittedTypes = new ReferenceBinding[] { anonymousType };
} else {
System.arraycopy(permittedTypes, 0, permittedTypes = new ReferenceBinding[sz + 1], 0, sz);
permittedTypes[sz] = anonymousType;
}
anonymousType.modifiers |= ClassFileConstants.AccFinal;
superEnum.setPermittedTypes(permittedTypes);
}
anonymousType.modifiers |= ClassFileConstants.AccFinal; // JLS 15 / sealed preview/Sec 8.9.1
sourceSuperType.setPermittedTypes(permTypes);
}

void buildComponents() {
Expand Down Expand Up @@ -1183,7 +1178,7 @@ private boolean connectSuperclass() {
if (sourceType.id == TypeIds.T_JavaLangObject) { // handle the case of redefining java.lang.Object up front
sourceType.setSuperClass(null);
sourceType.setSuperInterfaces(Binding.NO_SUPERINTERFACES);
sourceType.setPermittedTypes(Binding.NO_PERMITTEDTYPES);
sourceType.setPermittedTypes(Binding.NO_PERMITTED_TYPES);
if (!sourceType.isClass())
problemReporter().objectMustBeClass(sourceType);
if (this.referenceContext.superclass != null || (this.referenceContext.superInterfaces != null && this.referenceContext.superInterfaces.length > 0))
Expand Down Expand Up @@ -1310,7 +1305,7 @@ void connectImplicitPermittedTypes() {
}
void connectPermittedTypes() {
SourceTypeBinding sourceType = this.referenceContext.binding;
sourceType.setPermittedTypes(Binding.NO_PERMITTEDTYPES);
sourceType.setPermittedTypes(Binding.NO_PERMITTED_TYPES);
if (sourceType.id == TypeIds.T_JavaLangObject || sourceType.isEnum()) // already handled
return;

Expand All @@ -1323,30 +1318,24 @@ void connectPermittedTypes() {
nextPermittedType : for (int i = 0; i < length; i++) {
TypeReference permittedTypeRef = this.referenceContext.permittedTypes[i];
ReferenceBinding permittedType = findPermittedtype(permittedTypeRef);
if (permittedType == null) { // detected cycle
if (permittedType == null) {
continue nextPermittedType;
}
if (!isPermittedTypeInAllowedFormat(sourceType, permittedTypeRef, permittedType))
continue nextPermittedType;

// check for simple interface collisions
// Check for a duplicate interface once the name is resolved, otherwise we may be confused (i.e. a.b.I and c.d.I)
for (int j = 0; j < i; j++) {
if (TypeBinding.equalsEquals(permittedTypeBindings[j], permittedType)) {
problemReporter().sealedDuplicateTypeInPermits(sourceType, permittedTypeRef, permittedType);
problemReporter().duplicatePermittedType(sourceType, permittedTypeRef, permittedType);
continue nextPermittedType;
}
}
// only want to reach here when no errors are reported
permittedTypeBindings[count++] = permittedType;
}
// hold onto all correctly resolved superinterfaces
if (count > 0) {
if (count != length)
System.arraycopy(permittedTypeBindings, 0, permittedTypeBindings = new ReferenceBinding[count], 0, count);
sourceType.setPermittedTypes(permittedTypeBindings);
} else {
sourceType.setPermittedTypes(Binding.NO_PERMITTEDTYPES);
sourceType.setPermittedTypes(Binding.NO_PERMITTED_TYPES);
}
} finally {
sourceType.tagBits &= ~TagBits.SealingTypeHierarchy;
Expand All @@ -1359,29 +1348,6 @@ void connectPermittedTypes() {
}
}

private boolean isPermittedTypeInAllowedFormat(SourceTypeBinding sourceType, TypeReference permittedTypeRef,
ReferenceBinding permittedType) {
if (!(permittedType.isMemberType() && permittedTypeRef instanceof SingleTypeReference))
return true;
ReferenceBinding enclosingType = permittedType.enclosingType();
while (enclosingType != null) {
if (TypeBinding.equalsEquals(sourceType, enclosingType)) {
CompilationUnitScope cu = this.compilationUnitScope();
if (cu.imports != null || cu.imports.length > 0) {
for (ImportBinding ib : cu.imports) {
Binding resolvedImport = cu.resolveSingleImport(ib, Binding.TYPE);
if (resolvedImport instanceof TypeBinding &&
TypeBinding.equalsEquals(permittedType, (TypeBinding) resolvedImport))
return true;
}
}
return false;
}
enclosingType = enclosingType.enclosingType();
}
return true;
}

private boolean connectRecordSuperclass() {
SourceTypeBinding sourceType = this.referenceContext.binding;
ReferenceBinding rootRecordType = getJavaLangRecord();
Expand Down Expand Up @@ -1675,7 +1641,7 @@ private ReferenceBinding findSupertype(TypeReference typeReference) {
} catch (AbortCompilation e) {
SourceTypeBinding sourceType = this.referenceContext.binding;
if (sourceType.superInterfaces == null) sourceType.setSuperInterfaces(Binding.NO_SUPERINTERFACES); // be more resilient for hierarchies (144976)
if (sourceType.permittedTypes == null) sourceType.setPermittedTypes(Binding.NO_PERMITTEDTYPES);
if (sourceType.permittedTypes == null) sourceType.setPermittedTypes(Binding.NO_PERMITTED_TYPES);
e.updateContext(typeReference, referenceCompilationUnit().compilationResult);
throw e;
} finally {
Expand Down Expand Up @@ -1703,7 +1669,7 @@ private ReferenceBinding findPermittedtype(TypeReference typeReference) {
return permittedType != null ? permittedType.actualType() : permittedType; // while permitted classes/interfaces cannot be parameterized with type arguments, they are not raw either
} catch (AbortCompilation e) {
SourceTypeBinding sourceType = this.referenceContext.binding;
if (sourceType.permittedTypes == null) sourceType.setPermittedTypes(Binding.NO_PERMITTEDTYPES);
if (sourceType.permittedTypes == null) sourceType.setPermittedTypes(Binding.NO_PERMITTED_TYPES);
e.updateContext(typeReference, referenceCompilationUnit().compilationResult);
throw e;
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public MissingTypeBinding(PackageBinding packageBinding, char[][] compoundName,
this.modifiers = ClassFileConstants.AccPublic;
this.superclass = null; // will be fixed up using #setMissingSuperclass(...)
this.superInterfaces = Binding.NO_SUPERINTERFACES;
this.permittedTypes = Binding.NO_PERMITTEDTYPES;
this.permittedTypes = Binding.NO_PERMITTED_TYPES;
this.typeVariables = Binding.NO_TYPE_VARIABLES;
this.memberTypes = Binding.NO_MEMBER_TYPES;
this.fields = Binding.NO_FIELDS;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3240,7 +3240,7 @@ public RecordComponentBinding[] setComponents(RecordComponentBinding[] comps) {
return this.methods = methods;
}

//Propagate writes to all annotated variants so the clones evolve along.
// Propagate writes to all annotated variants so the clones evolve along.
public ReferenceBinding [] setPermittedTypes(ReferenceBinding [] permittedTypes) {

if (!isPrototype())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1759,7 +1759,7 @@ public ReferenceBinding superclass() {
}

public ReferenceBinding[] permittedTypes() {
return Binding.NO_PERMITTEDTYPES;
return Binding.NO_PERMITTED_TYPES;
}

public ReferenceBinding[] superInterfaces() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12336,7 +12336,7 @@ public void sealedMissingSealedModifier(SourceTypeBinding type, ASTNode node) {
node.sourceEnd);
}

public void sealedDuplicateTypeInPermits(SourceTypeBinding type, TypeReference reference, ReferenceBinding superType) {
public void duplicatePermittedType(SourceTypeBinding type, TypeReference reference, ReferenceBinding superType) {
this.handle(
IProblem.SealedDuplicateTypeInPermits,
new String[] {
Expand Down

0 comments on commit 09f7d68

Please sign in to comment.