8303820: Simplify type metadata

Reviewed-by: vromero
This commit is contained in:
Maurizio Cimadamore 2023-03-10 13:12:50 +00:00
parent 75d630621c
commit b9951dd639
8 changed files with 143 additions and 319 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -30,12 +30,14 @@ import java.util.ArrayDeque;
import java.util.Collections; import java.util.Collections;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate; import java.util.function.Predicate;
import javax.lang.model.type.*; import javax.lang.model.type.*;
import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.TypeMetadata.Entry; import com.sun.tools.javac.code.TypeMetadata.Annotations;
import com.sun.tools.javac.code.TypeMetadata.ConstantValue;
import com.sun.tools.javac.code.Types.TypeMapping; import com.sun.tools.javac.code.Types.TypeMapping;
import com.sun.tools.javac.code.Types.UniqueType; import com.sun.tools.javac.code.Types.UniqueType;
import com.sun.tools.javac.comp.Infer.IncorporationAction; import com.sun.tools.javac.comp.Infer.IncorporationAction;
@ -86,15 +88,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
* class, a given {@code Type} may have at most one metadata array * class, a given {@code Type} may have at most one metadata array
* entry of that class. * entry of that class.
*/ */
protected final TypeMetadata metadata; protected final List<TypeMetadata> metadata;
public TypeMetadata getMetadata() {
return metadata;
}
public Entry getMetadataOfKind(final Entry.Kind kind) {
return metadata != null ? metadata.get(kind) : null;
}
/** Constant type: no type at all. */ /** Constant type: no type at all. */
public static final JCNoType noType = new JCNoType() { public static final JCNoType noType = new JCNoType() {
@ -188,7 +182,8 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
* @return the constant value attribute of this type * @return the constant value attribute of this type
*/ */
public Object constValue() { public Object constValue() {
return null; return getMetadata(TypeMetadata.ConstantValue.class)
.map(ConstantValue::value).orElse(null);
} }
/** Is this a constant type whose value is false? /** Is this a constant type whose value is false?
@ -230,7 +225,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
/** Define a type given its tag, type symbol, and type annotations /** Define a type given its tag, type symbol, and type annotations
*/ */
public Type(TypeSymbol tsym, TypeMetadata metadata) { public Type(TypeSymbol tsym, List<TypeMetadata> metadata) {
Assert.checkNonNull(metadata); Assert.checkNonNull(metadata);
this.tsym = tsym; this.tsym = tsym;
this.metadata = metadata; this.metadata = metadata;
@ -345,13 +340,53 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
* it should not be used outside this class. * it should not be used outside this class.
*/ */
protected Type typeNoMetadata() { protected Type typeNoMetadata() {
return metadata == TypeMetadata.EMPTY ? this : baseType(); return metadata.isEmpty() ? this : baseType();
} }
/** /**
* Create a new copy of this type but with the specified TypeMetadata. * Create a new copy of this type but with the specified TypeMetadata.
* Only to be used internally!
*/ */
public abstract Type cloneWithMetadata(TypeMetadata metadata); protected Type cloneWithMetadata(List<TypeMetadata> metadata) {
throw new AssertionError("Cannot add metadata to this type: " + getTag());
}
/**
* Get all the type metadata associated with this type.
*/
public List<TypeMetadata> getMetadata() {
return metadata;
}
/**
* Get the type metadata of the given kind associated with this type (if any).
*/
public <M extends TypeMetadata> Optional<M> getMetadata(Class<M> metadataClass) {
return metadata.stream()
.filter(m -> metadataClass.isAssignableFrom(m.getClass()))
.map(metadataClass::cast)
.findFirst();
}
/**
* Create a new copy of this type but with the specified type metadata.
* If this type is already associated with a type metadata of the same class,
* an exception is thrown.
*/
public Type addMetadata(TypeMetadata md) {
Assert.check(getMetadata(md.getClass()).isEmpty());
return cloneWithMetadata(metadata.append(md));
}
/**
* Create a new copy of this type but without the specified type metadata.
*/
public Type dropMetadata(Class<? extends TypeMetadata> metadataClass) {
List<TypeMetadata> newMetadata = metadata.stream()
.filter(m -> !metadataClass.isAssignableFrom(m.getClass()))
.collect(List.collector());
return cloneWithMetadata(newMetadata);
}
/** /**
* Does this type require annotation stripping for API clients? * Does this type require annotation stripping for API clients?
@ -398,24 +433,22 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
} }
}; };
public Type preannotatedType() {
return addMetadata(new Annotations());
}
public Type annotatedType(final List<Attribute.TypeCompound> annos) { public Type annotatedType(final List<Attribute.TypeCompound> annos) {
final Entry annoMetadata = new TypeMetadata.Annotations(annos); return addMetadata(new Annotations(annos));
return cloneWithMetadata(metadata.combine(annoMetadata));
} }
public boolean isAnnotated() { public boolean isAnnotated() {
final TypeMetadata.Annotations metadata = return getMetadata(TypeMetadata.Annotations.class).isPresent();
(TypeMetadata.Annotations)getMetadataOfKind(Entry.Kind.ANNOTATIONS);
return null != metadata && !metadata.getAnnotations().isEmpty();
} }
@Override @DefinedBy(Api.LANGUAGE_MODEL) @Override @DefinedBy(Api.LANGUAGE_MODEL)
public List<Attribute.TypeCompound> getAnnotationMirrors() { public List<Attribute.TypeCompound> getAnnotationMirrors() {
final TypeMetadata.Annotations metadata = return getMetadata(TypeMetadata.Annotations.class)
(TypeMetadata.Annotations)getMetadataOfKind(Entry.Kind.ANNOTATIONS); .map(Annotations::annotations).orElse(List.nil());
return metadata == null ? List.nil() : metadata.getAnnotations();
} }
@ -688,17 +721,17 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
TypeTag tag; TypeTag tag;
public JCPrimitiveType(TypeTag tag, TypeSymbol tsym) { public JCPrimitiveType(TypeTag tag, TypeSymbol tsym) {
this(tag, tsym, TypeMetadata.EMPTY); this(tag, tsym, List.nil());
} }
private JCPrimitiveType(TypeTag tag, TypeSymbol tsym, TypeMetadata metadata) { private JCPrimitiveType(TypeTag tag, TypeSymbol tsym, List<TypeMetadata> metadata) {
super(tsym, metadata); super(tsym, metadata);
this.tag = tag; this.tag = tag;
Assert.check(tag.isPrimitive); Assert.check(tag.isPrimitive);
} }
@Override @Override
public JCPrimitiveType cloneWithMetadata(TypeMetadata md) { protected JCPrimitiveType cloneWithMetadata(List<TypeMetadata> md) {
return new JCPrimitiveType(tag, tsym, md) { return new JCPrimitiveType(tag, tsym, md) {
@Override @Override
public Type baseType() { return JCPrimitiveType.this.baseType(); } public Type baseType() { return JCPrimitiveType.this.baseType(); }
@ -744,17 +777,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
*/ */
@Override @Override
public Type constType(Object constValue) { public Type constType(Object constValue) {
final Object value = constValue; return addMetadata(new ConstantValue(constValue));
return new JCPrimitiveType(tag, tsym, metadata) {
@Override
public Object constValue() {
return value;
}
@Override
public Type baseType() {
return tsym.type;
}
};
} }
/** /**
@ -829,21 +852,21 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
} }
public WildcardType(Type type, BoundKind kind, TypeSymbol tsym) { public WildcardType(Type type, BoundKind kind, TypeSymbol tsym) {
this(type, kind, tsym, null, TypeMetadata.EMPTY); this(type, kind, tsym, null, List.nil());
} }
public WildcardType(Type type, BoundKind kind, TypeSymbol tsym, public WildcardType(Type type, BoundKind kind, TypeSymbol tsym,
TypeMetadata metadata) { List<TypeMetadata> metadata) {
this(type, kind, tsym, null, metadata); this(type, kind, tsym, null, metadata);
} }
public WildcardType(Type type, BoundKind kind, TypeSymbol tsym, public WildcardType(Type type, BoundKind kind, TypeSymbol tsym,
TypeVar bound) { TypeVar bound) {
this(type, kind, tsym, bound, TypeMetadata.EMPTY); this(type, kind, tsym, bound, List.nil());
} }
public WildcardType(Type type, BoundKind kind, TypeSymbol tsym, public WildcardType(Type type, BoundKind kind, TypeSymbol tsym,
TypeVar bound, TypeMetadata metadata) { TypeVar bound, List<TypeMetadata> metadata) {
super(tsym, metadata); super(tsym, metadata);
this.type = Assert.checkNonNull(type); this.type = Assert.checkNonNull(type);
this.kind = kind; this.kind = kind;
@ -851,7 +874,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
} }
@Override @Override
public WildcardType cloneWithMetadata(TypeMetadata md) { protected WildcardType cloneWithMetadata(List<TypeMetadata> md) {
return new WildcardType(type, kind, tsym, bound, md) { return new WildcardType(type, kind, tsym, bound, md) {
@Override @Override
public Type baseType() { return WildcardType.this.baseType(); } public Type baseType() { return WildcardType.this.baseType(); }
@ -978,11 +1001,11 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
public List<Type> all_interfaces_field; public List<Type> all_interfaces_field;
public ClassType(Type outer, List<Type> typarams, TypeSymbol tsym) { public ClassType(Type outer, List<Type> typarams, TypeSymbol tsym) {
this(outer, typarams, tsym, TypeMetadata.EMPTY); this(outer, typarams, tsym, List.nil());
} }
public ClassType(Type outer, List<Type> typarams, TypeSymbol tsym, public ClassType(Type outer, List<Type> typarams, TypeSymbol tsym,
TypeMetadata metadata) { List<TypeMetadata> metadata) {
super(tsym, metadata); super(tsym, metadata);
this.outer_field = outer; this.outer_field = outer;
this.typarams_field = typarams; this.typarams_field = typarams;
@ -996,7 +1019,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
} }
@Override @Override
public ClassType cloneWithMetadata(TypeMetadata md) { protected ClassType cloneWithMetadata(List<TypeMetadata> md) {
return new ClassType(outer_field, typarams_field, tsym, md) { return new ClassType(outer_field, typarams_field, tsym, md) {
@Override @Override
public Type baseType() { return ClassType.this.baseType(); } public Type baseType() { return ClassType.this.baseType(); }
@ -1014,17 +1037,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
} }
public Type constType(Object constValue) { public Type constType(Object constValue) {
final Object value = constValue; return addMetadata(new ConstantValue(constValue));
return new ClassType(getEnclosingType(), typarams_field, tsym, metadata) {
@Override
public Object constValue() {
return value;
}
@Override
public Type baseType() {
return tsym.type;
}
};
} }
/** The Java source which this type represents. /** The Java source which this type represents.
@ -1190,7 +1203,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
public static class ErasedClassType extends ClassType { public static class ErasedClassType extends ClassType {
public ErasedClassType(Type outer, TypeSymbol tsym, public ErasedClassType(Type outer, TypeSymbol tsym,
TypeMetadata metadata) { List<TypeMetadata> metadata) {
super(outer, List.nil(), tsym, metadata); super(outer, List.nil(), tsym, metadata);
} }
@ -1215,11 +1228,6 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
alternatives_field = alternatives; alternatives_field = alternatives;
} }
@Override
public UnionClassType cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to a union type");
}
public Type getLub() { public Type getLub() {
return tsym.type; return tsym.type;
} }
@ -1271,11 +1279,6 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
!supertype_field.isInterface(), supertype_field); !supertype_field.isInterface(), supertype_field);
} }
@Override
public IntersectionClassType cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to an intersection type");
}
@DefinedBy(Api.LANGUAGE_MODEL) @DefinedBy(Api.LANGUAGE_MODEL)
public java.util.List<? extends TypeMirror> getBounds() { public java.util.List<? extends TypeMirror> getBounds() {
return Collections.unmodifiableList(getExplicitComponents()); return Collections.unmodifiableList(getExplicitComponents());
@ -1318,11 +1321,11 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
public Type elemtype; public Type elemtype;
public ArrayType(Type elemtype, TypeSymbol arrayClass) { public ArrayType(Type elemtype, TypeSymbol arrayClass) {
this(elemtype, arrayClass, TypeMetadata.EMPTY); this(elemtype, arrayClass, List.nil());
} }
public ArrayType(Type elemtype, TypeSymbol arrayClass, public ArrayType(Type elemtype, TypeSymbol arrayClass,
TypeMetadata metadata) { List<TypeMetadata> metadata) {
super(arrayClass, metadata); super(arrayClass, metadata);
this.elemtype = elemtype; this.elemtype = elemtype;
} }
@ -1338,7 +1341,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
} }
@Override @Override
public ArrayType cloneWithMetadata(TypeMetadata md) { protected ArrayType cloneWithMetadata(List<TypeMetadata> md) {
return new ArrayType(elemtype, tsym, md) { return new ArrayType(elemtype, tsym, md) {
@Override @Override
public Type baseType() { return ArrayType.this.baseType(); } public Type baseType() { return ArrayType.this.baseType(); }
@ -1463,17 +1466,12 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
TypeSymbol methodClass) { TypeSymbol methodClass) {
// Presently no way to refer to a method type directly, so // Presently no way to refer to a method type directly, so
// we cannot put type annotations on it. // we cannot put type annotations on it.
super(methodClass, TypeMetadata.EMPTY); super(methodClass, List.nil());
this.argtypes = argtypes; this.argtypes = argtypes;
this.restype = restype; this.restype = restype;
this.thrown = thrown; this.thrown = thrown;
} }
@Override
public MethodType cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to a method type");
}
@Override @Override
public TypeTag getTag() { public TypeTag getTag() {
return METHOD; return METHOD;
@ -1560,12 +1558,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
PackageType(PackageSymbol tsym) { PackageType(PackageSymbol tsym) {
// Package types cannot be annotated // Package types cannot be annotated
super(tsym, TypeMetadata.EMPTY); super(tsym, List.nil());
}
@Override
public PackageType cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to a package type");
} }
@Override @Override
@ -1598,12 +1591,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
ModuleType(ModuleSymbol tsym) { ModuleType(ModuleSymbol tsym) {
// Module types cannot be annotated // Module types cannot be annotated
super(tsym, TypeMetadata.EMPTY); super(tsym, List.nil());
}
@Override
public ModuleType cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to a module type");
} }
@Override @Override
@ -1659,7 +1647,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
public Type lower; public Type lower;
public TypeVar(Name name, Symbol owner, Type lower) { public TypeVar(Name name, Symbol owner, Type lower) {
super(null, TypeMetadata.EMPTY); super(null, List.nil());
Assert.checkNonNull(lower); Assert.checkNonNull(lower);
tsym = new TypeVariableSymbol(0, name, this, owner); tsym = new TypeVariableSymbol(0, name, this, owner);
this.setUpperBound(null); this.setUpperBound(null);
@ -1667,11 +1655,11 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
} }
public TypeVar(TypeSymbol tsym, Type bound, Type lower) { public TypeVar(TypeSymbol tsym, Type bound, Type lower) {
this(tsym, bound, lower, TypeMetadata.EMPTY); this(tsym, bound, lower, List.nil());
} }
public TypeVar(TypeSymbol tsym, Type bound, Type lower, public TypeVar(TypeSymbol tsym, Type bound, Type lower,
TypeMetadata metadata) { List<TypeMetadata> metadata) {
super(tsym, metadata); super(tsym, metadata);
Assert.checkNonNull(lower); Assert.checkNonNull(lower);
this.setUpperBound(bound); this.setUpperBound(bound);
@ -1679,7 +1667,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
} }
@Override @Override
public TypeVar cloneWithMetadata(TypeMetadata md) { protected TypeVar cloneWithMetadata(List<TypeMetadata> md) {
return new TypeVar(tsym, getUpperBound(), lower, md) { return new TypeVar(tsym, getUpperBound(), lower, md) {
@Override @Override
public Type baseType() { return TypeVar.this.baseType(); } public Type baseType() { return TypeVar.this.baseType(); }
@ -1762,13 +1750,13 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
Type upper, Type upper,
Type lower, Type lower,
WildcardType wildcard, WildcardType wildcard,
TypeMetadata metadata) { List<TypeMetadata> metadata) {
super(tsym, bound, lower, metadata); super(tsym, bound, lower, metadata);
this.wildcard = wildcard; this.wildcard = wildcard;
} }
@Override @Override
public CapturedType cloneWithMetadata(TypeMetadata md) { protected CapturedType cloneWithMetadata(List<TypeMetadata> md) {
return new CapturedType(tsym, getUpperBound(), getUpperBound(), lower, wildcard, md) { return new CapturedType(tsym, getUpperBound(), getUpperBound(), lower, wildcard, md) {
@Override @Override
public Type baseType() { return CapturedType.this.baseType(); } public Type baseType() { return CapturedType.this.baseType(); }
@ -1807,11 +1795,11 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
public TypeTag tag; public TypeTag tag;
public DelegatedType(TypeTag tag, Type qtype) { public DelegatedType(TypeTag tag, Type qtype) {
this(tag, qtype, TypeMetadata.EMPTY); this(tag, qtype, List.nil());
} }
public DelegatedType(TypeTag tag, Type qtype, public DelegatedType(TypeTag tag, Type qtype,
TypeMetadata metadata) { List<TypeMetadata> metadata) {
super(qtype.tsym, metadata); super(qtype.tsym, metadata);
this.tag = tag; this.tag = tag;
this.qtype = qtype; this.qtype = qtype;
@ -1844,11 +1832,6 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
this.tvars = tvars; this.tvars = tvars;
} }
@Override
public ForAll cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to a forall type");
}
@Override @Override
public <R,S> R accept(Type.Visitor<R,S> v, S s) { public <R,S> R accept(Type.Visitor<R,S> v, S s) {
return v.visitForAll(this, s); return v.visitForAll(this, s);
@ -2077,11 +2060,6 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
uv2.kind = kind; uv2.kind = kind;
} }
@Override
public UndetVar cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to an UndetVar type");
}
@Override @Override
public boolean isPartial() { public boolean isPartial() {
return true; return true;
@ -2224,12 +2202,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
// Need to use List.nil(), because JCNoType constructor // Need to use List.nil(), because JCNoType constructor
// gets called in static initializers in Type, where // gets called in static initializers in Type, where
// noAnnotations is also defined. // noAnnotations is also defined.
super(null, TypeMetadata.EMPTY); super(null, List.nil());
}
@Override
public JCNoType cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to a JCNoType");
} }
@Override @Override
@ -2257,12 +2230,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
public JCVoidType() { public JCVoidType() {
// Void cannot be annotated // Void cannot be annotated
super(null, TypeMetadata.EMPTY); super(null, List.nil());
}
@Override
public JCVoidType cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to a void type");
} }
@Override @Override
@ -2292,12 +2260,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
static class BottomType extends Type implements NullType { static class BottomType extends Type implements NullType {
public BottomType() { public BottomType() {
// Bottom is a synthesized internal type, so it cannot be annotated // Bottom is a synthesized internal type, so it cannot be annotated
super(null, TypeMetadata.EMPTY); super(null, List.nil());
}
@Override
public BottomType cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to a bottom type");
} }
@Override @Override
@ -2354,14 +2317,14 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
} }
private ErrorType(Type originalType, TypeSymbol tsym, private ErrorType(Type originalType, TypeSymbol tsym,
TypeMetadata metadata) { List<TypeMetadata> metadata) {
super(noType, List.nil(), null, metadata); super(noType, List.nil(), null, metadata);
this.tsym = tsym; this.tsym = tsym;
this.originalType = (originalType == null ? noType : originalType); this.originalType = (originalType == null ? noType : originalType);
} }
@Override @Override
public ErrorType cloneWithMetadata(TypeMetadata md) { protected ErrorType cloneWithMetadata(List<TypeMetadata> md) {
return new ErrorType(originalType, tsym, md) { return new ErrorType(originalType, tsym, md) {
@Override @Override
public Type baseType() { return ErrorType.this.baseType(); } public Type baseType() { return ErrorType.this.baseType(); }
@ -2432,12 +2395,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
public UnknownType() { public UnknownType() {
// Unknown is a synthesized internal type, so it cannot be // Unknown is a synthesized internal type, so it cannot be
// annotated. // annotated.
super(null, TypeMetadata.EMPTY); super(null, List.nil());
}
@Override
public UnknownType cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to an unknown type");
} }
@Override @Override

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,181 +25,55 @@
package com.sun.tools.javac.code; package com.sun.tools.javac.code;
import com.sun.tools.javac.util.Assert;
import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.List;
import java.util.EnumMap; import com.sun.tools.javac.util.ListBuffer;
import java.util.HashSet;
import java.util.Set;
/** /**
* TypeMetadata is essentially an immutable {@code EnumMap<Entry.Kind, <? extends Entry>>} * A type metadata is an object that can be stapled on a type. This is typically done using
* * {@link Type#addMetadata(TypeMetadata)}. Metadata associated to a type can also be removed,
* A metadata class represented by a subtype of Entry can express a property on a Type instance. * typically using {@link Type#dropMetadata(Class)}. To drop <em>all</em> metadata from a given type,
* There should be at most one instance of an Entry per Entry.Kind on any given Type instance. * the {@link Type#baseType()} method can also be used. This can be useful when comparing two
* * using reference equality (see also {@link Type#equalsIgnoreMetadata(Type)}).
* Metadata classes of a specific kind are responsible for how they combine themselves. * <p>
* * There are no constraints on how a type metadata should be defined. Typically, a type
* @implNote {@code Entry:combine} need not be commutative. * metadata will be defined as a small record, storing additional information (see {@link ConstantValue}).
* In other cases, type metadata can be mutable and support complex state transitions
* (see {@link Annotations}).
* <p>
* The only invariant the implementation requires is that there must be <em>one</em> metadata
* of a given kind attached to a type, as this makes accessing and dropping metadata simpler.
* If clients wish to store multiple metadata values that are logically related, they should
* define a metadata type that collects such values in e.g. a list.
*/ */
public class TypeMetadata { public sealed interface TypeMetadata {
public static final TypeMetadata EMPTY = new TypeMetadata();
private final EnumMap<Entry.Kind, Entry> contents;
/** /**
* Create a new empty TypeMetadata map. * A type metadata object holding type annotations. This metadata needs to be mutable,
* because type annotations are sometimes set in two steps. That is, a type can be created with
* an empty set of annotations (e.g. during member enter). At some point later, the type
* is then updated to contain the correct annotations. At this point we need to augment
* the existing type (rather than creating a new one), as the type might already have been
* saved inside other symbols.
*/ */
private TypeMetadata() { record Annotations(ListBuffer<Attribute.TypeCompound> annotationBuffer) implements TypeMetadata {
contents = new EnumMap<>(Entry.Kind.class);
}
/** Annotations() {
* Create a new TypeMetadata map containing the Entry {@code elem}. this(new ListBuffer<>());
*
* @param elem the sole contents of this map
*/
public TypeMetadata(Entry elem) {
this();
Assert.checkNonNull(elem);
contents.put(elem.kind(), elem);
}
/**
* Creates a copy of TypeMetadata {@code other} with a shallow copy the other's metadata contents.
*
* @param other the TypeMetadata to copy contents from.
*/
public TypeMetadata(TypeMetadata other) {
Assert.checkNonNull(other);
contents = other.contents.clone();
}
/**
* Return a copy of this TypeMetadata with the metadata entry for {@code elem.kind()} combined
* with {@code elem}.
*
* @param elem the new value
* @return a new TypeMetadata updated with {@code Entry elem}
*/
public TypeMetadata combine(Entry elem) {
Assert.checkNonNull(elem);
TypeMetadata out = new TypeMetadata(this);
Entry.Kind key = elem.kind();
if (contents.containsKey(key)) {
out.add(key, this.contents.get(key).combine(elem));
} else {
out.add(key, elem);
}
return out;
}
/**
* Return a copy of this TypeMetadata with the metadata entry for all kinds from {@code other}
* combined with the same kind from this.
*
* @param other the TypeMetadata to combine with this
* @return a new TypeMetadata updated with all entries from {@code other}
*/
public TypeMetadata combineAll(TypeMetadata other) {
Assert.checkNonNull(other);
TypeMetadata out = new TypeMetadata();
Set<Entry.Kind> keys = new HashSet<>(contents.keySet());
keys.addAll(other.contents.keySet());
for(Entry.Kind key : keys) {
if (contents.containsKey(key)) {
if (other.contents.containsKey(key)) {
out.add(key, contents.get(key).combine(other.contents.get(key)));
} else {
out.add(key, contents.get(key));
}
} else if (other.contents.containsKey(key)) {
out.add(key, other.contents.get(key));
}
}
return out;
}
/**
* Return a TypeMetadata with the metadata entry for {@code kind} removed.
*
* This may be the same instance or a new TypeMetadata.
*
* @param kind the {@code Kind} to remove metadata for
* @return a new TypeMetadata without {@code Kind kind}
*/
public TypeMetadata without(Entry.Kind kind) {
if (this == EMPTY || contents.get(kind) == null)
return this;
TypeMetadata out = new TypeMetadata(this);
out.contents.remove(kind);
return out.contents.isEmpty() ? EMPTY : out;
}
public Entry get(Entry.Kind kind) {
return contents.get(kind);
}
private void add(Entry.Kind kind, Entry elem) {
contents.put(kind, elem);
}
public interface Entry {
public enum Kind {
ANNOTATIONS
} }
/** Annotations(List<Attribute.TypeCompound> annotations) {
* Get the kind of metadata this object represents this();
*/ annotationBuffer.appendList(annotations);
public Kind kind(); }
/** List<Attribute.TypeCompound> annotations() {
* Combine this type metadata with another metadata of the return annotationBuffer.toList();
* same kind. }
*
* @param other The metadata with which to combine this one.
* @return The combined metadata.
*/
public Entry combine(Entry other);
} }
/** /**
* A type metadata object holding type annotations. * A type metadata holding a constant value. This can be used to describe constant types,
* such as the type of a string literal, or that of a numeric constant.
*/ */
public static class Annotations implements Entry { record ConstantValue(Object value) implements TypeMetadata { }
private List<Attribute.TypeCompound> annos;
public static final List<Attribute.TypeCompound> TO_BE_SET = List.nil();
public Annotations(List<Attribute.TypeCompound> annos) {
this.annos = annos;
}
/**
* Get the type annotations contained in this metadata.
*
* @return The annotations.
*/
public List<Attribute.TypeCompound> getAnnotations() {
return annos;
}
@Override
public Annotations combine(Entry other) {
Assert.check(annos == TO_BE_SET);
annos = ((Annotations)other).annos;
return this;
}
@Override
public Kind kind() { return Kind.ANNOTATIONS; }
@Override
public String toString() { return "ANNOTATIONS [ " + annos + " ]"; }
}
} }

View File

@ -44,7 +44,7 @@ import com.sun.tools.javac.code.Attribute.RetentionPolicy;
import com.sun.tools.javac.code.Lint.LintCategory; import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Source.Feature; import com.sun.tools.javac.code.Source.Feature;
import com.sun.tools.javac.code.Type.UndetVar.InferenceBound; import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
import com.sun.tools.javac.code.TypeMetadata.Entry.Kind; import com.sun.tools.javac.code.TypeMetadata.Annotations;
import com.sun.tools.javac.comp.AttrContext; import com.sun.tools.javac.comp.AttrContext;
import com.sun.tools.javac.comp.Check; import com.sun.tools.javac.comp.Check;
import com.sun.tools.javac.comp.Enter; import com.sun.tools.javac.comp.Enter;
@ -2399,7 +2399,7 @@ public class Types {
private TypeMapping<Boolean> erasure = new StructuralTypeMapping<Boolean>() { private TypeMapping<Boolean> erasure = new StructuralTypeMapping<Boolean>() {
private Type combineMetadata(final Type s, private Type combineMetadata(final Type s,
final Type t) { final Type t) {
if (t.getMetadata() != TypeMetadata.EMPTY) { if (t.getMetadata().nonEmpty()) {
switch (s.getKind()) { switch (s.getKind()) {
case OTHER: case OTHER:
case UNION: case UNION:
@ -2410,7 +2410,7 @@ public class Types {
case VOID: case VOID:
case ERROR: case ERROR:
return s; return s;
default: return s.cloneWithMetadata(s.getMetadata().without(Kind.ANNOTATIONS)); default: return s.dropMetadata(Annotations.class);
} }
} else { } else {
return s; return s;
@ -2437,7 +2437,7 @@ public class Types {
Type erased = t.tsym.erasure(Types.this); Type erased = t.tsym.erasure(Types.this);
if (recurse) { if (recurse) {
erased = new ErasedClassType(erased.getEnclosingType(),erased.tsym, erased = new ErasedClassType(erased.getEnclosingType(),erased.tsym,
t.getMetadata().without(Kind.ANNOTATIONS)); t.dropMetadata(Annotations.class).getMetadata());
return erased; return erased;
} else { } else {
return combineMetadata(erased, t); return combineMetadata(erased, t);

View File

@ -32,7 +32,7 @@ import com.sun.tools.javac.code.Kinds.KindSelector;
import com.sun.tools.javac.code.Scope.WriteableScope; import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.code.Source.Feature; import com.sun.tools.javac.code.Source.Feature;
import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.TypeMetadata.Entry.Kind; import com.sun.tools.javac.code.TypeMetadata.Annotations;
import com.sun.tools.javac.comp.Check.CheckContext; import com.sun.tools.javac.comp.Check.CheckContext;
import com.sun.tools.javac.resources.CompilerProperties.Errors; import com.sun.tools.javac.resources.CompilerProperties.Errors;
import com.sun.tools.javac.resources.CompilerProperties.Fragments; import com.sun.tools.javac.resources.CompilerProperties.Fragments;
@ -1049,7 +1049,10 @@ public class Annotate {
typeAnnotation(() -> { typeAnnotation(() -> {
List<Attribute.TypeCompound> compounds = fromAnnotations(annotations); List<Attribute.TypeCompound> compounds = fromAnnotations(annotations);
Assert.check(annotations.size() == compounds.size()); Assert.check(annotations.size() == compounds.size());
storeAt.getMetadataOfKind(Kind.ANNOTATIONS).combine(new TypeMetadata.Annotations(compounds)); // the type already has annotation metadata, but it's empty
Annotations metadata = storeAt.getMetadata(Annotations.class).orElseThrow(AssertionError::new);
Assert.check(metadata.annotationBuffer().isEmpty());
metadata.annotationBuffer().appendList(compounds);
}); });
} }

View File

@ -46,7 +46,6 @@ import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.code.Source.Feature; import com.sun.tools.javac.code.Source.Feature;
import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.code.TypeMetadata.Annotations;
import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError; import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext; import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
import com.sun.tools.javac.comp.Check.CheckContext; import com.sun.tools.javac.comp.Check.CheckContext;
@ -5210,7 +5209,7 @@ public class Attr extends JCTree.Visitor {
public void visitAnnotatedType(JCAnnotatedType tree) { public void visitAnnotatedType(JCAnnotatedType tree) {
attribAnnotationTypes(tree.annotations, env); attribAnnotationTypes(tree.annotations, env);
Type underlyingType = attribType(tree.underlyingType, env); Type underlyingType = attribType(tree.underlyingType, env);
Type annotatedType = underlyingType.annotatedType(Annotations.TO_BE_SET); Type annotatedType = underlyingType.preannotatedType();
if (!env.info.isNewClass) if (!env.info.isNewClass)
annotate.annotateTypeSecondStage(tree, tree.annotations, annotatedType); annotate.annotateTypeSecondStage(tree, tree.annotations, annotatedType);

View File

@ -221,17 +221,12 @@ public class DeferredAttr extends JCTree.Visitor {
SpeculativeCache speculativeCache; SpeculativeCache speculativeCache;
DeferredType(JCExpression tree, Env<AttrContext> env) { DeferredType(JCExpression tree, Env<AttrContext> env) {
super(null, TypeMetadata.EMPTY); super(null, List.nil());
this.tree = tree; this.tree = tree;
this.env = attr.copyEnv(env); this.env = attr.copyEnv(env);
this.speculativeCache = new SpeculativeCache(); this.speculativeCache = new SpeculativeCache();
} }
@Override
public DeferredType cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to a deferred type");
}
@Override @Override
public TypeTag getTag() { public TypeTag getTag() {
return DEFERRED; return DEFERRED;

View File

@ -2925,7 +2925,7 @@ public class ClassReader {
private final Name name; private final Name name;
public ProxyType(int index) { public ProxyType(int index) {
super(syms.noSymbol, TypeMetadata.EMPTY); super(syms.noSymbol, List.nil());
this.name = poolReader.getName(index); this.name = poolReader.getName(index);
} }
@ -2934,11 +2934,6 @@ public class ClassReader {
return TypeTag.NONE; return TypeTag.NONE;
} }
@Override
public Type cloneWithMetadata(TypeMetadata metadata) {
throw new UnsupportedOperationException();
}
public Type resolve() { public Type resolve() {
return name.map(ClassReader.this::sigToType); return name.map(ClassReader.this::sigToType);
} }

View File

@ -53,13 +53,13 @@ class UninitializedType extends Type.DelegatedType {
public final int offset; // PC where allocation took place public final int offset; // PC where allocation took place
private UninitializedType(TypeTag tag, Type qtype, int offset, private UninitializedType(TypeTag tag, Type qtype, int offset,
TypeMetadata metadata) { List<TypeMetadata> metadata) {
super(tag, qtype, metadata); super(tag, qtype, metadata);
this.offset = offset; this.offset = offset;
} }
@Override @Override
public UninitializedType cloneWithMetadata(final TypeMetadata md) { protected UninitializedType cloneWithMetadata(final List<TypeMetadata> md) {
return new UninitializedType(tag, qtype, offset, md); return new UninitializedType(tag, qtype, offset, md);
} }