< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java

Print this page

        

*** 92,101 **** --- 92,103 ---- private final JavaFileManager fileManager; private final Source source; private final Target target; private final Profile profile; private final boolean warnOnAnyAccessToMembers; + private final boolean allowGenericsOverValues; + private final boolean allowValueBasedClasses; // The set of lint options currently in effect. It is initialized // from the context, and then is set/reset as needed by Attr as it // visits all the various parts of the trees during attribution. private Lint lint;
*** 132,142 **** 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); --- 134,145 ---- fileManager = context.get(JavaFileManager.class); source = Source.instance(context); target = Target.instance(context); warnOnAnyAccessToMembers = options.isSet("warnOnAccessToMembers"); ! allowGenericsOverValues = options.isSet("allowGenericsOverValues"); ! allowValueBasedClasses = options.isSet("allowValueBasedClasses"); Target target = Target.instance(context); syntheticNameChar = target.syntheticNameChar(); profile = Profile.instance(context);
*** 448,458 **** 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 --- 451,461 ---- 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
*** 554,569 **** --- 557,579 ---- 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)) { + checkParameterizationWithValues(pos, found); + } } if (req.hasTag(ERROR)) return req; if (req.hasTag(NONE)) return found; if (checkContext.compatible(found, req, checkContext.checkWarner(pos, found, req))) { + if (found.hasTag(BOT) && types.isValueBased(req)) { + log.warning(pos, Warnings.SuspiciousMixOfNullWithValueBasedClass(req)); + } return found; } else { if (found.isNumeric() && req.isNumeric()) { checkContext.report(pos, diags.fragment(Fragments.PossibleLossOfPrecision(found, req))); return types.createErrorType(found);
*** 582,591 **** --- 592,608 ---- Type checkCastable(DiagnosticPosition pos, Type found, Type req) { return checkCastable(pos, found, req, basicHandler); } Type checkCastable(DiagnosticPosition pos, Type found, Type req, CheckContext checkContext) { if (types.isCastable(found, req, castWarner(pos, found, req))) { + if (types.isValueBased(req)) { + if (found.hasTag(BOT)) { + log.warning(pos, Warnings.SuspiciousMixOfNullWithValueBasedClass(req)); + } else if (!types.isValueBased(found)) { + log.warning(pos, Warnings.PotentialNullPollution(found)); + } + } return req; } else { checkContext.report(pos, diags.fragment(Fragments.InconvertibleTypes(found, req))); return types.createErrorType(found); }
*** 731,759 **** /** 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; } --- 748,786 ---- /** 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 valueOK If false, a value class does not qualify */ ! Type checkRefType(DiagnosticPosition pos, Type t, boolean valueOK) { ! if (t.isReference() && (valueOK || !types.isValue(t))) return t; else return typeTagError(pos, diags.fragment(Fragments.TypeReqRef), 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, allowGenericsOverValues); tl = tl.tail; } return types; }
*** 785,794 **** --- 812,871 ---- return false; } else return true; } + void checkParameterizationWithValues(DiagnosticPosition pos, Type t) { + if (!allowGenericsOverValues && t.tsym != syms.classType.tsym) { // tolerate Value.class for now. + valueParameterizationChecker.visit(t, pos); + } + } + + /** valueParameterizationChecker: A type visitor that descends down the given type looking for instances of value types + * being used as type arguments and issues error against those usages. + */ + private final Types.SimpleVisitor<Void, DiagnosticPosition> valueParameterizationChecker = 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 (types.isValue(targ) && !allowGenericsOverValues) { + log.error(pos, Errors.GenericParameterizationWithValueType(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) ||
*** 933,943 **** 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, --- 1010,1024 ---- 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)) { ! checkParameterizationWithValues(pos, varType); ! } ! return varType; } Type checkMethod(final Type mtype, final Symbol sym, final Env<AttrContext> env,
*** 1131,1142 **** 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 --- 1212,1227 ---- 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 (types.isValue(sym.owner.type) && (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
*** 1158,1168 **** } } else { mask = implicit = InterfaceMethodFlags; } } else { ! mask = MethodFlags; } // Imply STRICTFP if owner has STRICTFP set. if (((flags|implicit) & Flags.ABSTRACT) == 0 || ((flags) & Flags.DEFAULT) != 0) implicit |= sym.owner.flags_field & STRICTFP; --- 1243,1255 ---- } } else { mask = implicit = InterfaceMethodFlags; } } else { ! // instance methods of value types do not have a monitor associated with their `this' ! mask = ((sym.owner.flags_field & VALUE) != 0 && (flags & Flags.STATIC) == 0) ? ! MethodFlags & ~SYNCHRONIZED : MethodFlags; } // Imply STRICTFP if owner has STRICTFP set. if (((flags|implicit) & Flags.ABSTRACT) == 0 || ((flags) & Flags.DEFAULT) != 0) implicit |= sym.owner.flags_field & STRICTFP;
*** 1187,1198 **** } // Interfaces are always ABSTRACT if ((flags & INTERFACE) != 0) implicit |= ABSTRACT; if ((flags & ENUM) != 0) { ! // enums can't be declared abstract or final ! mask &= ~(ABSTRACT | FINAL); implicit |= implicitEnumFinalFlag(tree); } // Imply STRICTFP if owner has STRICTFP set. implicit |= sym.owner.flags_field & STRICTFP; break; --- 1274,1285 ---- } // Interfaces are always ABSTRACT if ((flags & INTERFACE) != 0) implicit |= ABSTRACT; if ((flags & ENUM) != 0) { ! // enums can't be declared abstract or final or value type ! mask &= ~(ABSTRACT | FINAL | VALUE); implicit |= implicitEnumFinalFlag(tree); } // Imply STRICTFP if owner has STRICTFP set. implicit |= sym.owner.flags_field & STRICTFP; break;
*** 1221,1231 **** STATIC | PRIVATE, DEFAULT) && checkDisjoint(pos, flags, ABSTRACT | INTERFACE, ! FINAL | NATIVE | SYNCHRONIZED) && checkDisjoint(pos, flags, PUBLIC, PRIVATE | PROTECTED) && --- 1308,1318 ---- STATIC | PRIVATE, DEFAULT) && checkDisjoint(pos, flags, ABSTRACT | INTERFACE, ! FINAL | NATIVE | SYNCHRONIZED | VALUE) && checkDisjoint(pos, flags, PUBLIC, PRIVATE | PROTECTED) &&
*** 2031,2041 **** 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(); --- 2118,2129 ---- 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() && ! (!m.owner.isValue() || (tree.body.flags & SYNTHETIC) == 0)); 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();
*** 2155,2164 **** --- 2243,2291 ---- log.error(pos, Errors.DoesNotOverrideAbstract(c, undef1, undef1.location())); } } + // A value 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)) { + Type fieldType = field.sym.type; + checkNonCyclicMembership((ClassSymbol) fieldType.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.CyclicValueTypeMembership(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 && types.isValue(symbol.type); + } + void checkNonCyclicDecl(JCClassDecl tree) { CycleChecker cc = new CycleChecker(); cc.scan(tree); if (!cc.errorFound && !cc.partialCheck) { tree.sym.flags_field |= ACYCLIC;
*** 2838,2847 **** --- 2965,2981 ---- log.error(a.pos(), Errors.BadFunctionalIntfAnno); } else if (!s.isInterface() || (s.flags() & ANNOTATION) != 0) { log.error(a.pos(), Errors.BadFunctionalIntfAnno1(Fragments.NotAFunctionalIntf(s))); } } + if (a.annotationType.type.tsym == syms.valueBasedType.tsym) { + if (s.isInterface() || s.isEnum()) { + log.error(a.pos(), Errors.BadValueBasedAnno); + } else if (allowValueBasedClasses) { + s.flags_field |= VALUEBASED; + } + } } public void validateTypeAnnotation(JCAnnotation a, boolean isTypeParameter) { Assert.checkNonNull(a.type); validateAnnotationTree(a);
< prev index next >