< prev index next > src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
Print this page
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.code.Source.Feature;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Type.*;
+ import com.sun.tools.javac.code.Type.ClassType.Flavor;
import com.sun.tools.javac.code.TypeMetadata.Annotations;
import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
import com.sun.tools.javac.comp.Check.CheckContext;
import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
allowPoly = Feature.POLY.allowedInSource(source);
allowTypeAnnos = Feature.TYPE_ANNOTATIONS.allowedInSource(source);
allowLambda = Feature.LAMBDA.allowedInSource(source);
allowDefaultMethods = Feature.DEFAULT_METHODS.allowedInSource(source);
allowStaticInterfaceMethods = Feature.STATIC_INTERFACE_METHODS.allowedInSource(source);
+ allowPrimitiveClasses = Feature.PRIMITIVE_CLASSES.allowedInSource(source);
allowReifiableTypesInInstanceof = Feature.REIFIABLE_TYPES_INSTANCEOF.allowedInSource(source);
allowRecords = Feature.RECORDS.allowedInSource(source);
allowPatternSwitch = (preview.isEnabled() || !preview.isPreview(Feature.PATTERN_SWITCH)) &&
Feature.PATTERN_SWITCH.allowedInSource(source);
sourceName = source.name;
/** Switch: support default methods ?
*/
boolean allowDefaultMethods;
+ /** Switch: allow primitive classes ?
+ */
+ boolean allowPrimitiveClasses;
+
/** Switch: static interface methods enabled?
*/
boolean allowStaticInterfaceMethods;
/** Switch: reifiable types in instanceof enabled?
for (JCTypeParameter tvar : typarams) {
TypeVar a = (TypeVar)tvar.type;
a.tsym.flags_field |= UNATTRIBUTED;
a.setUpperBound(Type.noType);
if (!tvar.bounds.isEmpty()) {
! List<Type> bounds = List.of(attribType(tvar.bounds.head, env));
for (JCExpression bound : tvar.bounds.tail)
! bounds = bounds.prepend(attribType(bound, env));
types.setBounds(a, bounds.reverse());
} else {
// if no bounds are given, assume a single bound of
// java.lang.Object.
types.setBounds(a, List.of(syms.objectType));
for (JCTypeParameter tvar : typarams) {
TypeVar a = (TypeVar)tvar.type;
a.tsym.flags_field |= UNATTRIBUTED;
a.setUpperBound(Type.noType);
if (!tvar.bounds.isEmpty()) {
! List<Type> bounds = List.of(chk.checkRefType(tvar.bounds.head, attribType(tvar.bounds.head, env), false));
for (JCExpression bound : tvar.bounds.tail)
! bounds = bounds.prepend(chk.checkRefType(bound, attribType(bound, env), false));
types.setBounds(a, bounds.reverse());
} else {
// if no bounds are given, assume a single bound of
// java.lang.Object.
types.setBounds(a, List.of(syms.objectType));
// super(...) or this(...) is given
// or we are compiling class java.lang.Object.
if (tree.name == names.init && owner.type != syms.objectType) {
JCBlock body = tree.body;
if (body.stats.isEmpty() ||
! TreeInfo.getConstructorInvocationName(body.stats, names) == names.empty) {
JCStatement supCall = make.at(body.pos).Exec(make.Apply(List.nil(),
make.Ident(names._super), make.Idents(List.nil())));
body.stats = body.stats.prepend(supCall);
} else if ((env.enclClass.sym.flags() & ENUM) != 0 &&
(tree.mods.flags & GENERATEDCONSTR) == 0 &&
// super(...) or this(...) is given
// or we are compiling class java.lang.Object.
if (tree.name == names.init && owner.type != syms.objectType) {
JCBlock body = tree.body;
if (body.stats.isEmpty() ||
! TreeInfo.getConstructorInvocationName(body.stats, names, true) == names.empty) {
JCStatement supCall = make.at(body.pos).Exec(make.Apply(List.nil(),
make.Ident(names._super), make.Idents(List.nil())));
body.stats = body.stats.prepend(supCall);
} else if ((env.enclClass.sym.flags() & ENUM) != 0 &&
(tree.mods.flags & GENERATEDCONSTR) == 0 &&
// directly, so make sure there aren't any super calls
// in enum constructors, except in the compiler
// generated one.
log.error(tree.body.stats.head.pos(),
Errors.CallToSuperNotAllowedInEnumCtor(env.enclClass.sym));
+ } else if ((env.enclClass.sym.flags() & VALUE_CLASS) != 0 &&
+ (tree.mods.flags & GENERATEDCONSTR) == 0 &&
+ TreeInfo.isSuperCall(body.stats.head)) {
+ // value constructors are not allowed to call super directly,
+ // but tolerate compiler generated ones, these are ignored during code generation
+ log.error(tree.body.stats.head.pos(), Errors.CallToSuperNotAllowedInValueCtor);
}
if (env.enclClass.sym.isRecord() && (tree.sym.flags_field & RECORD) != 0) { // we are seeing the canonical constructor
List<Name> recordComponentNames = TreeInfo.recordFields(env.enclClass).map(vd -> vd.sym.name);
List<Name> initParamNames = tree.sym.params.map(p -> p.name);
if (!initParamNames.equals(recordComponentNames)) {
try {
v.getConstValue(); // ensure compile-time constant initializer is evaluated
deferredLintHandler.flush(tree.pos());
chk.checkDeprecatedAnnotation(tree.pos(), v);
if (tree.init != null) {
! if ((v.flags_field & FINAL) == 0 ||
!memberEnter.needsLazyConstValue(tree.init)) {
// Not a compile-time constant
// Attribute initializer in a new environment
// with the declared variable as owner.
// Check that initializer conforms to variable's declared type.
try {
v.getConstValue(); // ensure compile-time constant initializer is evaluated
deferredLintHandler.flush(tree.pos());
chk.checkDeprecatedAnnotation(tree.pos(), v);
+ /* Don't want constant propagation/folding for instance fields of primitive classes,
+ as these can undergo updates via copy on write.
+ */
if (tree.init != null) {
! if ((v.flags_field & FINAL) == 0 || ((v.flags_field & STATIC) == 0 && v.owner.isValueClass()) ||
!memberEnter.needsLazyConstValue(tree.init)) {
// Not a compile-time constant
// Attribute initializer in a new environment
// with the declared variable as owner.
// Check that initializer conforms to variable's declared type.
Type exprType = types.cvarUpperBound(attribExpr(tree.expr, loopEnv));
chk.checkNonVoid(tree.pos(), exprType);
Type elemtype = types.elemtype(exprType); // perhaps expr is an array?
if (elemtype == null) {
// or perhaps expr implements Iterable<T>?
! Type base = types.asSuper(exprType, syms.iterableType.tsym);
if (base == null) {
log.error(tree.expr.pos(),
Errors.ForeachNotApplicableToType(exprType,
Fragments.TypeReqArrayOrIterable));
elemtype = types.createErrorType(exprType);
Type exprType = types.cvarUpperBound(attribExpr(tree.expr, loopEnv));
chk.checkNonVoid(tree.pos(), exprType);
Type elemtype = types.elemtype(exprType); // perhaps expr is an array?
if (elemtype == null) {
// or perhaps expr implements Iterable<T>?
! Type base = types.asSuper(exprType.referenceProjectionOrSelf(), syms.iterableType.tsym);
if (base == null) {
log.error(tree.expr.pos(),
Errors.ForeachNotApplicableToType(exprType,
Fragments.TypeReqArrayOrIterable));
elemtype = types.createErrorType(exprType);
// Check the return type of the method iterator().
// This is the bare minimum we need to verify to make sure code generation doesn't crash.
Symbol iterSymbol = rs.resolveInternalMethod(tree.pos(),
loopEnv, types.skipTypeVars(exprType, false), names.iterator, List.nil(), List.nil());
! if (types.asSuper(iterSymbol.type.getReturnType(), syms.iteratorType.tsym) == null) {
log.error(tree.pos(),
Errors.ForeachNotApplicableToType(exprType, Fragments.TypeReqArrayOrIterable));
}
}
}
// Check the return type of the method iterator().
// This is the bare minimum we need to verify to make sure code generation doesn't crash.
Symbol iterSymbol = rs.resolveInternalMethod(tree.pos(),
loopEnv, types.skipTypeVars(exprType, false), names.iterator, List.nil(), List.nil());
! if (types.asSuper(iterSymbol.type.getReturnType().referenceProjectionOrSelf(), syms.iteratorType.tsym) == null) {
log.error(tree.pos(),
Errors.ForeachNotApplicableToType(exprType, Fragments.TypeReqArrayOrIterable));
}
}
}
}
return null;
}
public void visitSynchronized(JCSynchronized tree) {
! chk.checkRefType(tree.pos(), attribExpr(tree.lock, env));
if (env.info.lint.isEnabled(LintCategory.SYNCHRONIZATION) && isValueBased(tree.lock.type)) {
log.warning(LintCategory.SYNCHRONIZATION, tree.pos(), Warnings.AttemptToSynchronizeOnInstanceOfValueBasedClass);
}
attribStat(tree.body, env);
result = null;
}
return null;
}
public void visitSynchronized(JCSynchronized tree) {
! chk.checkIdentityType(tree.pos(), attribExpr(tree.lock, env));
if (env.info.lint.isEnabled(LintCategory.SYNCHRONIZATION) && isValueBased(tree.lock.type)) {
log.warning(LintCategory.SYNCHRONIZATION, tree.pos(), Warnings.AttemptToSynchronizeOnInstanceOfValueBasedClass);
}
attribStat(tree.body, env);
result = null;
}
}
void checkAutoCloseable(DiagnosticPosition pos, Env<AttrContext> env, Type resource) {
if (!resource.isErroneous() &&
! types.asSuper(resource, syms.autoCloseableType.tsym) != null &&
!types.isSameType(resource, syms.autoCloseableType)) { // Don't emit warning for AutoCloseable itself
Symbol close = syms.noSymbol;
Log.DiagnosticHandler discardHandler = new Log.DiscardDiagnosticHandler(log);
try {
close = rs.resolveQualifiedMethod(pos,
}
}
void checkAutoCloseable(DiagnosticPosition pos, Env<AttrContext> env, Type resource) {
if (!resource.isErroneous() &&
! types.asSuper(resource.referenceProjectionOrSelf(), syms.autoCloseableType.tsym) != null &&
!types.isSameType(resource, syms.autoCloseableType)) { // Don't emit warning for AutoCloseable itself
Symbol close = syms.noSymbol;
Log.DiagnosticHandler discardHandler = new Log.DiscardDiagnosticHandler(log);
try {
close = rs.resolveQualifiedMethod(pos,
return candidate;
}
}
}
! // Those were all the cases that could result in a primitive
condTypes = condTypes.stream()
! .map(t -> t.isPrimitive() ? types.boxedClass(t).type : t)
.collect(List.collector());
for (Type type : condTypes) {
if (condTypes.stream().filter(t -> t != type).allMatch(t -> types.isAssignable(t, type)))
return type.baseType();
}
Iterator<DiagnosticPosition> posIt = positions.iterator();
condTypes = condTypes.stream()
! .map(t -> chk.checkNonVoid(posIt.next(), t))
.collect(List.collector());
! // both are known to be reference types. The result is
// lub(thentype,elsetype). This cannot fail, as it will
// always be possible to infer "Object" if nothing better.
return types.lub(condTypes.stream()
.map(t -> t.baseType())
.filter(t -> !t.hasTag(BOT))
return candidate;
}
}
}
! // Those were all the cases that could result in a primitive. See if primitive boxing and primitive
+ // value conversions bring about a convergence.
condTypes = condTypes.stream()
! .map(t -> t.isPrimitive() ? types.boxedClass(t).type
+ : t.isReferenceProjection() ? t.valueProjection() : t)
.collect(List.collector());
for (Type type : condTypes) {
if (condTypes.stream().filter(t -> t != type).allMatch(t -> types.isAssignable(t, type)))
return type.baseType();
}
Iterator<DiagnosticPosition> posIt = positions.iterator();
condTypes = condTypes.stream()
! .map(t -> chk.checkNonVoid(posIt.next(), t.isPrimitiveClass() ? t.referenceProjection() : t))
.collect(List.collector());
! // both are known to be reference types (or projections). The result is
// lub(thentype,elsetype). This cannot fail, as it will
// always be possible to infer "Object" if nothing better.
return types.lub(condTypes.stream()
.map(t -> t.baseType())
.filter(t -> !t.hasTag(BOT))
Symbol msym = TreeInfo.symbol(tree.meth);
restype = adjustMethodReturnType(msym, qualifier, methName, argtypes, restype);
chk.checkRefTypes(tree.typeargs, typeargtypes);
+ final Symbol symbol = TreeInfo.symbol(tree.meth);
+ if (symbol != null) {
+ /* Is this an ill-conceived attempt to invoke jlO methods not available on value class types ??
+ */
+ boolean superCallOnValueReceiver = env.enclClass.sym.type.isValueClass()
+ && (tree.meth.hasTag(SELECT))
+ && ((JCFieldAccess)tree.meth).selected.hasTag(IDENT)
+ && TreeInfo.name(((JCFieldAccess)tree.meth).selected) == names._super;
+ if (qualifier.isValueClass() || superCallOnValueReceiver) {
+ int argSize = argtypes.size();
+ Name name = symbol.name;
+ switch (name.toString()) {
+ case "wait":
+ if (argSize == 0
+ || (types.isConvertible(argtypes.head, syms.longType) &&
+ (argSize == 1 || (argSize == 2 && types.isConvertible(argtypes.tail.head, syms.intType))))) {
+ log.error(tree.pos(), Errors.ValueClassDoesNotSupport(name));
+ }
+ break;
+ case "notify":
+ case "notifyAll":
+ case "finalize":
+ if (argSize == 0)
+ log.error(tree.pos(), Errors.ValueClassDoesNotSupport(name));
+ break;
+ }
+ }
+ }
+
// Check that value of resulting type is admissible in the
// current context. Also, capture the return type
Type capturedRes = resultInfo.checkContext.inferenceContext().cachedCapture(tree, restype, true);
result = check(tree, capturedRes, KindSelector.VAL, resultInfo);
}
if (msym != null &&
(msym.owner == syms.objectType.tsym || msym.owner.isInterface()) &&
methodName == names.getClass &&
argtypes.isEmpty()) {
// as a special case, x.getClass() has type Class<? extends |X|>
return new ClassType(restype.getEnclosingType(),
! List.of(new WildcardType(types.erasure(qualifierType),
BoundKind.EXTENDS,
syms.boundClass)),
restype.tsym,
! restype.getMetadata());
} else if (msym != null &&
msym.owner == syms.arrayClass &&
methodName == names.clone &&
types.isArray(qualifierType)) {
// as a special case, array.clone() has a result that is
if (msym != null &&
(msym.owner == syms.objectType.tsym || msym.owner.isInterface()) &&
methodName == names.getClass &&
argtypes.isEmpty()) {
// as a special case, x.getClass() has type Class<? extends |X|>
+ // Special treatment for primitive classes: Given an expression v of type V where
+ // V is a primitive class, v.getClass() is typed to be Class<? extends |V.ref|>
+ Type wcb = types.erasure(qualifierType.isPrimitiveClass() ?
+ qualifierType.referenceProjection() : qualifierType);
return new ClassType(restype.getEnclosingType(),
! List.of(new WildcardType(wcb,
BoundKind.EXTENDS,
syms.boundClass)),
restype.tsym,
! restype.getMetadata(),
+ restype.getFlavor());
} else if (msym != null &&
msym.owner == syms.arrayClass &&
methodName == names.clone &&
types.isArray(qualifierType)) {
// as a special case, array.clone() has a result that is
log.error(tree.pos(), Errors.EnumCantBeInstantiated);
boolean isSpeculativeDiamondInferenceRound = TreeInfo.isDiamond(tree) &&
resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.SPECULATIVE;
boolean skipNonDiamondPath = false;
+ // Check that it is an instantiation of a class and not a projection type
+ if (clazz.hasTag(SELECT)) {
+ JCFieldAccess fieldAccess = (JCFieldAccess) clazz;
+ if (fieldAccess.selected.type.isPrimitiveClass() &&
+ (fieldAccess.name == names.ref || fieldAccess.name == names.val)) {
+ log.error(tree.pos(), Errors.ProjectionCantBeInstantiated);
+ }
+ }
// Check that class is not abstract
if (cdef == null && !isSpeculativeDiamondInferenceRound && // class body may be nulled out in speculative tree copy
(clazztype.tsym.flags() & (ABSTRACT | INTERFACE)) != 0) {
log.error(tree.pos(),
Errors.AbstractCantBeInstantiated(clazztype.tsym));
}
if (TreeInfo.isDiamond(tree)) {
ClassType site = new ClassType(clazztype.getEnclosingType(),
clazztype.tsym.type.getTypeArguments(),
clazztype.tsym,
! clazztype.getMetadata());
Env<AttrContext> diamondEnv = localEnv.dup(tree);
diamondEnv.info.selectSuper = cdef != null || tree.classDeclRemoved();
diamondEnv.info.pendingResolutionPhase = null;
}
if (TreeInfo.isDiamond(tree)) {
ClassType site = new ClassType(clazztype.getEnclosingType(),
clazztype.tsym.type.getTypeArguments(),
clazztype.tsym,
! clazztype.getMetadata(),
+ clazztype.getFlavor());
Env<AttrContext> diamondEnv = localEnv.dup(tree);
diamondEnv.info.selectSuper = cdef != null || tree.classDeclRemoved();
diamondEnv.info.pendingResolutionPhase = null;
}
// For <>(){}, inferred types must also be accessible.
for (Type t : clazztype.getTypeArguments()) {
rs.checkAccessibleType(env, t);
}
+ chk.checkParameterizationByPrimitiveClass(tree, clazztype);
}
// If we already errored, be careful to avoid a further avalanche. ErrorType answers
// false for isInterface call even when the original type is an interface.
boolean implementing = clazztype.tsym.isInterface() ||
*/
public JCExpression makeNullCheck(JCExpression arg) {
// optimization: new Outer() can never be null; skip null check
if (arg.getTag() == NEWCLASS)
return arg;
+ // Likewise arg can't be null if it is a primitive class instance.
+ if (arg.type.isPrimitiveClass())
+ return arg;
// optimization: X.this is never null; skip null check
Name name = TreeInfo.name(arg);
if (name == names._this || name == names._super) return arg;
JCTree.Tag optag = NULLCHK;
// comparisons will not have an acmp* opc at this point.
if ((opc == ByteCodes.if_acmpeq || opc == ByteCodes.if_acmpne)) {
if (!types.isCastable(left, right, new Warner(tree.pos()))) {
log.error(tree.pos(), Errors.IncomparableTypes(left, right));
}
+ chk.checkForSuspectClassLiteralComparison(tree, left, right);
}
chk.checkDivZero(tree.rhs.pos(), operator, right);
}
result = check(tree, owntype, KindSelector.VAL, resultInfo);
skind = KindSelector.of(skind, KindSelector.VAL, KindSelector.TYP);
}
// Attribute the qualifier expression, and determine its symbol (if any).
Type site = attribTree(tree.selected, env, new ResultInfo(skind, Type.noType));
+ Assert.check(site == tree.selected.type);
+ if (tree.name == names._class && site.isPrimitiveClass()) {
+ /* JDK-8269956: Where a reflective (class) literal is needed, the unqualified Point.class is
+ * always the "primary" mirror - representing the primitive reference runtime type - thereby
+ * always matching the behavior of Object::getClass
+ */
+ if (!tree.selected.hasTag(SELECT) || ((JCFieldAccess) tree.selected).name != names.val) {
+ tree.selected.setType(site = site.referenceProjection());
+ }
+ }
if (!pkind().contains(KindSelector.TYP_PCK))
site = capture(site); // Capture field access
// don't allow T.class T[].class, etc
if (skind == KindSelector.TYP) {
elt = ((ArrayType)elt).elemtype;
if (elt.hasTag(TYPEVAR)) {
log.error(tree.pos(), Errors.TypeVarCantBeDeref);
result = tree.type = types.createErrorType(tree.name, site.tsym, site);
tree.sym = tree.type.tsym;
! return ;
}
}
// If qualifier symbol is a type or `super', assert `selectSuper'
// for the selection. This is relevant for determining whether
// protected symbols are accessible.
Symbol sitesym = TreeInfo.symbol(tree.selected);
boolean selectSuperPrev = env.info.selectSuper;
env.info.selectSuper =
sitesym != null &&
sitesym.name == names._super;
elt = ((ArrayType)elt).elemtype;
if (elt.hasTag(TYPEVAR)) {
log.error(tree.pos(), Errors.TypeVarCantBeDeref);
result = tree.type = types.createErrorType(tree.name, site.tsym, site);
tree.sym = tree.type.tsym;
! return;
}
}
// If qualifier symbol is a type or `super', assert `selectSuper'
// for the selection. This is relevant for determining whether
// protected symbols are accessible.
Symbol sitesym = TreeInfo.symbol(tree.selected);
+
boolean selectSuperPrev = env.info.selectSuper;
env.info.selectSuper =
sitesym != null &&
sitesym.name == names._super;
// Check that super-qualified symbols are not abstract (JLS)
rs.checkNonAbstract(tree.pos(), sym);
if (site.isRaw()) {
// Determine argument types for site.
! Type site1 = types.asSuper(env.enclClass.sym.type, site.tsym);
if (site1 != null) site = site1;
}
}
if (env.info.isSerializable) {
// Check that super-qualified symbols are not abstract (JLS)
rs.checkNonAbstract(tree.pos(), sym);
if (site.isRaw()) {
// Determine argument types for site.
! Type site1 = types.asSuper(env.enclClass.sym.type.referenceProjectionOrSelf(), site.tsym);
if (site1 != null) site = site1;
}
}
if (env.info.isSerializable) {
return rs.resolveSelf(pos, env, site.tsym, name);
} else if (name == names._class) {
// In this case, we have already made sure in
// visitSelect that qualifier expression is a type.
return syms.getClassField(site, types);
+ } else if (site.isPrimitiveClass() && isType(location) && resultInfo.pkind.contains(KindSelector.TYP) && (name == names.ref || name == names.val)) {
+ return site.tsym;
} else {
// We are seeing a plain identifier as selector.
Symbol sym = rs.findIdentInType(pos, env, site, name, resultInfo.pkind);
sym = rs.accessBase(sym, pos, location, site, name, true);
return sym;
}
Type owntype; // The computed type of this identifier occurrence.
switch (sym.kind) {
case TYP:
// For types, the computed type equals the symbol's type,
! // except for two situations:
owntype = sym.type;
if (owntype.hasTag(CLASS)) {
chk.checkForBadAuxiliaryClassAccess(tree.pos(), env, (ClassSymbol)sym);
Type ownOuter = owntype.getEnclosingType();
! // (a) If the symbol's type is parameterized, erase it
// because no type parameters were given.
// We recover generic outer type later in visitTypeApply.
if (owntype.tsym.type.getTypeArguments().nonEmpty()) {
owntype = types.erasure(owntype);
}
! // (b) If the symbol's type is an inner class, then
// we have to interpret its outer type as a superclass
// of the site type. Example:
//
// class Tree<A> { class Visitor { ... } }
// class PointTree extends Tree<Point> { ... }
}
Type owntype; // The computed type of this identifier occurrence.
switch (sym.kind) {
case TYP:
// For types, the computed type equals the symbol's type,
! // except for three situations:
owntype = sym.type;
if (owntype.hasTag(CLASS)) {
+ Assert.check(owntype.getFlavor() != Flavor.X_Typeof_X);
chk.checkForBadAuxiliaryClassAccess(tree.pos(), env, (ClassSymbol)sym);
Type ownOuter = owntype.getEnclosingType();
! // (a) If symbol is a primitive class and its reference projection
+ // is requested via the .ref notation, then adjust the computed type to
+ // reflect this.
+ if (owntype.isPrimitiveClass() && tree.hasTag(SELECT) && ((JCFieldAccess) tree).name == names.ref) {
+ owntype = new ClassType(owntype.getEnclosingType(), owntype.getTypeArguments(), (TypeSymbol)sym, owntype.getMetadata(), Flavor.L_TypeOf_Q);
+ }
+
+ // (b) If the symbol's type is parameterized, erase it
// because no type parameters were given.
// We recover generic outer type later in visitTypeApply.
if (owntype.tsym.type.getTypeArguments().nonEmpty()) {
owntype = types.erasure(owntype);
}
! // (c) If the symbol's type is an inner class, then
// we have to interpret its outer type as a superclass
// of the site type. Example:
//
// class Tree<A> { class Visitor { ... } }
// class PointTree extends Tree<Point> { ... }
if (normOuter == null) // perhaps from an import
normOuter = types.erasure(ownOuter);
if (normOuter != ownOuter)
owntype = new ClassType(
normOuter, List.nil(), owntype.tsym,
! owntype.getMetadata());
}
}
break;
case VAR:
VarSymbol v = (VarSymbol)sym;
if (normOuter == null) // perhaps from an import
normOuter = types.erasure(ownOuter);
if (normOuter != ownOuter)
owntype = new ClassType(
normOuter, List.nil(), owntype.tsym,
! owntype.getMetadata(), owntype.getFlavor());
}
}
break;
case VAR:
VarSymbol v = (VarSymbol)sym;
log.report(errDiag);
return types.createErrorType(site);
}
}
+ public void visitDefaultValue(JCDefaultValue tree) {
+ if (!allowPrimitiveClasses) {
+ log.error(DiagnosticFlag.SOURCE_LEVEL, tree.pos(),
+ Feature.PRIMITIVE_CLASSES.error(sourceName));
+ }
+
+ // Attribute the qualifier expression, and determine its symbol (if any).
+ Type site = attribTree(tree.clazz, env, new ResultInfo(KindSelector.TYP_PCK, Type.noType));
+ if (!pkind().contains(KindSelector.TYP_PCK))
+ site = capture(site); // Capture field access
+
+ Symbol sym = switch (site.getTag()) {
+ case WILDCARD -> throw new AssertionError(tree);
+ case PACKAGE -> {
+ log.error(tree.pos, Errors.CantResolveLocation(Kinds.KindName.CLASS, site.tsym.getQualifiedName(), null, null,
+ Fragments.Location(Kinds.typeKindName(env.enclClass.type), env.enclClass.type, null)));
+ yield syms.errSymbol;
+ }
+ case ERROR -> types.createErrorType(names._default, site.tsym, site).tsym;
+ default -> new VarSymbol(STATIC, names._default, site, site.tsym);
+ };
+
+ if (site.hasTag(TYPEVAR) && sym.kind != ERR) {
+ site = types.skipTypeVars(site, true);
+ }
+ result = checkId(tree, site, sym, env, resultInfo);
+ }
+
public void visitLiteral(JCLiteral tree) {
result = check(tree, litType(tree.typetag).constType(tree.value),
KindSelector.VAL, resultInfo);
}
//where
site = types.erasure(clazzOuter);
clazzOuter = site;
}
}
owntype = new ClassType(clazzOuter, actuals, clazztype.tsym,
! clazztype.getMetadata());
} else {
if (formals.length() != 0) {
log.error(tree.pos(),
Errors.WrongNumberTypeArgs(Integer.toString(formals.length())));
} else {
site = types.erasure(clazzOuter);
clazzOuter = site;
}
}
owntype = new ClassType(clazzOuter, actuals, clazztype.tsym,
! clazztype.getMetadata(), clazztype.getFlavor());
} else {
if (formals.length() != 0) {
log.error(tree.pos(),
Errors.WrongNumberTypeArgs(Integer.toString(formals.length())));
} else {
} else {
extending = null;
implementing = bounds;
}
JCClassDecl cd = make.at(tree).ClassDef(
! make.Modifiers(PUBLIC | ABSTRACT),
names.empty, List.nil(),
extending, implementing, List.nil());
ClassSymbol c = (ClassSymbol)owntype.tsym;
Assert.check((c.flags() & COMPOUND) != 0);
} else {
extending = null;
implementing = bounds;
}
JCClassDecl cd = make.at(tree).ClassDef(
! make.Modifiers(PUBLIC | ABSTRACT | (extending != null && TreeInfo.symbol(extending).isPrimitiveClass() ? PRIMITIVE_CLASS : 0)),
names.empty, List.nil(),
extending, implementing, List.nil());
ClassSymbol c = (ClassSymbol)owntype.tsym;
Assert.check((c.flags() & COMPOUND) != 0);
public void visitWildcard(JCWildcard tree) {
//- System.err.println("visitWildcard("+tree+");");//DEBUG
Type type = (tree.kind.kind == BoundKind.UNBOUND)
? syms.objectType
: attribType(tree.inner, env);
! result = check(tree, new WildcardType(chk.checkRefType(tree.pos(), type),
tree.kind.kind,
syms.boundClass),
KindSelector.TYP, resultInfo);
}
public void visitWildcard(JCWildcard tree) {
//- System.err.println("visitWildcard("+tree+");");//DEBUG
Type type = (tree.kind.kind == BoundKind.UNBOUND)
? syms.objectType
: attribType(tree.inner, env);
! result = check(tree, new WildcardType(chk.checkRefType(tree.pos(), type, false),
tree.kind.kind,
syms.boundClass),
KindSelector.TYP, resultInfo);
}
*/
public void attribClass(DiagnosticPosition pos, ClassSymbol c) {
try {
annotate.flush();
attribClass(c);
+ if (c.type.isPrimitiveClass()) {
+ final Env<AttrContext> env = typeEnvs.get(c);
+ if (env != null && env.tree != null && env.tree.hasTag(CLASSDEF))
+ chk.checkNonCyclicMembership((JCClassDecl)env.tree);
+ }
} catch (CompletionFailure ex) {
chk.completionError(pos, ex);
}
}
if (!hasErrorSuper) {
log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.NonSealedWithNoSealedSupertype(c));
}
}
! } else {
if (c.isDirectlyOrIndirectlyLocal() && !c.isEnum()) {
log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.LocalClassesCantExtendSealed(c.isAnonymous() ? Fragments.Anonymous : Fragments.Local));
}
if (!c.type.isCompound()) {
if (!hasErrorSuper) {
log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.NonSealedWithNoSealedSupertype(c));
}
}
! } else if ((c.flags_field & Flags.COMPOUND) == 0) {
if (c.isDirectlyOrIndirectlyLocal() && !c.isEnum()) {
log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.LocalClassesCantExtendSealed(c.isAnonymous() ? Fragments.Anonymous : Fragments.Local));
}
if (!c.type.isCompound()) {
if (rs.isSerializable(c.type)) {
env.info.isSerializable = true;
}
+ if (c.isValueClass()) {
+ Assert.check(env.tree.hasTag(CLASSDEF));
+ chk.checkConstraintsOfValueClass(env.tree.pos(), c);
+ }
+
attribClassBody(env, c);
chk.checkDeprecatedAnnotation(env.tree.pos(), c);
chk.checkClassOverrideEqualsAndHashIfNeeded(env.tree.pos(), c);
chk.checkFunctionalInterface((JCClassDecl) env.tree, c);
< prev index next >