< 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.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;
import com.sun.tools.javac.comp.MatchBindingsComputer.MatchBindings;
attrRecover = AttrRecover.instance(context);
Options options = Options.instance(context);
Source source = Source.instance(context);
+ allowPrimitiveClasses = Feature.PRIMITIVE_CLASSES.allowedInSource(source) && options.isSet("enablePrimitiveClasses");
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);
allowUnconditionalPatternsInstanceOf = (preview.isEnabled() || !preview.isPreview(Feature.UNCONDITIONAL_PATTERN_IN_INSTANCEOF)) &&
unknownTypeInfo = new ResultInfo(KindSelector.TYP, Type.noType);
unknownTypeExprInfo = new ResultInfo(KindSelector.VAL_TYP, Type.noType);
recoveryInfo = new RecoveryInfo(deferredAttr.emptyDeferredAttrContext);
}
+ /** Switch: allow primitive classes ?
+ */
+ boolean allowPrimitiveClasses;
+
/** Switch: reifiable types in instanceof enabled?
*/
boolean allowReifiableTypesInInstanceof;
/** Are records allowed
// owner refers to the innermost variable, method or
// initializer block declaration at this point.
boolean isAssignable =
v.owner == owner
||
! ((owner.name == names.init || // i.e. we are in a constructor
owner.kind == VAR || // i.e. we are in a variable initializer
(owner.flags() & BLOCK) != 0) // i.e. we are in an initializer block
&&
v.owner == owner.owner
&&
// owner refers to the innermost variable, method or
// initializer block declaration at this point.
boolean isAssignable =
v.owner == owner
||
! ((names.isInitOrVNew(owner.name) || // i.e. we are in a constructor
owner.kind == VAR || // i.e. we are in a variable initializer
(owner.flags() & BLOCK) != 0) // i.e. we are in an initializer block
&&
v.owner == owner.owner
&&
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));
log.error(tree,
Errors.InvalidAccessorMethodInRecord(env.enclClass.sym, Fragments.AccessorMethodMustNotBeStatic));
}
}
! if (tree.name == names.init) {
// if this a constructor other than the canonical one
if ((tree.sym.flags_field & RECORD) == 0) {
JCMethodInvocation app = TreeInfo.firstConstructorCall(tree);
if (app == null ||
TreeInfo.name(app.meth) != names._this ||
log.error(tree,
Errors.InvalidAccessorMethodInRecord(env.enclClass.sym, Fragments.AccessorMethodMustNotBeStatic));
}
}
! if (names.isInitOrVNew(tree.name)) {
// if this a constructor other than the canonical one
if ((tree.sym.flags_field & RECORD) == 0) {
JCMethodInvocation app = TreeInfo.firstConstructorCall(tree);
if (app == null ||
TreeInfo.name(app.meth) != names._this ||
log.error(tree.pos(), Errors.NativeMethCantHaveBody);
}
// Add an implicit super() call unless an explicit call to
// 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 &&
log.error(tree.pos(), Errors.NativeMethCantHaveBody);
}
// Add an implicit super() call unless an explicit call to
// super(...) or this(...) is given
// or we are compiling class java.lang.Object.
! if (names.isInitOrVNew(tree.name) && 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.
for (Symbol s : syms.objectType.tsym.members().getSymbolsByName(name, s -> s.kind == MTH)) {
if (s.type.getParameterTypes().isEmpty()) {
return true;
}
}
! return false;
}
Fragment canInferLocalVarType(JCVariableDecl tree) {
LocalInitScanner lis = new LocalInitScanner();
lis.scan(tree.init);
for (Symbol s : syms.objectType.tsym.members().getSymbolsByName(name, s -> s.kind == MTH)) {
if (s.type.getParameterTypes().isEmpty()) {
return true;
}
}
! // isValueObject is not included in Object yet so we need a work around
+ return name == names.isValueObject;
}
Fragment canInferLocalVarType(JCVariableDecl tree) {
LocalInitScanner lis = new LocalInitScanner();
lis.scan(tree.init);
Type exprType = types.cvarUpperBound(attribExpr(tree.expr, loopEnv));
chk.checkNonVoid(tree.pos(), exprType);
tree.elementType = types.elemtype(exprType); // perhaps expr is an array?
if (tree.elementType == 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));
tree.elementType = types.createErrorType(exprType);
Type exprType = types.cvarUpperBound(attribExpr(tree.expr, loopEnv));
chk.checkNonVoid(tree.pos(), exprType);
tree.elementType = types.elemtype(exprType); // perhaps expr is an array?
if (tree.elementType == 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));
tree.elementType = 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(), allowPrimitiveClasses && 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))
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.baseType()),
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(allowPrimitiveClasses && qualifierType.isPrimitiveClass() ?
+ qualifierType.referenceProjection() : qualifierType.baseType());
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
* @param tree The application node
* @param enclMethod The enclosing method of the application.
* @param error Should an error be issued?
*/
boolean checkFirstConstructorStat(JCMethodInvocation tree, JCMethodDecl enclMethod, boolean error) {
! if (enclMethod != null && enclMethod.name == names.init) {
JCBlock body = enclMethod.body;
if (body.stats.head.hasTag(EXEC) &&
((JCExpressionStatement) body.stats.head).expr == tree)
return true;
}
* @param tree The application node
* @param enclMethod The enclosing method of the application.
* @param error Should an error be issued?
*/
boolean checkFirstConstructorStat(JCMethodInvocation tree, JCMethodDecl enclMethod, boolean error) {
! if (enclMethod != null && names.isInitOrVNew(enclMethod.name)) {
JCBlock body = enclMethod.body;
if (body.stats.head.hasTag(EXEC) &&
((JCExpressionStatement) body.stats.head).expr == tree)
return true;
}
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 (allowPrimitiveClasses) {
+ 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);
}
+ if (allowPrimitiveClasses) {
+ 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 (allowPrimitiveClasses && 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;
/* if the field isn't static, then we can get the first constructor
* and use it as the owner of the environment. This is what
* LTM code is doing to look for type annotations so we are fine.
*/
if ((owner.flags() & STATIC) == 0) {
! for (Symbol s : enclClass.members_field.getSymbolsByName(names.init)) {
newScopeOwner = s;
break;
}
} else {
/* if the field is static then we need to create a fake clinit
/* if the field isn't static, then we can get the first constructor
* and use it as the owner of the environment. This is what
* LTM code is doing to look for type annotations so we are fine.
*/
if ((owner.flags() & STATIC) == 0) {
! Name constructorName = owner.isConcreteValueClass() ? names.vnew : names.init;
+ for (Symbol s : enclClass.members_field.getSymbolsByName(constructorName)) {
newScopeOwner = s;
break;
}
} else {
/* if the field is static then we need to create a fake clinit
//give up attribution of method reference
result = that.type = exprType;
return;
}
if (TreeInfo.isStaticSelector(that.expr, names)) {
//if the qualifier is a type, validate it; raw warning check is
//omitted as we don't know at this stage as to whether this is a
//raw selector (because of inference)
chk.validate(that.expr, env, false);
} else {
- Symbol lhsSym = TreeInfo.symbol(that.expr);
localEnv.info.selectSuper = lhsSym != null && lhsSym.name == names._super;
}
//attrib type-arguments
List<Type> typeargtypes = List.nil();
if (that.typeargs != null) {
//give up attribution of method reference
result = that.type = exprType;
return;
}
+ Symbol lhsSym = TreeInfo.symbol(that.expr);
if (TreeInfo.isStaticSelector(that.expr, names)) {
+ // TODO - a bit hacky but...
+ if (lhsSym != null && lhsSym.isConcreteValueClass() && that.name == names.init) {
+ that.name = names.vnew;
+ }
//if the qualifier is a type, validate it; raw warning check is
//omitted as we don't know at this stage as to whether this is a
//raw selector (because of inference)
chk.validate(that.expr, env, false);
} else {
localEnv.info.selectSuper = lhsSym != null && lhsSym.name == names._super;
}
//attrib type-arguments
List<Type> typeargtypes = List.nil();
if (that.typeargs != null) {
result = that.type = types.createErrorType(currentTarget);
return;
}
}
! that.sym = refSym.isConstructor() ? refSym.baseSymbol() : refSym;
that.kind = lookupHelper.referenceKind(that.sym);
that.ownerAccessible = rs.isAccessible(localEnv, that.sym.enclClass());
if (desc.getReturnType() == Type.recoveryType) {
// stop here
result = that.type = types.createErrorType(currentTarget);
return;
}
}
! that.sym = refSym.isInitOrVNew() ? refSym.baseSymbol() : refSym;
that.kind = lookupHelper.referenceKind(that.sym);
that.ownerAccessible = rs.isAccessible(localEnv, that.sym.enclClass());
if (desc.getReturnType() == Type.recoveryType) {
// stop here
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 (allowPrimitiveClasses && 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
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
// 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 (allowPrimitiveClasses && 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)) {
+ if (allowPrimitiveClasses) {
+ 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 (allowPrimitiveClasses && 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;
// Emit a `deprecation' warning if symbol is deprecated.
// (for constructors (but not for constructor references), the error
// was given when the constructor was resolved)
! if (sym.name != names.init || tree.hasTag(REFERENCE)) {
chk.checkDeprecated(tree.pos(), env.info.scope.owner, sym);
chk.checkSunAPI(tree.pos(), sym);
chk.checkProfile(tree.pos(), sym);
chk.checkPreview(tree.pos(), env.info.scope.owner, sym);
}
// Emit a `deprecation' warning if symbol is deprecated.
// (for constructors (but not for constructor references), the error
// was given when the constructor was resolved)
! if (!names.isInitOrVNew(sym.name) || tree.hasTag(REFERENCE)) {
chk.checkDeprecated(tree.pos(), env.info.scope.owner, sym);
chk.checkSunAPI(tree.pos(), sym);
chk.checkProfile(tree.pos(), sym);
chk.checkPreview(tree.pos(), env.info.scope.owner, 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
+ if (!allowPrimitiveClasses) {
+ result = types.createErrorType(names._default, site.tsym, site);
+ } else {
+ 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 (allowPrimitiveClasses && 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 >