< prev index next > src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
Print this page
useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
captureMRefReturnType = Source.Feature.CAPTURE_MREF_RETURN_TYPE.allowedInSource(source);
statInfo = new ResultInfo(KindSelector.NIL, Type.noType);
varAssignmentInfo = new ResultInfo(KindSelector.ASG, Type.noType);
+ varAssignmentOpInfo = new ResultInfo(KindSelector.of(KindSelector.VAL, KindSelector.ASG), Type.noType);
unknownExprInfo = new ResultInfo(KindSelector.VAL, Type.noType);
methodAttrInfo = new MethodAttrInfo();
unknownTypeInfo = new ResultInfo(KindSelector.TYP, Type.noType);
unknownTypeExprInfo = new ResultInfo(KindSelector.VAL_TYP, Type.noType);
recoveryInfo = new RecoveryInfo(deferredAttr.emptyDeferredAttrContext);
initBlockType = new MethodType(List.nil(), syms.voidType, List.nil(), syms.methodClass);
+ allowValueClasses = preview.isEnabled() && Feature.VALUE_CLASSES.allowedInSource(source);
}
/** Switch: reifiable types in instanceof enabled?
*/
boolean allowReifiableTypesInInstanceof;
/** Are unconditional patterns in instanceof allowed
*/
private final boolean allowUnconditionalPatternsInstanceOf;
+ /** Are value classes allowed
+ */
+ private final boolean allowValueClasses;
+
/**
* Switch: warn about use of variable before declaration?
* RFE: 6425594
*/
boolean useBeforeDeclarationWarning;
} else {
log.error(pos, Errors.CantAssignValToVar(Flags.toSource(v.flags() & (STATIC | FINAL)), v));
}
return;
}
-
- // Check instance field assignments that appear in constructor prologues
- if (rs.isEarlyReference(env, base, v)) {
-
- // Field may not be inherited from a superclass
- if (v.owner != env.enclClass.sym) {
- log.error(pos, Errors.CantRefBeforeCtorCalled(v));
- return;
- }
-
- // Field may not have an initializer
- if ((v.flags() & HASINIT) != 0) {
- log.error(pos, Errors.CantAssignInitializedBeforeCtorCalled(v));
- return;
- }
- }
}
/** Does tree represent a static reference to an identifier?
* It is assumed that tree is either a SELECT or an IDENT.
* We have to weed out selects from non-type names here.
}
}
final ResultInfo statInfo;
final ResultInfo varAssignmentInfo;
+ final ResultInfo varAssignmentOpInfo;
final ResultInfo methodAttrInfo;
final ResultInfo unknownExprInfo;
final ResultInfo unknownTypeInfo;
final ResultInfo unknownTypeExprInfo;
final ResultInfo recoveryInfo;
public void visitClassDef(JCClassDecl tree) {
Optional<ArgumentAttr.LocalCacheContext> localCacheContext =
Optional.ofNullable(env.info.attributionMode.isSpeculative ?
argumentAttr.withLocalCacheContext() : null);
! boolean ctorProloguePrev = env.info.ctorPrologue;
try {
// Local and anonymous classes have not been entered yet, so we need to
// do it now.
if (env.info.scope.owner.kind.matches(KindSelector.VAL_MTH)) {
enter.classEnter(tree, env);
} else {
public void visitClassDef(JCClassDecl tree) {
Optional<ArgumentAttr.LocalCacheContext> localCacheContext =
Optional.ofNullable(env.info.attributionMode.isSpeculative ?
argumentAttr.withLocalCacheContext() : null);
! EarlyConstructionContext earlyConstructionPrev = env.info.earlyContext;
try {
+ env.info.earlyContext = earlyConstructionPrev.nested(true);
// Local and anonymous classes have not been entered yet, so we need to
// do it now.
if (env.info.scope.owner.kind.matches(KindSelector.VAL_MTH)) {
enter.classEnter(tree, env);
} else {
c.complete();
// If a class declaration appears in a constructor prologue,
// that means it's either a local class or an anonymous class.
// Either way, there is no immediately enclosing instance.
! if (ctorProloguePrev) {
c.flags_field |= NOOUTERTHIS;
}
attribClass(tree.pos(), c);
result = tree.type = c.type;
}
} finally {
localCacheContext.ifPresent(LocalCacheContext::leave);
! env.info.ctorPrologue = ctorProloguePrev;
}
}
public void visitMethodDef(JCMethodDecl tree) {
MethodSymbol m = tree.sym;
boolean isDefaultMethod = (m.flags() & DEFAULT) != 0;
Lint lint = env.info.lint.augment(m);
Lint prevLint = chk.setLint(lint);
! boolean ctorProloguePrev = env.info.ctorPrologue;
! Assert.check(!env.info.ctorPrologue);
MethodSymbol prevMethod = chk.setMethod(m);
try {
chk.checkDeprecatedAnnotation(tree.pos(), m);
c.complete();
// If a class declaration appears in a constructor prologue,
// that means it's either a local class or an anonymous class.
// Either way, there is no immediately enclosing instance.
! if (earlyConstructionPrev.ctorPrologue()) {
c.flags_field |= NOOUTERTHIS;
}
attribClass(tree.pos(), c);
result = tree.type = c.type;
}
} finally {
localCacheContext.ifPresent(LocalCacheContext::leave);
! env.info.earlyContext = earlyConstructionPrev;
}
}
public void visitMethodDef(JCMethodDecl tree) {
MethodSymbol m = tree.sym;
boolean isDefaultMethod = (m.flags() & DEFAULT) != 0;
Lint lint = env.info.lint.augment(m);
Lint prevLint = chk.setLint(lint);
! EarlyConstructionContext earlyConstructionPrev = env.info.earlyContext;
! Assert.check(!earlyConstructionPrev.ctorPrologue());
MethodSymbol prevMethod = chk.setMethod(m);
try {
chk.checkDeprecatedAnnotation(tree.pos(), m);
Fragments.CanonicalMustNotHaveStrongerAccess(asFlagSet(env.enclClass.sym.flags() & AccessFlags))
)
);
}
! if (TreeInfo.hasAnyConstructorCall(tree)) {
log.error(tree, Errors.InvalidCanonicalConstructorInRecord(
Fragments.Canonical, env.enclClass.sym.name,
Fragments.CanonicalMustNotContainExplicitConstructorInvocation));
}
}
Fragments.CanonicalMustNotHaveStrongerAccess(asFlagSet(env.enclClass.sym.flags() & AccessFlags))
)
);
}
! if ((!allowValueClasses || TreeInfo.isCompactConstructor(tree)) &&
+ TreeInfo.hasAnyConstructorCall(tree)) {
log.error(tree, Errors.InvalidCanonicalConstructorInRecord(
Fragments.Canonical, env.enclClass.sym.name,
Fragments.CanonicalMustNotContainExplicitConstructorInvocation));
}
}
// or we are compiling class java.lang.Object.
if (isConstructor && owner.type != syms.objectType) {
if (!TreeInfo.hasAnyConstructorCall(tree)) {
JCStatement supCall = make.at(tree.body.pos).Exec(make.Apply(List.nil(),
make.Ident(names._super), make.Idents(List.nil())));
! tree.body.stats = tree.body.stats.prepend(supCall);
} else if ((env.enclClass.sym.flags() & ENUM) != 0 &&
(tree.mods.flags & GENERATEDCONSTR) == 0 &&
TreeInfo.hasConstructorCall(tree, names._super)) {
// enum constructors are not allowed to call super
// directly, so make sure there aren't any super calls
// or we are compiling class java.lang.Object.
if (isConstructor && owner.type != syms.objectType) {
if (!TreeInfo.hasAnyConstructorCall(tree)) {
JCStatement supCall = make.at(tree.body.pos).Exec(make.Apply(List.nil(),
make.Ident(names._super), make.Idents(List.nil())));
! if (allowValueClasses && (owner.isValueClass() || owner.isRecord())) {
+ tree.body.stats = tree.body.stats.append(supCall);
+ } else {
+ tree.body.stats = tree.body.stats.prepend(supCall);
+ }
} else if ((env.enclClass.sym.flags() & ENUM) != 0 &&
(tree.mods.flags & GENERATEDCONSTR) == 0 &&
TreeInfo.hasConstructorCall(tree, names._super)) {
// enum constructors are not allowed to call super
// directly, so make sure there aren't any super calls
// Attribute all type annotations in the body
annotate.queueScanTreeAndTypeAnnotate(tree.body, localEnv, m);
annotate.flush();
// Start of constructor prologue (if not in java.lang.Object constructor)
! localEnv.info.ctorPrologue = isConstructor && owner.type != syms.objectType;
// Attribute method body.
attribStat(tree.body, localEnv);
}
localEnv.info.scope.leave();
result = tree.type = m.type;
} finally {
chk.setLint(prevLint);
chk.setMethod(prevMethod);
! env.info.ctorPrologue = ctorProloguePrev;
}
}
public void visitVarDef(JCVariableDecl tree) {
// Local variables have not been entered yet, so we need to do it now:
// Attribute all type annotations in the body
annotate.queueScanTreeAndTypeAnnotate(tree.body, localEnv, m);
annotate.flush();
// Start of constructor prologue (if not in java.lang.Object constructor)
! if (isConstructor && owner.type != syms.objectType) {
+ boolean hasThisConstructorCall = TreeInfo.hasConstructorCall(tree, names._this);
+ localEnv.info.earlyContext = EarlyConstructionContext.of(owner,
+ hasThisConstructorCall && allowValueClasses);
+ }
// Attribute method body.
attribStat(tree.body, localEnv);
}
localEnv.info.scope.leave();
result = tree.type = m.type;
} finally {
chk.setLint(prevLint);
chk.setMethod(prevMethod);
! env.info.earlyContext = earlyConstructionPrev;
}
}
public void visitVarDef(JCVariableDecl tree) {
// Local variables have not been entered yet, so we need to do it now:
initEnv.info.lint = lint;
// In order to catch self-references, we set the variable's
// declaration position to maximal possible value, effectively
// marking the variable as undefined.
initEnv.info.enclVar = v;
! attribExpr(tree.init, initEnv, v.type);
! if (tree.isImplicitlyTyped()) {
! //fixup local variable type
! v.type = chk.checkLocalVarType(tree, tree.init.type, tree.name);
}
}
if (tree.isImplicitlyTyped()) {
setupImplicitlyTypedVariable(tree, v.type);
}
initEnv.info.lint = lint;
// In order to catch self-references, we set the variable's
// declaration position to maximal possible value, effectively
// marking the variable as undefined.
initEnv.info.enclVar = v;
! EarlyConstructionContext previousEarlyConstruction = initEnv.info.earlyContext;
! try {
! if (v.isStrictInstance() && allowValueClasses) {
! // instance strict field init occur in early construction context
+ initEnv.info.earlyContext = EarlyConstructionContext.of((ClassSymbol)v.owner, false);
+ }
+ attribExpr(tree.init, initEnv, v.type);
+ if (tree.isImplicitlyTyped()) {
+ //fixup local variable type
+ v.type = chk.checkLocalVarType(tree, tree.init.type, tree.name);
+ }
+ } finally {
+ initEnv.info.earlyContext = previousEarlyConstruction;
}
}
if (tree.isImplicitlyTyped()) {
setupImplicitlyTypedVariable(tree, v.type);
}
}
return null;
}
public void visitSynchronized(JCSynchronized tree) {
! chk.checkRefType(tree.pos(), attribExpr(tree.lock, env));
! if (tree.lock.type != null && tree.lock.type.isValueBased()) {
log.warning(tree.pos(), LintWarnings.AttemptToSynchronizeOnInstanceOfValueBasedClass);
}
attribStat(tree.body, env);
result = null;
}
}
return null;
}
public void visitSynchronized(JCSynchronized tree) {
! boolean identityType = chk.checkIdentityType(tree.pos(), attribExpr(tree.lock, env));
! if (identityType && tree.lock.type != null && tree.lock.type.isValueBased()) {
log.warning(tree.pos(), LintWarnings.AttemptToSynchronizeOnInstanceOfValueBasedClass);
}
attribStat(tree.body, env);
result = null;
}
// Attribute arguments, yielding list of argument types.
KindSelector kind = attribArgs(KindSelector.MTH, tree.args, localEnv, argtypesBuf);
argtypes = argtypesBuf.toList();
typeargtypes = attribTypes(tree.typeargs, localEnv);
! // Done with this()/super() parameters. End of constructor prologue.
! env.info.ctorPrologue = false;
// Variable `site' points to the class in which the called
// constructor is defined.
Type site = env.enclClass.sym.type;
if (methName == names._super) {
// Attribute arguments, yielding list of argument types.
KindSelector kind = attribArgs(KindSelector.MTH, tree.args, localEnv, argtypesBuf);
argtypes = argtypesBuf.toList();
typeargtypes = attribTypes(tree.typeargs, localEnv);
! // End of constructor prologue. Done with this()/super() parameters.
! env.info.earlyContext = EarlyConstructionContext.NONE;
// Variable `site' points to the class in which the called
// constructor is defined.
Type site = env.enclClass.sym.type;
if (methName == names._super) {
} else {
lambdaEnv = env.dup(that, env.info.dup(env.info.scope.dup()));
}
lambdaEnv.info.yieldResult = null;
lambdaEnv.info.isLambda = true;
+ lambdaEnv.info.earlyContext = lambdaEnv.info.earlyContext.nested(false);
return lambdaEnv;
}
@Override
public void visitReference(final JCMemberReference that) {
result = check(tree, capturedType, KindSelector.VAL, resultInfo);
}
public void visitAssignop(JCAssignOp tree) {
// Attribute arguments.
! Type owntype = attribTree(tree.lhs, env, varAssignmentInfo);
Type operand = attribExpr(tree.rhs, env);
// Find operator.
Symbol operator = tree.operator = operators.resolveBinary(tree, tree.getTag().noAssignOp(), owntype, operand);
if (operator != operators.noOpSymbol &&
!owntype.isErroneous() &&
result = check(tree, capturedType, KindSelector.VAL, resultInfo);
}
public void visitAssignop(JCAssignOp tree) {
// Attribute arguments.
! Type owntype = attribTree(tree.lhs, env, varAssignmentOpInfo);
Type operand = attribExpr(tree.rhs, env);
// Find operator.
Symbol operator = tree.operator = operators.resolveBinary(tree, tree.getTag().noAssignOp(), owntype, operand);
if (operator != operators.noOpSymbol &&
!owntype.isErroneous() &&
}
public void visitUnary(JCUnary tree) {
// Attribute arguments.
Type argtype = (tree.getTag().isIncOrDecUnaryOp())
! ? attribTree(tree.arg, env, varAssignmentInfo)
: chk.checkNonVoid(tree.arg.pos(), attribExpr(tree.arg, env));
// Find operator.
OperatorSymbol operator = tree.operator = operators.resolveUnary(tree, tree.getTag(), argtype);
Type owntype = types.createErrorType(tree.type);
}
public void visitUnary(JCUnary tree) {
// Attribute arguments.
Type argtype = (tree.getTag().isIncOrDecUnaryOp())
! ? attribTree(tree.arg, env, varAssignmentOpInfo)
: chk.checkNonVoid(tree.arg.pos(), attribExpr(tree.arg, env));
// Find operator.
OperatorSymbol operator = tree.operator = operators.resolveUnary(tree, tree.getTag(), argtype);
Type owntype = types.createErrorType(tree.type);
if (pkind().contains(KindSelector.VAL_MTH))
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));
if (!pkind().contains(KindSelector.TYP_PCK))
site = capture(site); // Capture field access
// don't allow T.class T[].class, etc
if (skind == KindSelector.TYP) {
if (pkind().contains(KindSelector.VAL_MTH))
skind = KindSelector.of(skind, KindSelector.VAL, KindSelector.TYP);
}
// Attribute the qualifier expression, and determine its symbol (if any).
! Type site;
+ EarlyConstructionContext earlyConstructionPrev = env.info.earlyContext;
+ JCTree earlyFieldQualifier = earlyFieldQualifier(tree);
+ try {
+ if (earlyFieldQualifier != null) {
+ // if we're seeing a likely field access, and qualifier is this/super,
+ // pretend we're not in early construction context. This allows Resolve
+ // to skip premature checks against this/super
+ env.info.earlyContext = EarlyConstructionContext.NONE;
+ }
+ site = attribTree(tree.selected, env, new ResultInfo(skind, Type.noType));
+ } finally {
+ env.info.earlyContext = earlyConstructionPrev;
+ }
+ Assert.check(site == tree.selected.type);
if (!pkind().contains(KindSelector.TYP_PCK))
site = capture(site); // Capture field access
// don't allow T.class T[].class, etc
if (skind == KindSelector.TYP) {
sitesym != null &&
sitesym.name == names._super;
// Determine the symbol represented by the selection.
env.info.pendingResolutionPhase = null;
! Symbol sym = selectSym(tree, sitesym, site, env, resultInfo);
if (sym.kind == VAR && sym.name != names._super && env.info.defaultSuperCallSite != null) {
log.error(tree.selected.pos(), Errors.NotEnclClass(site.tsym));
sym = syms.errSymbol;
}
! if (sym.exists() && !isType(sym) && pkind().contains(KindSelector.TYP_PCK)) {
site = capture(site);
! sym = selectSym(tree, sitesym, site, env, resultInfo);
}
boolean varArgs = env.info.lastResolveVarargs();
tree.sym = sym;
if (site.hasTag(TYPEVAR) && !isType(sym) && sym.kind != ERR) {
sitesym != null &&
sitesym.name == names._super;
// Determine the symbol represented by the selection.
env.info.pendingResolutionPhase = null;
! Symbol sym;
+ sym = selectSym(tree, sitesym, site, env, resultInfo, earlyFieldQualifier);
if (sym.kind == VAR && sym.name != names._super && env.info.defaultSuperCallSite != null) {
log.error(tree.selected.pos(), Errors.NotEnclClass(site.tsym));
sym = syms.errSymbol;
}
! if (sym.exists() && !isType(sym) &&
+ tree.name != names._this && tree.name != names._super &&
+ pkind().contains(KindSelector.TYP_PCK)) {
site = capture(site);
! sym = selectSym(tree, sitesym, site, env, resultInfo, earlyFieldQualifier);
}
boolean varArgs = env.info.lastResolveVarargs();
tree.sym = sym;
if (site.hasTag(TYPEVAR) && !isType(sym) && sym.kind != ERR) {
}
env.info.selectSuper = selectSuperPrev;
result = checkId(tree, site, sym, env, resultInfo);
}
+
+ private JCTree earlyFieldQualifier(JCFieldAccess tree) {
+ boolean methodSelect = resultInfo.pt.hasTag(METHOD) || resultInfo.pt.hasTag(FORALL);
+ if (!methodSelect &&
+ (TreeInfo.isThisOrSelectorDotThis(tree.selected) ||
+ TreeInfo.isSuperOrSelectorDotSuper(tree.selected))) {
+ return tree.selected;
+ }
+ return null;
+ }
+
//where
/** Determine symbol referenced by a Select expression,
*
* @param tree The select tree.
* @param site The type of the selected expression,
*/
private Symbol selectSym(JCFieldAccess tree,
Symbol location,
Type site,
Env<AttrContext> env,
! ResultInfo resultInfo) {
DiagnosticPosition pos = tree.pos();
Name name = tree.name;
switch (site.getTag()) {
case PACKAGE:
return rs.accessBase(
*/
private Symbol selectSym(JCFieldAccess tree,
Symbol location,
Type site,
Env<AttrContext> env,
! ResultInfo resultInfo,
+ JCTree earlyFieldQualifier) {
DiagnosticPosition pos = tree.pos();
Name name = tree.name;
switch (site.getTag()) {
case PACKAGE:
return rs.accessBase(
case CLASS:
if (resultInfo.pt.hasTag(METHOD) || resultInfo.pt.hasTag(FORALL)) {
return rs.resolveQualifiedMethod(
pos, env, location, site, name, resultInfo.pt.getParameterTypes(), resultInfo.pt.getTypeArguments());
} else if (name == names._this || name == names._super) {
! return rs.resolveSelf(pos, env, site.tsym, tree);
} 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 {
// 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;
}
case WILDCARD:
throw new AssertionError(tree);
case CLASS:
if (resultInfo.pt.hasTag(METHOD) || resultInfo.pt.hasTag(FORALL)) {
return rs.resolveQualifiedMethod(
pos, env, location, site, name, resultInfo.pt.getParameterTypes(), resultInfo.pt.getTypeArguments());
} else if (name == names._this || name == names._super) {
! Symbol sym = rs.resolveSelf(pos, env, site.tsym, tree);
+ return rs.accessBase(sym, pos, env.enclClass.sym.type, name, true);
} 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 {
// We are seeing a plain identifier as selector.
! Symbol sym = rs.findIdentInType(pos, env, site, name, resultInfo.pkind, earlyFieldQualifier);
sym = rs.accessBase(sym, pos, location, site, name, true);
return sym;
}
case WILDCARD:
throw new AssertionError(tree);
// when determining the supertype which *must* be
// done before attributing the type variables. In
// other words, we are seeing this illegal program:
// class B<T> extends A<T.foo> {}
Symbol sym = (site.getUpperBound() != null)
! ? selectSym(tree, location, capture(site.getUpperBound()), env, resultInfo)
: null;
if (sym == null) {
log.error(pos, Errors.TypeVarCantBeDeref);
return syms.errSymbol;
} else {
// when determining the supertype which *must* be
// done before attributing the type variables. In
// other words, we are seeing this illegal program:
// class B<T> extends A<T.foo> {}
Symbol sym = (site.getUpperBound() != null)
! ? selectSym(tree, location, capture(site.getUpperBound()), env, resultInfo, earlyFieldQualifier)
: null;
if (sym == null) {
log.error(pos, Errors.TypeVarCantBeDeref);
return syms.errSymbol;
} else {
// Check for proper use of serialVersionUID and other
// serialization-related fields and methods
if (env.info.lint.isEnabled(LintCategory.SERIAL)
&& rs.isSerializable(c.type)
&& !c.isAnonymous()) {
! chk.checkSerialStructure(tree, c);
}
// Correctly organize the positions of the type annotations
typeAnnotations.organizeTypeAnnotationsBodies(tree);
// Check type annotations applicability rules
// Check for proper use of serialVersionUID and other
// serialization-related fields and methods
if (env.info.lint.isEnabled(LintCategory.SERIAL)
&& rs.isSerializable(c.type)
&& !c.isAnonymous()) {
! chk.checkSerialStructure(env, tree, c);
}
// Correctly organize the positions of the type annotations
typeAnnotations.organizeTypeAnnotationsBodies(tree);
// Check type annotations applicability rules
< prev index next >