< prev index next > src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
Print this page
fileManager = context.get(JavaFileManager.class);
source = Source.instance(context);
target = Target.instance(context);
warnOnAnyAccessToMembers = options.isSet("warnOnAccessToMembers");
-
Target target = Target.instance(context);
syntheticNameChar = target.syntheticNameChar();
profile = Profile.instance(context);
preview = Preview.instance(context);
public void removeCompiled(ClassSymbol csym) {
compiled.remove(Pair.of(csym.packge().modle, csym.flatname));
}
! /* *************************************************************************
* Type Checking
**************************************************************************/
/**
* A check context is an object that can be used to perform compatibility
public void removeCompiled(ClassSymbol csym) {
compiled.remove(Pair.of(csym.packge().modle, csym.flatname));
}
! /* *************************************************************************
* Type Checking
**************************************************************************/
/**
* A check context is an object that can be used to perform compatibility
Type checkType(final DiagnosticPosition pos, final Type found, final Type req, final CheckContext checkContext) {
final InferenceContext inferenceContext = checkContext.inferenceContext();
if (inferenceContext.free(req) || inferenceContext.free(found)) {
inferenceContext.addFreeTypeListener(List.of(req, found),
solvedContext -> checkType(pos, solvedContext.asInstType(found), solvedContext.asInstType(req), checkContext));
+ } else {
+ if (found.hasTag(CLASS)) {
+ if (inferenceContext != infer.emptyContext)
+ checkParameterizationByPrimitiveClass(pos, found);
+ }
}
if (req.hasTag(ERROR))
return req;
if (req.hasTag(NONE))
return found;
return (t.hasTag(TYPEVAR))
? diags.fragment(Fragments.TypeParameter(t))
: t;
}
/** Check that type is a valid qualifier for a constructor reference expression
*/
! Type checkConstructorRefType(DiagnosticPosition pos, Type t) {
! t = checkClassOrArrayType(pos, t);
if (t.hasTag(CLASS)) {
if ((t.tsym.flags() & (ABSTRACT | INTERFACE)) != 0) {
! log.error(pos, Errors.AbstractCantBeInstantiated(t.tsym));
t = types.createErrorType(t);
} else if ((t.tsym.flags() & ENUM) != 0) {
! log.error(pos, Errors.EnumCantBeInstantiated);
t = types.createErrorType(t);
} else {
! t = checkClassType(pos, t, true);
}
} else if (t.hasTag(ARRAY)) {
if (!types.isReifiable(((ArrayType)t).elemtype)) {
! log.error(pos, Errors.GenericArrayCreation);
t = types.createErrorType(t);
}
}
return t;
}
return (t.hasTag(TYPEVAR))
? diags.fragment(Fragments.TypeParameter(t))
: t;
}
+ void checkSuperConstraintsOfValueClass(DiagnosticPosition pos, ClassSymbol c) {
+ for(Type st = types.supertype(c.type); st != Type.noType; st = types.supertype(st)) {
+ if (st == null || st.tsym == null || st.tsym.kind == ERR)
+ return;
+ if (st.tsym == syms.objectType.tsym)
+ return;
+ if (!st.tsym.isAbstract()) {
+ log.error(pos, Errors.ConcreteSupertypeForValueClass(c, st));
+ }
+ if ((st.tsym.flags() & IDENTITY_TYPE) == 0) {
+ return;
+ }
+ // TODO: If an IDENTITY_TYPE we may not issue an error below, if older abstract class qualifies
+ // We have an unsuitable abstract super class, find out why exactly and complain
+ if ((st.tsym.flags() & HASINITBLOCK) != 0) {
+ log.error(pos, Errors.SuperClassDeclaresInitBlock(c, st));
+ }
+ // No instance fields and no arged constructors both mean inner classes
+ // cannot be super classes for primitive classes.
+ Type encl = st.getEnclosingType();
+ if (encl != null && encl.hasTag(CLASS)) {
+ log.error(pos, Errors.SuperClassCannotBeInner(c, st));
+ }
+ for (Symbol s : st.tsym.members().getSymbols(NON_RECURSIVE)) {
+ switch (s.kind) {
+ case VAR:
+ if ((s.flags() & STATIC) == 0) {
+ log.error(pos, Errors.SuperFieldNotAllowed(s, c, st));
+ }
+ break;
+ case MTH:
+ if ((s.flags() & SYNCHRONIZED) != 0) {
+ log.error(pos, Errors.SuperMethodCannotBeSynchronized(s, c, st));
+ } else if (s.isConstructor()) {
+ MethodSymbol m = (MethodSymbol)s;
+ if (m.getParameters().size() > 0) {
+ log.error(pos, Errors.SuperConstructorCannotTakeArguments(m, c, st));
+ } else {
+ if ((m.flags() & EMPTYNOARGCONSTR) == 0) {
+ log.error(pos, Errors.SuperNoArgConstructorMustBeEmpty(m, c, st));
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
/** Check that type is a valid qualifier for a constructor reference expression
*/
! Type checkConstructorRefType(JCExpression expr, Type t) {
! t = checkClassOrArrayType(expr, t);
if (t.hasTag(CLASS)) {
if ((t.tsym.flags() & (ABSTRACT | INTERFACE)) != 0) {
! log.error(expr, Errors.AbstractCantBeInstantiated(t.tsym));
t = types.createErrorType(t);
} else if ((t.tsym.flags() & ENUM) != 0) {
! log.error(expr, Errors.EnumCantBeInstantiated);
t = types.createErrorType(t);
} else {
! // Projection types may not be mentioned in constructor references
+ if (expr.hasTag(SELECT)) {
+ JCFieldAccess fieldAccess = (JCFieldAccess) expr;
+ if (fieldAccess.selected.type.isPrimitiveClass() &&
+ (fieldAccess.name == names.ref || fieldAccess.name == names.val)) {
+ log.error(expr, Errors.ProjectionCantBeInstantiated);
+ t = types.createErrorType(t);
+ }
+ }
+ t = checkClassType(expr, t, true);
}
} else if (t.hasTag(ARRAY)) {
if (!types.isReifiable(((ArrayType)t).elemtype)) {
! log.error(expr, Errors.GenericArrayCreation);
t = types.createErrorType(t);
}
}
return t;
}
/** Check that type is a reference type, i.e. a class, interface or array type
* or a type variable.
* @param pos Position to be used for error reporting.
* @param t The type to be checked.
*/
! Type checkRefType(DiagnosticPosition pos, Type t) {
! if (t.isReference())
return t;
else
return typeTagError(pos,
diags.fragment(Fragments.TypeReqRef),
t);
}
/** Check that each type is a reference type, i.e. a class, interface or array type
* or a type variable.
* @param trees Original trees, used for error reporting.
* @param types The types to be checked.
*/
List<Type> checkRefTypes(List<JCExpression> trees, List<Type> types) {
List<JCExpression> tl = trees;
for (List<Type> l = types; l.nonEmpty(); l = l.tail) {
! l.head = checkRefType(tl.head.pos(), l.head);
tl = tl.tail;
}
return types;
}
/** Check that type is a reference type, i.e. a class, interface or array type
* or a type variable.
* @param pos Position to be used for error reporting.
* @param t The type to be checked.
+ * @param primitiveClassOK If false, a primitive class does not qualify
*/
! Type checkRefType(DiagnosticPosition pos, Type t, boolean primitiveClassOK) {
! if (t.isReference() && (primitiveClassOK || !t.isPrimitiveClass()))
return t;
else
return typeTagError(pos,
diags.fragment(Fragments.TypeReqRef),
t);
}
+ /** Check that type is an identity type, i.e. not a primitive type
+ * nor its reference projection. When not discernible statically,
+ * give it the benefit of doubt and defer to runtime.
+ *
+ * @param pos Position to be used for error reporting.
+ * @param t The type to be checked.
+ */
+ Type checkIdentityType(DiagnosticPosition pos, Type t) {
+
+ if (t.isPrimitive() || t.isValueClass() || t.isReferenceProjection())
+ return typeTagError(pos,
+ diags.fragment(Fragments.TypeReqIdentity),
+ t);
+
+ return t;
+ }
+
+ /** Check that type is a reference type, i.e. a class, interface or array type
+ * or a type variable.
+ * @param pos Position to be used for error reporting.
+ * @param t The type to be checked.
+ */
+ Type checkRefType(DiagnosticPosition pos, Type t) {
+ return checkRefType(pos, t, true);
+ }
+
/** Check that each type is a reference type, i.e. a class, interface or array type
* or a type variable.
* @param trees Original trees, used for error reporting.
* @param types The types to be checked.
*/
List<Type> checkRefTypes(List<JCExpression> trees, List<Type> types) {
List<JCExpression> tl = trees;
for (List<Type> l = types; l.nonEmpty(); l = l.tail) {
! l.head = checkRefType(tl.head.pos(), l.head, false);
tl = tl.tail;
}
return types;
}
return false;
} else
return true;
}
+ void checkParameterizationByPrimitiveClass(DiagnosticPosition pos, Type t) {
+ parameterizationByPrimitiveClassChecker.visit(t, pos);
+ }
+
+ /** parameterizationByPrimitiveClassChecker: A type visitor that descends down the given type looking for instances of primitive classes
+ * being used as type arguments and issues error against those usages.
+ */
+ private final Types.SimpleVisitor<Void, DiagnosticPosition> parameterizationByPrimitiveClassChecker =
+ new Types.SimpleVisitor<Void, DiagnosticPosition>() {
+
+ @Override
+ public Void visitType(Type t, DiagnosticPosition pos) {
+ return null;
+ }
+
+ @Override
+ public Void visitClassType(ClassType t, DiagnosticPosition pos) {
+ for (Type targ : t.allparams()) {
+ if (targ.isPrimitiveClass()) {
+ log.error(pos, Errors.GenericParameterizationWithPrimitiveClass(t));
+ }
+ visit(targ, pos);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitTypeVar(TypeVar t, DiagnosticPosition pos) {
+ return null;
+ }
+
+ @Override
+ public Void visitCapturedType(CapturedType t, DiagnosticPosition pos) {
+ return null;
+ }
+
+ @Override
+ public Void visitArrayType(ArrayType t, DiagnosticPosition pos) {
+ return visit(t.elemtype, pos);
+ }
+
+ @Override
+ public Void visitWildcardType(WildcardType t, DiagnosticPosition pos) {
+ return visit(t.type, pos);
+ }
+ };
+
+
+
/** Check that usage of diamond operator is correct (i.e. diamond should not
* be used with non-generic classes or in anonymous class creation expressions)
*/
Type checkDiamond(JCNewClass tree, Type t) {
if (!TreeInfo.isDiamond(tree) ||
log.error(pos, Errors.CantInferLocalVarType(name, Fragments.LocalCantInferVoid));
return types.createErrorType(t);
}
//upward project the initializer type
! return types.upward(t, types.captures(t));
}
Type checkMethod(final Type mtype,
final Symbol sym,
final Env<AttrContext> env,
log.error(pos, Errors.CantInferLocalVarType(name, Fragments.LocalCantInferVoid));
return types.createErrorType(t);
}
//upward project the initializer type
! Type varType = types.upward(t, types.captures(t));
+ if (varType.hasTag(CLASS)) {
+ checkParameterizationByPrimitiveClass(pos, varType);
+ }
+ return varType;
+ }
+
+ public void checkForSuspectClassLiteralComparison(
+ final JCBinary tree,
+ final Type leftType,
+ final Type rightType) {
+
+ if (lint.isEnabled(LintCategory.MIGRATION)) {
+ if (isInvocationOfGetClass(tree.lhs) && isClassOfSomeInterface(rightType) ||
+ isInvocationOfGetClass(tree.rhs) && isClassOfSomeInterface(leftType)) {
+ log.warning(LintCategory.MIGRATION, tree.pos(), Warnings.GetClassComparedWithInterface);
+ }
+ }
+ }
+ //where
+ private boolean isClassOfSomeInterface(Type someClass) {
+ if (someClass.tsym.flatName() == names.java_lang_Class) {
+ List<Type> arguments = someClass.getTypeArguments();
+ if (arguments.length() == 1) {
+ return arguments.head.isInterface();
+ }
+ }
+ return false;
+ }
+ //where
+ private boolean isInvocationOfGetClass(JCExpression tree) {
+ tree = TreeInfo.skipParens(tree);
+ if (tree.hasTag(APPLY)) {
+ JCMethodInvocation apply = (JCMethodInvocation)tree;
+ MethodSymbol msym = (MethodSymbol)TreeInfo.symbol(apply.meth);
+ return msym.name == names.getClass && msym.implementedIn(syms.objectType.tsym, types) != null;
+ }
+ return false;
}
Type checkMethod(final Type mtype,
final Symbol sym,
final Env<AttrContext> env,
mask = ReceiverParamFlags;
else if (sym.owner.kind != TYP)
mask = LocalVarFlags;
else if ((sym.owner.flags_field & INTERFACE) != 0)
mask = implicit = InterfaceVarFlags;
! else
mask = VarFlags;
break;
case MTH:
if (sym.name == names.init) {
if ((sym.owner.flags_field & ENUM) != 0) {
// enum constructors cannot be declared public or
mask = ReceiverParamFlags;
else if (sym.owner.kind != TYP)
mask = LocalVarFlags;
else if ((sym.owner.flags_field & INTERFACE) != 0)
mask = implicit = InterfaceVarFlags;
! else {
mask = VarFlags;
+ if (sym.owner.type.isValueClass() && (flags & STATIC) == 0) {
+ implicit |= FINAL;
+ }
+ }
break;
case MTH:
if (sym.name == names.init) {
if ((sym.owner.flags_field & ENUM) != 0) {
// enum constructors cannot be declared public or
}
} else {
mask = implicit = InterfaceMethodFlags;
}
} else if ((sym.owner.flags_field & RECORD) != 0) {
! mask = RecordMethodFlags;
} else {
! mask = MethodFlags;
}
if ((flags & STRICTFP) != 0) {
warnOnExplicitStrictfp(pos);
}
// Imply STRICTFP if owner has STRICTFP set.
}
} else {
mask = implicit = InterfaceMethodFlags;
}
} else if ((sym.owner.flags_field & RECORD) != 0) {
! mask = ((sym.owner.flags_field & VALUE_CLASS) != 0 && (flags & Flags.STATIC) == 0) ?
+ RecordMethodFlags & ~SYNCHRONIZED : RecordMethodFlags;
} else {
! // value objects do not have an associated monitor/lock
+ mask = ((sym.owner.flags_field & VALUE_CLASS) != 0 && (flags & Flags.STATIC) == 0) ?
+ MethodFlags & ~SYNCHRONIZED : MethodFlags;
}
if ((flags & STRICTFP) != 0) {
warnOnExplicitStrictfp(pos);
}
// Imply STRICTFP if owner has STRICTFP set.
(sym.isDirectlyOrIndirectlyLocal() && (flags & ANNOTATION) != 0)) {
boolean implicitlyStatic = !sym.isAnonymous() &&
((flags & RECORD) != 0 || (flags & ENUM) != 0 || (flags & INTERFACE) != 0);
boolean staticOrImplicitlyStatic = (flags & STATIC) != 0 || implicitlyStatic;
// local statics are allowed only if records are allowed too
! mask = staticOrImplicitlyStatic && allowRecords && (flags & ANNOTATION) == 0 ? StaticLocalFlags : LocalClassFlags;
implicit = implicitlyStatic ? STATIC : implicit;
} else if (sym.owner.kind == TYP) {
// statics in inner classes are allowed only if records are allowed too
mask = ((flags & STATIC) != 0) && allowRecords && (flags & ANNOTATION) == 0 ? ExtendedMemberStaticClassFlags : ExtendedMemberClassFlags;
if (sym.owner.owner.kind == PCK ||
(sym.isDirectlyOrIndirectlyLocal() && (flags & ANNOTATION) != 0)) {
boolean implicitlyStatic = !sym.isAnonymous() &&
((flags & RECORD) != 0 || (flags & ENUM) != 0 || (flags & INTERFACE) != 0);
boolean staticOrImplicitlyStatic = (flags & STATIC) != 0 || implicitlyStatic;
// local statics are allowed only if records are allowed too
! mask = staticOrImplicitlyStatic && allowRecords && (flags & ANNOTATION) == 0 ? ExtendedStaticLocalClassFlags : ExtendedLocalClassFlags;
implicit = implicitlyStatic ? STATIC : implicit;
} else if (sym.owner.kind == TYP) {
// statics in inner classes are allowed only if records are allowed too
mask = ((flags & STATIC) != 0) && allowRecords && (flags & ANNOTATION) == 0 ? ExtendedMemberStaticClassFlags : ExtendedMemberClassFlags;
if (sym.owner.owner.kind == PCK ||
}
// Interfaces are always ABSTRACT
if ((flags & INTERFACE) != 0) implicit |= ABSTRACT;
if ((flags & ENUM) != 0) {
! // enums can't be declared abstract, final, sealed or non-sealed
! mask &= ~(ABSTRACT | FINAL | SEALED | NON_SEALED);
implicit |= implicitEnumFinalFlag(tree);
}
if ((flags & RECORD) != 0) {
// records can't be declared abstract
mask &= ~ABSTRACT;
}
// Interfaces are always ABSTRACT
if ((flags & INTERFACE) != 0) implicit |= ABSTRACT;
if ((flags & ENUM) != 0) {
! // enums can't be declared abstract, final, sealed or non-sealed or primitive/value
! mask &= ~(ABSTRACT | FINAL | SEALED | NON_SEALED | PRIMITIVE_CLASS | VALUE_CLASS);
implicit |= implicitEnumFinalFlag(tree);
}
if ((flags & RECORD) != 0) {
// records can't be declared abstract
mask &= ~ABSTRACT;
if ((flags & STRICTFP) != 0) {
warnOnExplicitStrictfp(pos);
}
// Imply STRICTFP if owner has STRICTFP set.
implicit |= sym.owner.flags_field & STRICTFP;
+
+ // primitive classes are implicitly final value classes.
+ if ((flags & PRIMITIVE_CLASS) != 0)
+ implicit |= VALUE_CLASS | FINAL;
+
+ // concrete value classes are implicitly final
+ if ((flags & (ABSTRACT | INTERFACE | VALUE_CLASS)) == VALUE_CLASS)
+ implicit |= FINAL;
+
+ // TYPs can't be declared synchronized
+ mask &= ~SYNCHRONIZED;
break;
default:
throw new AssertionError();
}
long illegal = flags & ExtendedStandardFlags & ~mask;
STATIC | PRIVATE,
DEFAULT)
&&
checkDisjoint(pos, flags,
ABSTRACT | INTERFACE,
! FINAL | NATIVE | SYNCHRONIZED)
&&
checkDisjoint(pos, flags,
PUBLIC,
PRIVATE | PROTECTED)
&&
checkDisjoint(pos, flags,
PRIVATE,
PUBLIC | PROTECTED)
&&
! checkDisjoint(pos, flags,
FINAL,
VOLATILE)
&&
(sym.kind == TYP ||
checkDisjoint(pos, flags,
STATIC | PRIVATE,
DEFAULT)
&&
checkDisjoint(pos, flags,
ABSTRACT | INTERFACE,
! FINAL | NATIVE | SYNCHRONIZED | PRIMITIVE_CLASS)
+ &&
+ checkDisjoint(pos, flags,
+ IDENTITY_TYPE,
+ PRIMITIVE_CLASS | VALUE_CLASS)
&&
checkDisjoint(pos, flags,
PUBLIC,
PRIVATE | PROTECTED)
&&
checkDisjoint(pos, flags,
PRIVATE,
PUBLIC | PROTECTED)
&&
! checkDisjoint(pos, (flags | implicit), // complain against volatile & implcitly final entities too.
FINAL,
VOLATILE)
&&
(sym.kind == TYP ||
checkDisjoint(pos, flags,
}
}
public void visitSelectInternal(JCFieldAccess tree) {
if (tree.type.tsym.isStatic() &&
! tree.selected.type.isParameterized()) {
// The enclosing type is not a class, so we are
// looking at a static member type. However, the
// qualifying expression is parameterized.
log.error(tree.pos(), Errors.CantSelectStaticClassFromParamType);
} else {
// otherwise validate the rest of the expression
tree.selected.accept(this);
}
}
}
public void visitSelectInternal(JCFieldAccess tree) {
if (tree.type.tsym.isStatic() &&
! tree.selected.type.isParameterized() &&
+ (tree.name != names.ref || !tree.type.isReferenceProjection())) {
// The enclosing type is not a class, so we are
// looking at a static member type. However, the
// qualifying expression is parameterized.
+ // Tolerate the pseudo-select V.ref: V<T>.ref will be static if V<T> is and
+ // should not be confused as selecting a static member of a parameterized type.
log.error(tree.pos(), Errors.CantSelectStaticClassFromParamType);
} else {
// otherwise validate the rest of the expression
tree.selected.accept(this);
}
asFlagSet(other.flags() & AccessFlags)));
m.flags_field |= BAD_OVERRIDE;
return;
}
+ if (origin.isValueClass() && other.owner == syms.objectType.tsym && m.type.getParameterTypes().size() == 0) {
+ if (m.name == names.finalize) {
+ log.error(TreeInfo.diagnosticPositionFor(m, tree),
+ Errors.ValueClassMayNotOverride(m.name));
+ m.flags_field |= BAD_OVERRIDE;
+ return;
+ }
+ }
+
Type mt = types.memberType(origin.type, m);
Type ot = types.memberType(origin.type, other);
// Error if overriding result type is different
// (or, in the case of generics mode, not a subtype) of
// overridden result type. We have to rename any type parameters
log.error(pos,
Errors.DoesNotOverrideAbstract(c, undef1, undef1.location()));
}
}
+ // A primitive class cannot contain a field of its own type either or indirectly.
+ void checkNonCyclicMembership(JCClassDecl tree) {
+ Assert.check((tree.sym.flags_field & LOCKED) == 0);
+ try {
+ tree.sym.flags_field |= LOCKED;
+ for (List<? extends JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
+ if (l.head.hasTag(VARDEF)) {
+ JCVariableDecl field = (JCVariableDecl) l.head;
+ if (cyclePossible(field.sym)) {
+ checkNonCyclicMembership((ClassSymbol) field.type.tsym, field.pos());
+ }
+ }
+ }
+ } finally {
+ tree.sym.flags_field &= ~LOCKED;
+ }
+
+ }
+ // where
+ private void checkNonCyclicMembership(ClassSymbol c, DiagnosticPosition pos) {
+ if ((c.flags_field & LOCKED) != 0) {
+ log.error(pos, Errors.CyclicPrimitiveClassMembership(c));
+ return;
+ }
+ try {
+ c.flags_field |= LOCKED;
+ for (Symbol fld : c.members().getSymbols(s -> s.kind == VAR && cyclePossible((VarSymbol) s), NON_RECURSIVE)) {
+ checkNonCyclicMembership((ClassSymbol) fld.type.tsym, pos);
+ }
+ } finally {
+ c.flags_field &= ~LOCKED;
+ }
+ }
+ // where
+ private boolean cyclePossible(VarSymbol symbol) {
+ return (symbol.flags() & STATIC) == 0 && symbol.type.isPrimitiveClass();
+ }
+
void checkNonCyclicDecl(JCClassDecl tree) {
CycleChecker cc = new CycleChecker();
cc.scan(tree);
if (!cc.errorFound && !cc.partialCheck) {
tree.sym.flags_field |= ACYCLIC;
for (List<Type> m = supertypes; m != l; m = m.tail)
if (!checkCompatibleAbstracts(pos, l.head, m.head, c))
return;
}
checkCompatibleConcretes(pos, c);
+
+ boolean cIsValue = (c.tsym.flags() & VALUE_CLASS) != 0;
+ boolean cHasIdentity = (c.tsym.flags() & IDENTITY_TYPE) != 0;
+
+ if (cIsValue || cHasIdentity) {
+ List<Type> superTypes = types.closure(c);
+ for (Type superType : superTypes) {
+ if (cIsValue && (superType.tsym.flags() & IDENTITY_TYPE) != 0) {
+ log.error(pos, Errors.ValueTypeHasIdentitySuperType(c, superType));
+ } else if (cHasIdentity && (superType.tsym.flags() & VALUE_CLASS) != 0) {
+ log.error(pos, Errors.IdentityTypeHasValueSuperType(c, superType));
+ }
+ }
+ }
}
/** Check that all non-override equivalent methods accessible from 'site'
* are mutually compatible (JLS 8.4.8/9.4.1).
*
< prev index next >