< prev index next > src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
Print this page
deferredLintHandler = DeferredLintHandler.instance(context);
allowModules = Feature.MODULES.allowedInSource(source);
allowRecords = Feature.RECORDS.allowedInSource(source);
allowSealed = Feature.SEALED_CLASSES.allowedInSource(source);
+ allowPrimitiveClasses = Feature.PRIMITIVE_CLASSES.allowedInSource(source) && options.isSet("enablePrimitiveClasses");
}
/** Character for synthetic names
*/
char syntheticNameChar;
/** Are sealed classes allowed
*/
private final boolean allowSealed;
+ /** Are primitive classes allowed
+ */
+ private final boolean allowPrimitiveClasses;
+
/* *************************************************************************
* Errors and Warnings
**************************************************************************/
Lint setLint(Lint newLint) {
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 (allowPrimitiveClasses && 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 checkConstraintsOfValueClass(DiagnosticPosition pos, ClassSymbol c) {
+ for (Type st : types.closure(c.type)) {
+ if (st == null || st.tsym == null || st.tsym.kind == ERR)
+ continue;
+ if (st.tsym == syms.objectType.tsym || st.tsym == syms.recordType.tsym || st.isInterface())
+ continue;
+ if (!st.tsym.isAbstract()) {
+ if (c != st.tsym) {
+ log.error(pos, Errors.ConcreteSupertypeForValueClass(c, st));
+ }
+ continue;
+ }
+ // dealing with an abstract value or value super class below.
+ Fragment fragment = c.isAbstract() && c.isValueClass() && c == st.tsym ? Fragments.AbstractValueClass(c) : Fragments.SuperclassOfValueClass(c, st);
+ if ((st.tsym.flags() & HASINITBLOCK) != 0) {
+ log.error(pos, Errors.AbstractValueClassDeclaresInitBlock(fragment));
+ }
+ Type encl = st.getEnclosingType();
+ if (encl != null && encl.hasTag(CLASS)) {
+ log.error(pos, Errors.AbstractValueClassCannotBeInner(fragment));
+ }
+ for (Symbol s : st.tsym.members().getSymbols(NON_RECURSIVE)) {
+ switch (s.kind) {
+ case VAR:
+ if ((s.flags() & STATIC) == 0) {
+ log.error(pos, Errors.InstanceFieldNotAllowed(s, fragment));
+ }
+ break;
+ case MTH:
+ if ((s.flags() & (SYNCHRONIZED | STATIC)) == SYNCHRONIZED) {
+ log.error(pos, Errors.SuperClassMethodCannotBeSynchronized(s, c, st));
+ } else if (s.isInitOrVNew()) {
+ MethodSymbol m = (MethodSymbol)s;
+ if (m.getParameters().size() > 0) {
+ log.error(pos, Errors.AbstractValueClassConstructorCannotTakeArguments(m, fragment));
+ } else if (m.getTypeParameters().size() > 0) {
+ log.error(pos, Errors.AbstractValueClassConstructorCannotBeGeneric(m, fragment));
+ } else if (m.type.getThrownTypes().size() > 0) {
+ log.error(pos, Errors.AbstractValueClassConstructorCannotThrow(m, fragment));
+ } else if (protection(m.flags()) > protection(m.owner.flags())) {
+ log.error(pos, Errors.AbstractValueClassConstructorHasWeakerAccess(m, fragment));
+ } else if ((m.flags() & EMPTYNOARGCONSTR) == 0) {
+ log.error(pos, Errors.AbstractValueClassNoArgConstructorMustBeEmpty(m, fragment));
+ }
+ }
+ 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 (allowPrimitiveClasses && 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() && (!allowPrimitiveClasses || 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/value 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.
+ */
+ void checkIdentityType(DiagnosticPosition pos, Type t) {
+ if (t.hasTag(TYPEVAR)) {
+ t = types.skipTypeVars(t, false);
+ }
+ if (t.isIntersection()) {
+ IntersectionClassType ict = (IntersectionClassType)t;
+ for (Type component : ict.getExplicitComponents()) {
+ checkIdentityType(pos, component);
+ }
+ return;
+ }
+ if (t.isPrimitive() || t.isValueClass() || t.isValueInterface() || t.isReferenceProjection())
+ typeTagError(pos, diags.fragment(Fragments.TypeReqIdentity), 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 (allowPrimitiveClasses && 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) ||
}
}
//where
private boolean isTrustMeAllowedOnMethod(Symbol s) {
return (s.flags() & VARARGS) != 0 &&
! (s.isConstructor() ||
(s.flags() & (STATIC | FINAL |
(Feature.PRIVATE_SAFE_VARARGS.allowedInSource(source) ? PRIVATE : 0) )) != 0);
}
Type checkLocalVarType(DiagnosticPosition pos, Type t, Name name) {
}
}
//where
private boolean isTrustMeAllowedOnMethod(Symbol s) {
return (s.flags() & VARARGS) != 0 &&
! (s.isInitOrVNew() ||
(s.flags() & (STATIC | FINAL |
(Feature.PRIVATE_SAFE_VARARGS.allowedInSource(source) ? PRIVATE : 0) )) != 0);
}
Type checkLocalVarType(DiagnosticPosition pos, Type t, Name name) {
log.error(pos, Errors.CantInferLocalVarType(name, Fragments.LocalCantInferVoid));
return types.createErrorType(t);
}
//upward project the initializer type
! return types.upward(t, types.captures(t)).baseType();
}
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)).baseType();
+ if (allowPrimitiveClasses && varType.hasTag(CLASS)) {
+ checkParameterizationByPrimitiveClass(pos, varType);
+ }
+ return varType;
}
Type checkMethod(final Type mtype,
final Symbol sym,
final Env<AttrContext> env,
Type owntype = mtype;
List<Type> formals = owntype.getParameterTypes();
List<Type> nonInferred = sym.type.getParameterTypes();
if (nonInferred.length() != formals.length()) nonInferred = formals;
Type last = useVarargs ? formals.last() : null;
+ // TODO - is enum so <init>
if (sym.name == names.init && sym.owner == syms.enumSym) {
formals = formals.tail.tail;
nonInferred = nonInferred.tail.tail;
}
if ((sym.flags() & ANONCONSTR_BASED) != 0) {
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
// protected and must be implicitly or explicitly
// private
implicit = PRIVATE;
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 (names.isInitOrVNew(sym.name)) {
if ((sym.owner.flags_field & ENUM) != 0) {
// enum constructors cannot be declared public or
// protected and must be implicitly or explicitly
// private
implicit = PRIVATE;
}
} 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;
+ if ((flags & NON_SEALED) != 0) {
+ // cant declare a final value class non-sealed
+ log.error(pos,
+ Errors.ModNotAllowedHere(asFlagSet(NON_SEALED)));
+ }
+ }
+
+ // 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,
&& checkDisjoint(pos, flags,
SEALED,
FINAL | NON_SEALED)
&& checkDisjoint(pos, flags,
SEALED,
! ANNOTATION)) {
// skip
}
return flags & (mask | ~ExtendedStandardFlags) | implicit;
}
&& checkDisjoint(pos, flags,
SEALED,
FINAL | NON_SEALED)
&& checkDisjoint(pos, flags,
SEALED,
! ANNOTATION)
+ && checkDisjoint(pos, flags,
+ IDENTITY_TYPE,
+ ANNOTATION)
+ && checkDisjoint(pos, flags,
+ VALUE_CLASS,
+ ANNOTATION) ) {
// skip
}
return flags & (mask | ~ExtendedStandardFlags) | implicit;
}
}
}
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);
}
}
}
//where
private boolean withinAnonConstr(Env<AttrContext> env) {
return env.enclClass.name.isEmpty() &&
! env.enclMethod != null && env.enclMethod.name == names.init;
}
/* *************************************************************************
* Exception checking
**************************************************************************/
}
}
//where
private boolean withinAnonConstr(Env<AttrContext> env) {
return env.enclClass.name.isEmpty() &&
! env.enclMethod != null && names.isInitOrVNew(env.enclMethod.name);
}
/* *************************************************************************
* Exception checking
**************************************************************************/
final boolean explicitOverride = m.attribute(syms.overrideType.tsym) != null;
// Check if this method must override a super method due to being annotated with @Override
// or by virtue of being a member of a diamond inferred anonymous class. Latter case is to
// be treated "as if as they were annotated" with @Override.
boolean mustOverride = explicitOverride ||
! (env.info.isAnonymousDiamond && !m.isConstructor() && !m.isPrivate());
if (mustOverride && !isOverrider(m)) {
DiagnosticPosition pos = tree.pos();
for (JCAnnotation a : tree.getModifiers().annotations) {
if (a.annotationType.type.tsym == syms.overrideType.tsym) {
pos = a.pos();
final boolean explicitOverride = m.attribute(syms.overrideType.tsym) != null;
// Check if this method must override a super method due to being annotated with @Override
// or by virtue of being a member of a diamond inferred anonymous class. Latter case is to
// be treated "as if as they were annotated" with @Override.
boolean mustOverride = explicitOverride ||
! (env.info.isAnonymousDiamond && !m.isInitOrVNew() && !m.isPrivate());
if (mustOverride && !isOverrider(m)) {
DiagnosticPosition pos = tree.pos();
for (JCAnnotation a : tree.getModifiers().annotations) {
if (a.annotationType.type.tsym == syms.overrideType.tsym) {
pos = a.pos();
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) {
+ if (allowPrimitiveClasses) {
+ 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 && allowPrimitiveClasses && 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;
+ Type identitySuper = null, valueSuper = null;
+ for (Type t : types.closure(c)) {
+ if (t != c) {
+ if ((t.tsym.flags() & IDENTITY_TYPE) != 0)
+ identitySuper = t;
+ else if ((t.tsym.flags() & VALUE_CLASS) != 0)
+ valueSuper = t;
+ if (cIsValue && identitySuper != null) {
+ log.error(pos, Errors.ValueTypeHasIdentitySuperType(c, identitySuper));
+ break;
+ } else if (cHasIdentity && valueSuper != null) {
+ log.error(pos, Errors.IdentityTypeHasValueSuperType(c, valueSuper));
+ break;
+ } else if (identitySuper != null && valueSuper != null) {
+ log.error(pos, Errors.MutuallyIncompatibleSupers(c, identitySuper, valueSuper));
+ break;
+ }
+ }
+ }
}
/** Check that all non-override equivalent methods accessible from 'site'
* are mutually compatible (JLS 8.4.8/9.4.1).
*
public boolean test(Symbol s) {
return s.kind == MTH &&
(s.flags() & SYNTHETIC) == 0 &&
!shouldSkip(s) &&
s.isInheritedIn(site.tsym, types) &&
! !s.isConstructor();
}
}
void checkDefaultMethodClashes(DiagnosticPosition pos, Type site) {
DefaultMethodClashFilter dcf = new DefaultMethodClashFilter(site);
public boolean test(Symbol s) {
return s.kind == MTH &&
(s.flags() & SYNTHETIC) == 0 &&
!shouldSkip(s) &&
s.isInheritedIn(site.tsym, types) &&
! !s.isInitOrVNew();
}
}
void checkDefaultMethodClashes(DiagnosticPosition pos, Type site) {
DefaultMethodClashFilter dcf = new DefaultMethodClashFilter(site);
@Override
public boolean test(Symbol s) {
return s.kind == MTH &&
(s.flags() & DEFAULT) != 0 &&
s.isInheritedIn(site.tsym, types) &&
! !s.isConstructor();
}
}
/** Report warnings for potentially ambiguous method declarations in the given site. */
void checkPotentiallyAmbiguousOverloads(JCClassDecl tree, Type site) {
@Override
public boolean test(Symbol s) {
return s.kind == MTH &&
(s.flags() & DEFAULT) != 0 &&
s.isInheritedIn(site.tsym, types) &&
! !s.isInitOrVNew();
}
}
/** Report warnings for potentially ambiguous method declarations in the given site. */
void checkPotentiallyAmbiguousOverloads(JCClassDecl tree, Type site) {
} else if (target == names.RECORD_COMPONENT) {
if (s.getKind() == ElementKind.RECORD_COMPONENT) {
applicableTargets.add(names.RECORD_COMPONENT);
}
} else if (target == names.METHOD) {
! if (s.kind == MTH && !s.isConstructor())
applicableTargets.add(names.METHOD);
} else if (target == names.PARAMETER) {
if (s.kind == VAR &&
(s.owner.kind == MTH && (s.flags() & PARAMETER) != 0)) {
applicableTargets.add(names.PARAMETER);
}
} else if (target == names.CONSTRUCTOR) {
! if (s.kind == MTH && s.isConstructor())
applicableTargets.add(names.CONSTRUCTOR);
} else if (target == names.LOCAL_VARIABLE) {
if (s.kind == VAR && s.owner.kind == MTH &&
(s.flags() & PARAMETER) == 0) {
applicableTargets.add(names.LOCAL_VARIABLE);
} else if (target == names.RECORD_COMPONENT) {
if (s.getKind() == ElementKind.RECORD_COMPONENT) {
applicableTargets.add(names.RECORD_COMPONENT);
}
} else if (target == names.METHOD) {
! if (s.kind == MTH && !s.isInitOrVNew())
applicableTargets.add(names.METHOD);
} else if (target == names.PARAMETER) {
if (s.kind == VAR &&
(s.owner.kind == MTH && (s.flags() & PARAMETER) != 0)) {
applicableTargets.add(names.PARAMETER);
}
} else if (target == names.CONSTRUCTOR) {
! if (s.kind == MTH && s.isInitOrVNew())
applicableTargets.add(names.CONSTRUCTOR);
} else if (target == names.LOCAL_VARIABLE) {
if (s.kind == VAR && s.owner.kind == MTH &&
(s.flags() & PARAMETER) == 0) {
applicableTargets.add(names.LOCAL_VARIABLE);
} else if (target == names.TYPE_USE) {
if (s.kind == VAR && s.owner.kind == MTH && s.type.hasTag(NONE)) {
//cannot type annotate implicitly typed locals
continue;
} else if (s.kind == TYP || s.kind == VAR ||
! (s.kind == MTH && !s.isConstructor() &&
!s.type.getReturnType().hasTag(VOID)) ||
! (s.kind == MTH && s.isConstructor())) {
applicableTargets.add(names.TYPE_USE);
}
} else if (target == names.TYPE_PARAMETER) {
if (s.kind == TYP && s.type.hasTag(TYPEVAR))
applicableTargets.add(names.TYPE_PARAMETER);
} else if (target == names.TYPE_USE) {
if (s.kind == VAR && s.owner.kind == MTH && s.type.hasTag(NONE)) {
//cannot type annotate implicitly typed locals
continue;
} else if (s.kind == TYP || s.kind == VAR ||
! (s.kind == MTH && !s.isInitOrVNew() &&
!s.type.getReturnType().hasTag(VOID)) ||
! (s.kind == MTH && s.isInitOrVNew())) {
applicableTargets.add(names.TYPE_USE);
}
} else if (target == names.TYPE_PARAMETER) {
if (s.kind == TYP && s.type.hasTag(TYPEVAR))
applicableTargets.add(names.TYPE_PARAMETER);
* constructor of its first nonserializable superclass.
*/
private void checkCtorAccess(JCClassDecl tree, ClassSymbol c) {
if (isExternalizable(c.type)) {
for(var sym : c.getEnclosedElements()) {
! if (sym.isConstructor() &&
((sym.flags() & PUBLIC) == PUBLIC)) {
if (((MethodSymbol)sym).getParameters().isEmpty()) {
return;
}
}
* constructor of its first nonserializable superclass.
*/
private void checkCtorAccess(JCClassDecl tree, ClassSymbol c) {
if (isExternalizable(c.type)) {
for(var sym : c.getEnclosedElements()) {
! if (sym.isInitOrVNew() &&
((sym.flags() & PUBLIC) == PUBLIC)) {
if (((MethodSymbol)sym).getParameters().isEmpty()) {
return;
}
}
}
// Non-Serializable superclass
try {
ClassSymbol supertype = ((ClassSymbol)(((DeclaredType)superClass).asElement()));
for(var sym : supertype.getEnclosedElements()) {
! if (sym.isConstructor()) {
MethodSymbol ctor = (MethodSymbol)sym;
if (ctor.getParameters().isEmpty()) {
if (((ctor.flags() & PRIVATE) == PRIVATE) ||
// Handle nested classes and implicit this$0
(supertype.getNestingKind() == NestingKind.MEMBER &&
}
// Non-Serializable superclass
try {
ClassSymbol supertype = ((ClassSymbol)(((DeclaredType)superClass).asElement()));
for(var sym : supertype.getEnclosedElements()) {
! if (sym.isInitOrVNew()) {
MethodSymbol ctor = (MethodSymbol)sym;
if (ctor.getParameters().isEmpty()) {
if (((ctor.flags() & PRIVATE) == PRIVATE) ||
// Handle nested classes and implicit this$0
(supertype.getNestingKind() == NestingKind.MEMBER &&
< prev index next >