--- a/langtools/src/share/classes/com/sun/tools/javac/code/Flags.java Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Flags.java Mon Apr 09 21:58:05 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -221,7 +221,7 @@
/** Flag that marks a hypothetical method that need not really be
* generated in the binary, but is present in the symbol table to
- * simplify checking for erasure clashes.
+ * simplify checking for erasure clashes - also used for 292 poly sig methods.
*/
public static final long HYPOTHETICAL = 1L<<37;
@@ -236,26 +236,20 @@
public static final long UNION = 1L<<39;
/**
- * Flag that marks a signature-polymorphic invoke method.
- * (These occur inside java.lang.invoke.MethodHandle.)
- */
- public static final long POLYMORPHIC_SIGNATURE = 1L<<40;
-
- /**
* Flag that marks a special kind of bridge methods (the ones that
* come from restricted supertype bounds)
*/
- public static final long OVERRIDE_BRIDGE = 1L<<41;
+ public static final long OVERRIDE_BRIDGE = 1L<<40;
/**
* Flag that marks an 'effectively final' local variable
*/
- public static final long EFFECTIVELY_FINAL = 1L<<42;
+ public static final long EFFECTIVELY_FINAL = 1L<<41;
/**
* Flag that marks non-override equivalent methods with the same signature
*/
- public static final long CLASH = 1L<<43;
+ public static final long CLASH = 1L<<42;
/** Modifier masks.
*/
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Mon Apr 09 21:58:05 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -202,16 +202,6 @@
return (flags() & INTERFACE) != 0;
}
- /** Recognize if this symbol was marked @PolymorphicSignature in the source. */
- public boolean isPolymorphicSignatureGeneric() {
- return (flags() & (POLYMORPHIC_SIGNATURE | HYPOTHETICAL)) == POLYMORPHIC_SIGNATURE;
- }
-
- /** Recognize if this symbol was split from a @PolymorphicSignature symbol in the source. */
- public boolean isPolymorphicSignatureInstance() {
- return (flags() & (POLYMORPHIC_SIGNATURE | HYPOTHETICAL)) == (POLYMORPHIC_SIGNATURE | HYPOTHETICAL);
- }
-
/** Is this symbol declared (directly or indirectly) local
* to a method or variable initializer?
* Also includes fields of inner classes which are in
@@ -1316,6 +1306,25 @@
getKind() == ElementKind.INSTANCE_INIT;
}
+ /**
+ * A polymorphic signature method (JLS SE 7, 8.4.1) is a method that
+ * (i) is declared in the java.lang.invoke.MethodHandle class, (ii) takes
+ * a single variable arity parameter (iii) whose declared type is Object[],
+ * (iv) has a return type of Object and (v) is native.
+ */
+ public boolean isSignaturePolymorphic(Types types) {
+ List<Type> argtypes = type.getParameterTypes();
+ Type firstElemType = argtypes.nonEmpty() ?
+ types.elemtype(argtypes.head) :
+ null;
+ return owner == types.syms.methodHandleType.tsym &&
+ argtypes.length() == 1 &&
+ firstElemType != null &&
+ types.isSameType(firstElemType, types.syms.objectType) &&
+ types.isSameType(type.getReturnType(), types.syms.objectType) &&
+ (flags() & NATIVE) != 0;
+ }
+
public Attribute getDefaultValue() {
return defaultValue;
}
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java Mon Apr 09 21:58:05 2012 -0700
@@ -127,7 +127,6 @@
public final Type serializableType;
public final Type methodHandleType;
public final Type nativeHeaderType;
- public final Type polymorphicSignatureType;
public final Type throwableType;
public final Type errorType;
public final Type interruptedExceptionType;
@@ -436,7 +435,6 @@
throwableType = enterClass("java.lang.Throwable");
serializableType = enterClass("java.io.Serializable");
methodHandleType = enterClass("java.lang.invoke.MethodHandle");
- polymorphicSignatureType = enterClass("java.lang.invoke.MethodHandle$PolymorphicSignature");
errorType = enterClass("java.lang.Error");
illegalArgumentExceptionType = enterClass("java.lang.IllegalArgumentException");
interruptedExceptionType = enterClass("java.lang.InterruptedException");
@@ -483,7 +481,6 @@
synthesizeEmptyInterfaceIfMissing(autoCloseableType);
synthesizeEmptyInterfaceIfMissing(cloneableType);
synthesizeEmptyInterfaceIfMissing(serializableType);
- synthesizeEmptyInterfaceIfMissing(polymorphicSignatureType);
synthesizeBoxTypeIfMissing(doubleType);
synthesizeBoxTypeIfMissing(floatType);
synthesizeBoxTypeIfMissing(voidType);
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Mon Apr 09 21:58:05 2012 -0700
@@ -42,6 +42,7 @@
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.code.Type.*;
+import com.sun.tools.javac.comp.Check.CheckContext;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.MemberSelectTree;
@@ -132,6 +133,11 @@
findDiamonds = options.get("findDiamond") != null &&
source.allowDiamond();
useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
+
+ statInfo = new ResultInfo(NIL, Type.noType);
+ varInfo = new ResultInfo(VAR, Type.noType);
+ unknownExprInfo = new ResultInfo(VAL, Type.noType);
+ unknownTypeInfo = new ResultInfo(TYP, Type.noType);
}
/** Switch: relax some constraints for retrofit mode.
@@ -204,7 +210,7 @@
Type check(JCTree tree, Type owntype, int ownkind, ResultInfo resultInfo) {
if (owntype.tag != ERROR && resultInfo.pt.tag != METHOD && resultInfo.pt.tag != FORALL) {
if ((ownkind & ~resultInfo.pkind) == 0) {
- owntype = chk.checkType(tree.pos(), owntype, resultInfo.pt, errKey);
+ owntype = resultInfo.check(tree, owntype);
} else {
log.error(tree.pos(), "unexpected.type",
kindNames(resultInfo.pkind),
@@ -394,20 +400,30 @@
}
}
- static class ResultInfo {
+ class ResultInfo {
int pkind;
Type pt;
+ CheckContext checkContext;
ResultInfo(int pkind, Type pt) {
+ this(pkind, pt, chk.basicHandler);
+ }
+
+ protected ResultInfo(int pkind, Type pt, CheckContext checkContext) {
this.pkind = pkind;
this.pt = pt;
+ this.checkContext = checkContext;
+ }
+
+ protected Type check(DiagnosticPosition pos, Type found) {
+ return chk.checkType(pos, found, pt, checkContext);
}
}
- private final ResultInfo statInfo = new ResultInfo(NIL, Type.noType);
- private final ResultInfo varInfo = new ResultInfo(VAR, Type.noType);
- private final ResultInfo unknownExprInfo = new ResultInfo(VAL, Type.noType);
- private final ResultInfo unknownTypeInfo = new ResultInfo(TYP, Type.noType);
+ private final ResultInfo statInfo;
+ private final ResultInfo varInfo;
+ private final ResultInfo unknownExprInfo;
+ private final ResultInfo unknownTypeInfo;
Type pt() {
return resultInfo.pt;
@@ -429,10 +445,6 @@
*/
ResultInfo resultInfo;
- /** Visitor argument: the error key to be generated when a type error occurs
- */
- String errKey;
-
/** Visitor result: the computed type.
*/
Type result;
@@ -445,17 +457,11 @@
* @param resultInfo The result info visitor argument.
*/
private Type attribTree(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
- return attribTree(tree, env, resultInfo, "incompatible.types");
- }
-
- private Type attribTree(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo, String errKey) {
Env<AttrContext> prevEnv = this.env;
ResultInfo prevResult = this.resultInfo;
- String prevErrKey = this.errKey;
try {
this.env = env;
this.resultInfo = resultInfo;
- this.errKey = errKey;
tree.accept(this);
if (tree == breakTree)
throw new BreakAttr(env);
@@ -466,18 +472,13 @@
} finally {
this.env = prevEnv;
this.resultInfo = prevResult;
- this.errKey = prevErrKey;
}
}
/** Derived visitor method: attribute an expression tree.
*/
public Type attribExpr(JCTree tree, Env<AttrContext> env, Type pt) {
- return attribExpr(tree, env, pt, "incompatible.types");
- }
-
- public Type attribExpr(JCTree tree, Env<AttrContext> env, Type pt, String key) {
- return attribTree(tree, env, new ResultInfo(VAL, pt.tag != ERROR ? pt : Type.noType), key);
+ return attribTree(tree, env, new ResultInfo(VAL, pt.tag != ERROR ? pt : Type.noType));
}
/** Derived visitor method: attribute an expression tree with
@@ -1121,9 +1122,16 @@
localEnv;
// Attribute resource declarations
for (JCTree resource : tree.resources) {
+ CheckContext twrContext = new Check.NestedCheckContext(resultInfo.checkContext) {
+ @Override
+ public void report(DiagnosticPosition pos, Type found, Type req, JCDiagnostic details) {
+ chk.basicHandler.report(pos, found, req, diags.fragment("try.not.applicable.to.type", found));
+ }
+ };
+ ResultInfo twrResult = new ResultInfo(VAL, syms.autoCloseableType, twrContext);
if (resource.hasTag(VARDEF)) {
attribStat(resource, tryEnv);
- chk.checkType(resource, resource.type, syms.autoCloseableType, "try.not.applicable.to.type");
+ twrResult.check(resource, resource.type);
//check that resource type cannot throw InterruptedException
checkAutoCloseable(resource.pos(), localEnv, resource.type);
@@ -1131,7 +1139,7 @@
VarSymbol var = (VarSymbol)TreeInfo.symbolFor(resource);
var.setData(ElementKind.RESOURCE_VARIABLE);
} else {
- attribExpr(resource, tryEnv, syms.autoCloseableType, "try.not.applicable.to.type");
+ attribTree(resource, tryEnv, twrResult);
}
}
// Attribute body
@@ -1846,7 +1854,7 @@
}
Type attribDiamond(Env<AttrContext> env,
- JCNewClass tree,
+ final JCNewClass tree,
Type clazztype,
List<Type> argtypes,
List<Type> typeargtypes) {
@@ -1886,25 +1894,17 @@
clazztype = syms.errType;
}
- if (clazztype.tag == FORALL && !pt().isErroneous()) {
- //if the resolved constructor's return type has some uninferred
- //type-variables, infer them using the expected type and declared
- //bounds (JLS 15.12.2.8).
+ if (clazztype.tag == FORALL && !resultInfo.pt.isErroneous()) {
try {
- clazztype = infer.instantiateExpr((ForAll) clazztype,
- pt().tag == NONE ? syms.objectType : pt(),
- Warner.noWarnings);
+ clazztype = resultInfo.checkContext.rawInstantiatePoly((ForAll)clazztype, pt(), Warner.noWarnings);
} catch (Infer.InferenceException ex) {
//an error occurred while inferring uninstantiated type-variables
- log.error(tree.clazz.pos(),
- "cant.apply.diamond.1",
- diags.fragment("diamond", clazztype.tsym),
- ex.diagnostic);
+ resultInfo.checkContext.report(tree.clazz.pos(), clazztype, resultInfo.pt,
+ diags.fragment("cant.apply.diamond.1", diags.fragment("diamond", clazztype.tsym), ex.diagnostic));
}
}
- return chk.checkClassType(tree.clazz.pos(),
- clazztype,
- true);
+
+ return chk.checkClassType(tree.clazz.pos(), clazztype, true);
}
/** Make an attributed null check tree.
@@ -2106,6 +2106,7 @@
if (exprtype.constValue() != null)
owntype = cfolder.coerce(exprtype, owntype);
result = check(tree, capture(owntype), VAL, resultInfo);
+ chk.checkRedundantCast(localEnv, tree);
}
public void visitTypeTest(JCInstanceOf tree) {
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java Mon Apr 09 21:58:05 2012 -0700
@@ -269,23 +269,6 @@
else return syms.errType;
}
- /** Report a type error.
- * @param pos Position to be used for error reporting.
- * @param problem A string describing the error.
- * @param found The type that was found.
- * @param req The type that was required.
- */
- Type typeError(DiagnosticPosition pos, Object problem, Type found, Type req) {
- log.error(pos, "prob.found.req",
- problem, found, req);
- return types.createErrorType(found);
- }
-
- Type typeError(DiagnosticPosition pos, String problem, Type found, Type req, Object explanation) {
- log.error(pos, "prob.found.req.1", problem, found, req, explanation);
- return types.createErrorType(found);
- }
-
/** Report an error that wrong type tag was found.
* @param pos Position to be used for error reporting.
* @param required An internationalized string describing the type tag
@@ -430,6 +413,86 @@
* Type Checking
**************************************************************************/
+ /**
+ * A check context is an object that can be used to perform compatibility
+ * checks - depending on the check context, meaning of 'compatibility' might
+ * vary significantly.
+ */
+ interface CheckContext {
+ /**
+ * Is type 'found' compatible with type 'req' in given context
+ */
+ boolean compatible(Type found, Type req, Warner warn);
+ /**
+ * Instantiate a ForAll type against a given target type 'req' in given context
+ */
+ Type rawInstantiatePoly(ForAll found, Type req, Warner warn);
+ /**
+ * Report a check error
+ */
+ void report(DiagnosticPosition pos, Type found, Type req, JCDiagnostic details);
+ /**
+ * Obtain a warner for this check context
+ */
+ public Warner checkWarner(DiagnosticPosition pos, Type found, Type req);
+ }
+
+ /**
+ * This class represent a check context that is nested within another check
+ * context - useful to check sub-expressions. The default behavior simply
+ * redirects all method calls to the enclosing check context leveraging
+ * the forwarding pattern.
+ */
+ static class NestedCheckContext implements CheckContext {
+ CheckContext enclosingContext;
+
+ NestedCheckContext(CheckContext enclosingContext) {
+ this.enclosingContext = enclosingContext;
+ }
+
+ public boolean compatible(Type found, Type req, Warner warn) {
+ return enclosingContext.compatible(found, req, warn);
+ }
+
+ public Type rawInstantiatePoly(ForAll found, Type req, Warner warn) {
+ return enclosingContext.rawInstantiatePoly(found, req, warn);
+ }
+
+ public void report(DiagnosticPosition pos, Type found, Type req, JCDiagnostic details) {
+ enclosingContext.report(pos, found, req, details);
+ }
+
+ public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) {
+ return enclosingContext.checkWarner(pos, found, req);
+ }
+ }
+
+ /**
+ * Check context to be used when evaluating assignment/return statements
+ */
+ CheckContext basicHandler = new CheckContext() {
+ public void report(DiagnosticPosition pos, Type found, Type req, JCDiagnostic details) {
+ if (details == null) {
+ log.error(pos, "prob.found.req", found, req);
+ } else {
+ log.error(pos, "prob.found.req.1", details);
+ }
+ }
+ public boolean compatible(Type found, Type req, Warner warn) {
+ return types.isAssignable(found, req, warn);
+ }
+
+ public Type rawInstantiatePoly(ForAll found, Type req, Warner warn) {
+ if (req.tag == NONE)
+ req = found.qtype.tag <= VOID ? found.qtype : syms.objectType;
+ return infer.instantiateExpr(found, req, warn);
+ }
+
+ public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) {
+ return convertWarner(pos, found, req);
+ }
+ };
+
/** Check that a given type is assignable to a given proto-type.
* If it is, return the type, otherwise return errType.
* @param pos Position to be used for error reporting.
@@ -437,64 +500,54 @@
* @param req The type that was required.
*/
Type checkType(DiagnosticPosition pos, Type found, Type req) {
- return checkType(pos, found, req, "incompatible.types");
+ return checkType(pos, found, req, basicHandler);
}
- Type checkType(DiagnosticPosition pos, Type found, Type req, String errKey) {
+ Type checkType(final DiagnosticPosition pos, Type found, Type req, CheckContext checkContext) {
if (req.tag == ERROR)
return req;
- if (found.tag == FORALL)
- return instantiatePoly(pos, (ForAll)found, req, convertWarner(pos, found, req));
+ if (found.tag == FORALL) {
+ ForAll fa = (ForAll)found;
+ Type owntype = instantiatePoly(pos, checkContext, fa, req, checkContext.checkWarner(pos, found, req));
+ return checkType(pos, owntype, req, checkContext);
+ }
if (req.tag == NONE)
return found;
- if (types.isAssignable(found, req, convertWarner(pos, found, req)))
+ if (checkContext.compatible(found, req, checkContext.checkWarner(pos, found, req))) {
return found;
- if (found.tag <= DOUBLE && req.tag <= DOUBLE)
- return typeError(pos, diags.fragment("possible.loss.of.precision"), found, req);
- if (found.isSuperBound()) {
- log.error(pos, "assignment.from.super-bound", found);
+ } else {
+ if (found.tag <= DOUBLE && req.tag <= DOUBLE) {
+ checkContext.report(pos, found, req, diags.fragment("possible.loss.of.precision"));
+ return types.createErrorType(found);
+ }
+ checkContext.report(pos, found, req, null);
return types.createErrorType(found);
}
- if (req.isExtendsBound()) {
- log.error(pos, "assignment.to.extends-bound", req);
- return types.createErrorType(found);
- }
- return typeError(pos, diags.fragment(errKey), found, req);
}
/** Instantiate polymorphic type to some prototype, unless
* prototype is `anyPoly' in which case polymorphic type
* is returned unchanged.
*/
- Type instantiatePoly(DiagnosticPosition pos, ForAll t, Type pt, Warner warn) throws Infer.NoInstanceException {
- if (pt == Infer.anyPoly && complexInference) {
- return t;
- } else if (pt == Infer.anyPoly || pt.tag == NONE) {
- Type newpt = t.qtype.tag <= VOID ? t.qtype : syms.objectType;
- return instantiatePoly(pos, t, newpt, warn);
- } else if (pt.tag == ERROR) {
- return pt;
- } else {
- try {
- return infer.instantiateExpr(t, pt, warn);
- } catch (Infer.NoInstanceException ex) {
+ Type instantiatePoly(DiagnosticPosition pos, CheckContext checkContext, ForAll t, Type pt, Warner warn) throws Infer.NoInstanceException {
+ try {
+ return checkContext.rawInstantiatePoly(t, pt, warn);
+ } catch (final Infer.NoInstanceException ex) {
+ JCDiagnostic d = ex.getDiagnostic();
+ if (d != null) {
if (ex.isAmbiguous) {
- JCDiagnostic d = ex.getDiagnostic();
- log.error(pos,
- "undetermined.type" + (d!=null ? ".1" : ""),
- t, d);
- return types.createErrorType(pt);
- } else {
- JCDiagnostic d = ex.getDiagnostic();
- return typeError(pos,
- diags.fragment("incompatible.types" + (d!=null ? ".1" : ""), d),
- t, pt);
+ d = diags.fragment("undetermined.type", t, d);
}
- } catch (Infer.InvalidInstanceException ex) {
- JCDiagnostic d = ex.getDiagnostic();
- log.error(pos, "invalid.inferred.types", t.tvars, d);
- return types.createErrorType(pt);
}
+ checkContext.report(pos, t, pt, d);
+ return types.createErrorType(pt);
+ } catch (Infer.InvalidInstanceException ex) {
+ JCDiagnostic d = ex.getDiagnostic();
+ if (d != null) {
+ d = diags.fragment("invalid.inferred.types", t.tvars, d);
+ }
+ checkContext.report(pos, t, pt, d);
+ return types.createErrorType(pt);
}
}
@@ -505,17 +558,48 @@
* @param req The target type of the cast.
*/
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 (found.tag == FORALL) {
- instantiatePoly(pos, (ForAll) found, req, castWarner(pos, found, req));
+ instantiatePoly(pos, basicHandler, (ForAll) found, req, castWarner(pos, found, req));
return req;
} else if (types.isCastable(found, req, castWarner(pos, found, req))) {
return req;
} else {
- return typeError(pos,
- diags.fragment("inconvertible.types"),
- found, req);
+ checkContext.report(pos, found, req, diags.fragment("inconvertible.types", found, req));
+ return types.createErrorType(found);
+ }
+ }
+
+ /** Check for redundant casts (i.e. where source type is a subtype of target type)
+ * The problem should only be reported for non-292 cast
+ */
+ public void checkRedundantCast(Env<AttrContext> env, JCTypeCast tree) {
+ if (!tree.type.isErroneous() &&
+ (env.info.lint == null || env.info.lint.isEnabled(Lint.LintCategory.CAST))
+ && types.isSameType(tree.expr.type, tree.clazz.type)
+ && !is292targetTypeCast(tree)) {
+ log.warning(Lint.LintCategory.CAST,
+ tree.pos(), "redundant.cast", tree.expr.type);
}
}
+ //where
+ private boolean is292targetTypeCast(JCTypeCast tree) {
+ boolean is292targetTypeCast = false;
+ JCExpression expr = TreeInfo.skipParens(tree.expr);
+ if (expr.hasTag(APPLY)) {
+ JCMethodInvocation apply = (JCMethodInvocation)expr;
+ Symbol sym = TreeInfo.symbol(apply.meth);
+ is292targetTypeCast = sym != null &&
+ sym.kind == MTH &&
+ (sym.flags() & HYPOTHETICAL) != 0;
+ }
+ return is292targetTypeCast;
+ }
+
+
+
//where
/** Is type a type variable, or a (possibly multi-dimensional) array of
* type variables?
@@ -838,14 +922,6 @@
&& types.isSubtype(actual, types.supertype(formal))
&& types.isSubtypeUnchecked(actual, types.interfaces(formal), warn))
return;
-
- if (false) {
- // TODO: make assertConvertible work
- typeError(tree.pos(), diags.fragment("incompatible.types"), actual, formal);
- throw new AssertionError("Tree: " + tree
- + " actual:" + actual
- + " formal: " + formal);
- }
}
/**
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java Mon Apr 09 21:58:05 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,8 +28,6 @@
package com.sun.tools.javac.comp;
import java.util.HashMap;
-import java.util.Map;
-import java.util.LinkedHashMap;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.tree.*;
@@ -179,7 +177,7 @@
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
-public class Flow extends TreeScanner {
+public class Flow {
protected static final Context.Key<Flow> flowKey =
new Context.Key<Flow>();
@@ -202,6 +200,11 @@
return instance;
}
+ public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
+ new FlowAnalyzer().analyzeTree(env, make);
+ new AssignAnalyzer().analyzeTree(env, make);
+ }
+
protected Flow(Context context) {
context.put(flowKey, this);
names = Names.instance(context);
@@ -216,1268 +219,1572 @@
allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis();
}
- /** A flag that indicates whether the last statement could
- * complete normally.
- */
- private boolean alive;
-
- /** The set of definitely assigned variables.
- */
- Bits inits;
-
- /** The set of definitely unassigned variables.
- */
- Bits uninits;
-
- HashMap<Symbol, List<Type>> preciseRethrowTypes;
-
- /** The set of variables that are definitely unassigned everywhere
- * in current try block. This variable is maintained lazily; it is
- * updated only when something gets removed from uninits,
- * typically by being assigned in reachable code. To obtain the
- * correct set of variables which are definitely unassigned
- * anywhere in current try block, intersect uninitsTry and
- * uninits.
- */
- Bits uninitsTry;
-
- /** When analyzing a condition, inits and uninits are null.
- * Instead we have:
- */
- Bits initsWhenTrue;
- Bits initsWhenFalse;
- Bits uninitsWhenTrue;
- Bits uninitsWhenFalse;
-
- /** A mapping from addresses to variable symbols.
- */
- VarSymbol[] vars;
-
- /** The current class being defined.
- */
- JCClassDecl classDef;
-
- /** The first variable sequence number in this class definition.
+ /**
+ * Base visitor class for all visitors implementing dataflow analysis logic.
+ * This class define the shared logic for handling jumps (break/continue statements).
*/
- int firstadr;
+ static abstract class BaseAnalyzer<P extends BaseAnalyzer.PendingExit> extends TreeScanner {
- /** The next available variable sequence number.
- */
- int nextadr;
+ enum JumpKind {
+ BREAK(JCTree.Tag.BREAK) {
+ @Override
+ JCTree getTarget(JCTree tree) {
+ return ((JCBreak)tree).target;
+ }
+ },
+ CONTINUE(JCTree.Tag.CONTINUE) {
+ @Override
+ JCTree getTarget(JCTree tree) {
+ return ((JCContinue)tree).target;
+ }
+ };
- /** The list of possibly thrown declarable exceptions.
- */
- List<Type> thrown;
+ JCTree.Tag treeTag;
- /** The list of exceptions that are either caught or declared to be
- * thrown.
- */
- List<Type> caught;
+ private JumpKind(Tag treeTag) {
+ this.treeTag = treeTag;
+ }
+
+ abstract JCTree getTarget(JCTree tree);
+ }
- /** The list of unreferenced automatic resources.
- */
- Scope unrefdResources;
+ /** The currently pending exits that go from current inner blocks
+ * to an enclosing block, in source order.
+ */
+ ListBuffer<P> pendingExits;
- /** Set when processing a loop body the second time for DU analysis. */
- boolean loopPassTwo = false;
+ /** A pending exit. These are the statements return, break, and
+ * continue. In addition, exception-throwing expressions or
+ * statements are put here when not known to be caught. This
+ * will typically result in an error unless it is within a
+ * try-finally whose finally block cannot complete normally.
+ */
+ abstract static class PendingExit {
+ JCTree tree;
- /*-------------------- Environments ----------------------*/
+ PendingExit(JCTree tree) {
+ this.tree = tree;
+ }
+
+ abstract void resolveJump();
+ }
+
+ abstract void markDead();
+
+ /** Record an outward transfer of control. */
+ void recordExit(JCTree tree, P pe) {
+ pendingExits.append(pe);
+ markDead();
+ }
- /** A pending exit. These are the statements return, break, and
- * continue. In addition, exception-throwing expressions or
- * statements are put here when not known to be caught. This
- * will typically result in an error unless it is within a
- * try-finally whose finally block cannot complete normally.
- */
- static class PendingExit {
- JCTree tree;
- Bits inits;
- Bits uninits;
- Type thrown;
- PendingExit(JCTree tree, Bits inits, Bits uninits) {
- this.tree = tree;
- this.inits = inits.dup();
- this.uninits = uninits.dup();
+ /** Resolve all jumps of this statement. */
+ private boolean resolveJump(JCTree tree,
+ ListBuffer<P> oldPendingExits,
+ JumpKind jk) {
+ boolean resolved = false;
+ List<P> exits = pendingExits.toList();
+ pendingExits = oldPendingExits;
+ for (; exits.nonEmpty(); exits = exits.tail) {
+ P exit = exits.head;
+ if (exit.tree.hasTag(jk.treeTag) &&
+ jk.getTarget(exit.tree) == tree) {
+ exit.resolveJump();
+ resolved = true;
+ } else {
+ pendingExits.append(exit);
+ }
+ }
+ return resolved;
}
- PendingExit(JCTree tree, Type thrown) {
- this.tree = tree;
- this.thrown = thrown;
+
+ /** Resolve all breaks of this statement. */
+ boolean resolveContinues(JCTree tree) {
+ return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE);
+ }
+
+ /** Resolve all continues of this statement. */
+ boolean resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) {
+ return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
}
}
- /** The currently pending exits that go from current inner blocks
- * to an enclosing block, in source order.
- */
- ListBuffer<PendingExit> pendingExits;
-
- /*-------------------- Exceptions ----------------------*/
-
- /** Complain that pending exceptions are not caught.
+ /**
+ * This pass implements the first two steps of the dataflow analysis:
+ * (i) liveness analysis checks that every statement is reachable and (ii)
+ * exception analysis to ensure that every checked exception that is
+ * thrown is declared or caught.
*/
- void errorUncaught() {
- for (PendingExit exit = pendingExits.next();
- exit != null;
- exit = pendingExits.next()) {
- if (classDef != null &&
- classDef.pos == exit.tree.pos) {
- log.error(exit.tree.pos(),
- "unreported.exception.default.constructor",
- exit.thrown);
- } else if (exit.tree.hasTag(VARDEF) &&
- ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
- log.error(exit.tree.pos(),
- "unreported.exception.implicit.close",
- exit.thrown,
- ((JCVariableDecl)exit.tree).sym.name);
- } else {
- log.error(exit.tree.pos(),
- "unreported.exception.need.to.catch.or.throw",
- exit.thrown);
+ class FlowAnalyzer extends BaseAnalyzer<FlowAnalyzer.FlowPendingExit> {
+
+ /** A flag that indicates whether the last statement could
+ * complete normally.
+ */
+ private boolean alive;
+
+ HashMap<Symbol, List<Type>> preciseRethrowTypes;
+
+ /** The current class being defined.
+ */
+ JCClassDecl classDef;
+
+ /** The list of possibly thrown declarable exceptions.
+ */
+ List<Type> thrown;
+
+ /** The list of exceptions that are either caught or declared to be
+ * thrown.
+ */
+ List<Type> caught;
+
+ class FlowPendingExit extends BaseAnalyzer.PendingExit {
+
+ Type thrown;
+
+ FlowPendingExit(JCTree tree, Type thrown) {
+ super(tree);
+ this.thrown = thrown;
+ }
+
+ void resolveJump() { /*do nothing*/ }
+ }
+
+ @Override
+ void markDead() {
+ alive = false;
+ }
+
+ /*-------------------- Exceptions ----------------------*/
+
+ /** Complain that pending exceptions are not caught.
+ */
+ void errorUncaught() {
+ for (FlowPendingExit exit = pendingExits.next();
+ exit != null;
+ exit = pendingExits.next()) {
+ if (classDef != null &&
+ classDef.pos == exit.tree.pos) {
+ log.error(exit.tree.pos(),
+ "unreported.exception.default.constructor",
+ exit.thrown);
+ } else if (exit.tree.hasTag(VARDEF) &&
+ ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
+ log.error(exit.tree.pos(),
+ "unreported.exception.implicit.close",
+ exit.thrown,
+ ((JCVariableDecl)exit.tree).sym.name);
+ } else {
+ log.error(exit.tree.pos(),
+ "unreported.exception.need.to.catch.or.throw",
+ exit.thrown);
+ }
+ }
+ }
+
+ /** Record that exception is potentially thrown and check that it
+ * is caught.
+ */
+ void markThrown(JCTree tree, Type exc) {
+ if (!chk.isUnchecked(tree.pos(), exc)) {
+ if (!chk.isHandled(exc, caught))
+ pendingExits.append(new FlowPendingExit(tree, exc));
+ thrown = chk.incl(exc, thrown);
+ }
+ }
+
+ /*************************************************************************
+ * Visitor methods for statements and definitions
+ *************************************************************************/
+
+ /** Analyze a definition.
+ */
+ void scanDef(JCTree tree) {
+ scanStat(tree);
+ if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) {
+ log.error(tree.pos(),
+ "initializer.must.be.able.to.complete.normally");
+ }
+ }
+
+ /** Analyze a statement. Check that statement is reachable.
+ */
+ void scanStat(JCTree tree) {
+ if (!alive && tree != null) {
+ log.error(tree.pos(), "unreachable.stmt");
+ if (!tree.hasTag(SKIP)) alive = true;
+ }
+ scan(tree);
+ }
+
+ /** Analyze list of statements.
+ */
+ void scanStats(List<? extends JCStatement> trees) {
+ if (trees != null)
+ for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
+ scanStat(l.head);
+ }
+
+ /* ------------ Visitor methods for various sorts of trees -------------*/
+
+ public void visitClassDef(JCClassDecl tree) {
+ if (tree.sym == null) return;
+
+ JCClassDecl classDefPrev = classDef;
+ List<Type> thrownPrev = thrown;
+ List<Type> caughtPrev = caught;
+ boolean alivePrev = alive;
+ ListBuffer<FlowPendingExit> pendingExitsPrev = pendingExits;
+ Lint lintPrev = lint;
+
+ pendingExits = new ListBuffer<FlowPendingExit>();
+ if (tree.name != names.empty) {
+ caught = List.nil();
+ }
+ classDef = tree;
+ thrown = List.nil();
+ lint = lint.augment(tree.sym.attributes_field);
+
+ try {
+ // process all the static initializers
+ for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
+ if (!l.head.hasTag(METHODDEF) &&
+ (TreeInfo.flags(l.head) & STATIC) != 0) {
+ scanDef(l.head);
+ errorUncaught();
+ }
+ }
+
+ // add intersection of all thrown clauses of initial constructors
+ // to set of caught exceptions, unless class is anonymous.
+ if (tree.name != names.empty) {
+ boolean firstConstructor = true;
+ for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
+ if (TreeInfo.isInitialConstructor(l.head)) {
+ List<Type> mthrown =
+ ((JCMethodDecl) l.head).sym.type.getThrownTypes();
+ if (firstConstructor) {
+ caught = mthrown;
+ firstConstructor = false;
+ } else {
+ caught = chk.intersect(mthrown, caught);
+ }
+ }
+ }
+ }
+
+ // process all the instance initializers
+ for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
+ if (!l.head.hasTag(METHODDEF) &&
+ (TreeInfo.flags(l.head) & STATIC) == 0) {
+ scanDef(l.head);
+ errorUncaught();
+ }
+ }
+
+ // in an anonymous class, add the set of thrown exceptions to
+ // the throws clause of the synthetic constructor and propagate
+ // outwards.
+ // Changing the throws clause on the fly is okay here because
+ // the anonymous constructor can't be invoked anywhere else,
+ // and its type hasn't been cached.
+ if (tree.name == names.empty) {
+ for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
+ if (TreeInfo.isInitialConstructor(l.head)) {
+ JCMethodDecl mdef = (JCMethodDecl)l.head;
+ mdef.thrown = make.Types(thrown);
+ mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
+ }
+ }
+ thrownPrev = chk.union(thrown, thrownPrev);
+ }
+
+ // process all the methods
+ for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
+ if (l.head.hasTag(METHODDEF)) {
+ scan(l.head);
+ errorUncaught();
+ }
+ }
+
+ thrown = thrownPrev;
+ } finally {
+ pendingExits = pendingExitsPrev;
+ alive = alivePrev;
+ caught = caughtPrev;
+ classDef = classDefPrev;
+ lint = lintPrev;
+ }
+ }
+
+ public void visitMethodDef(JCMethodDecl tree) {
+ if (tree.body == null) return;
+
+ List<Type> caughtPrev = caught;
+ List<Type> mthrown = tree.sym.type.getThrownTypes();
+ Lint lintPrev = lint;
+
+ lint = lint.augment(tree.sym.attributes_field);
+
+ Assert.check(pendingExits.isEmpty());
+
+ try {
+ for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
+ JCVariableDecl def = l.head;
+ scan(def);
+ }
+ if (TreeInfo.isInitialConstructor(tree))
+ caught = chk.union(caught, mthrown);
+ else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
+ caught = mthrown;
+ // else we are in an instance initializer block;
+ // leave caught unchanged.
+
+ alive = true;
+ scanStat(tree.body);
+
+ if (alive && tree.sym.type.getReturnType().tag != VOID)
+ log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
+
+ List<FlowPendingExit> exits = pendingExits.toList();
+ pendingExits = new ListBuffer<FlowPendingExit>();
+ while (exits.nonEmpty()) {
+ FlowPendingExit exit = exits.head;
+ exits = exits.tail;
+ if (exit.thrown == null) {
+ Assert.check(exit.tree.hasTag(RETURN));
+ } else {
+ // uncaught throws will be reported later
+ pendingExits.append(exit);
+ }
+ }
+ } finally {
+ caught = caughtPrev;
+ lint = lintPrev;
+ }
+ }
+
+ public void visitVarDef(JCVariableDecl tree) {
+ if (tree.init != null) {
+ Lint lintPrev = lint;
+ lint = lint.augment(tree.sym.attributes_field);
+ try{
+ scan(tree.init);
+ } finally {
+ lint = lintPrev;
+ }
}
}
- }
+
+ public void visitBlock(JCBlock tree) {
+ scanStats(tree.stats);
+ }
- /** Record that exception is potentially thrown and check that it
- * is caught.
- */
- void markThrown(JCTree tree, Type exc) {
- if (!chk.isUnchecked(tree.pos(), exc)) {
- if (!chk.isHandled(exc, caught))
- pendingExits.append(new PendingExit(tree, exc));
- thrown = chk.incl(exc, thrown);
+ public void visitDoLoop(JCDoWhileLoop tree) {
+ ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
+ pendingExits = new ListBuffer<FlowPendingExit>();
+ scanStat(tree.body);
+ alive |= resolveContinues(tree);
+ scan(tree.cond);
+ alive = alive && !tree.cond.type.isTrue();
+ alive |= resolveBreaks(tree, prevPendingExits);
}
- }
- /*-------------- Processing variables ----------------------*/
+ public void visitWhileLoop(JCWhileLoop tree) {
+ ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
+ pendingExits = new ListBuffer<FlowPendingExit>();
+ scan(tree.cond);
+ alive = !tree.cond.type.isFalse();
+ scanStat(tree.body);
+ alive |= resolveContinues(tree);
+ alive = resolveBreaks(tree, prevPendingExits) ||
+ !tree.cond.type.isTrue();
+ }
- /** Do we need to track init/uninit state of this symbol?
- * I.e. is symbol either a local or a blank final variable?
- */
- boolean trackable(VarSymbol sym) {
- return
- (sym.owner.kind == MTH ||
- ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
- classDef.sym.isEnclosedBy((ClassSymbol)sym.owner)));
- }
+ public void visitForLoop(JCForLoop tree) {
+ ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
+ scanStats(tree.init);
+ pendingExits = new ListBuffer<FlowPendingExit>();
+ if (tree.cond != null) {
+ scan(tree.cond);
+ alive = !tree.cond.type.isFalse();
+ } else {
+ alive = true;
+ }
+ scanStat(tree.body);
+ alive |= resolveContinues(tree);
+ scan(tree.step);
+ alive = resolveBreaks(tree, prevPendingExits) ||
+ tree.cond != null && !tree.cond.type.isTrue();
+ }
- /** Initialize new trackable variable by setting its address field
- * to the next available sequence number and entering it under that
- * index into the vars array.
- */
- void newVar(VarSymbol sym) {
- if (nextadr == vars.length) {
- VarSymbol[] newvars = new VarSymbol[nextadr * 2];
- System.arraycopy(vars, 0, newvars, 0, nextadr);
- vars = newvars;
+ public void visitForeachLoop(JCEnhancedForLoop tree) {
+ visitVarDef(tree.var);
+ ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
+ scan(tree.expr);
+ pendingExits = new ListBuffer<FlowPendingExit>();
+ scanStat(tree.body);
+ alive |= resolveContinues(tree);
+ resolveBreaks(tree, prevPendingExits);
+ alive = true;
+ }
+
+ public void visitLabelled(JCLabeledStatement tree) {
+ ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
+ pendingExits = new ListBuffer<FlowPendingExit>();
+ scanStat(tree.body);
+ alive |= resolveBreaks(tree, prevPendingExits);
}
- sym.adr = nextadr;
- vars[nextadr] = sym;
- inits.excl(nextadr);
- uninits.incl(nextadr);
- nextadr++;
- }
+
+ public void visitSwitch(JCSwitch tree) {
+ ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
+ pendingExits = new ListBuffer<FlowPendingExit>();
+ scan(tree.selector);
+ boolean hasDefault = false;
+ for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
+ alive = true;
+ JCCase c = l.head;
+ if (c.pat == null)
+ hasDefault = true;
+ else
+ scan(c.pat);
+ scanStats(c.stats);
+ // Warn about fall-through if lint switch fallthrough enabled.
+ if (alive &&
+ lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
+ c.stats.nonEmpty() && l.tail.nonEmpty())
+ log.warning(Lint.LintCategory.FALLTHROUGH,
+ l.tail.head.pos(),
+ "possible.fall-through.into.case");
+ }
+ if (!hasDefault) {
+ alive = true;
+ }
+ alive |= resolveBreaks(tree, prevPendingExits);
+ }
- /** Record an initialization of a trackable variable.
- */
- void letInit(DiagnosticPosition pos, VarSymbol sym) {
- if (sym.adr >= firstadr && trackable(sym)) {
- if ((sym.flags() & FINAL) != 0) {
- if ((sym.flags() & PARAMETER) != 0) {
- if ((sym.flags() & UNION) != 0) { //multi-catch parameter
- log.error(pos, "multicatch.parameter.may.not.be.assigned",
- sym);
+ public void visitTry(JCTry tree) {
+ List<Type> caughtPrev = caught;
+ List<Type> thrownPrev = thrown;
+ thrown = List.nil();
+ for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
+ List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
+ ((JCTypeUnion)l.head.param.vartype).alternatives :
+ List.of(l.head.param.vartype);
+ for (JCExpression ct : subClauses) {
+ caught = chk.incl(ct.type, caught);
+ }
+ }
+
+ ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
+ pendingExits = new ListBuffer<FlowPendingExit>();
+ for (JCTree resource : tree.resources) {
+ if (resource instanceof JCVariableDecl) {
+ JCVariableDecl vdecl = (JCVariableDecl) resource;
+ visitVarDef(vdecl);
+ } else if (resource instanceof JCExpression) {
+ scan((JCExpression) resource);
+ } else {
+ throw new AssertionError(tree); // parser error
+ }
+ }
+ for (JCTree resource : tree.resources) {
+ List<Type> closeableSupertypes = resource.type.isCompound() ?
+ types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
+ List.of(resource.type);
+ for (Type sup : closeableSupertypes) {
+ if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
+ Symbol closeMethod = rs.resolveQualifiedMethod(tree,
+ attrEnv,
+ sup,
+ names.close,
+ List.<Type>nil(),
+ List.<Type>nil());
+ if (closeMethod.kind == MTH) {
+ for (Type t : ((MethodSymbol)closeMethod).getThrownTypes()) {
+ markThrown(resource, t);
+ }
+ }
}
- else {
- log.error(pos, "final.parameter.may.not.be.assigned",
- sym);
- }
- } else if (!uninits.isMember(sym.adr)) {
- log.error(pos,
- loopPassTwo
- ? "var.might.be.assigned.in.loop"
- : "var.might.already.be.assigned",
- sym);
- } else if (!inits.isMember(sym.adr)) {
- // reachable assignment
- uninits.excl(sym.adr);
- uninitsTry.excl(sym.adr);
- } else {
- //log.rawWarning(pos, "unreachable assignment");//DEBUG
- uninits.excl(sym.adr);
}
}
- inits.incl(sym.adr);
- } else if ((sym.flags() & FINAL) != 0) {
- log.error(pos, "var.might.already.be.assigned", sym);
+ scanStat(tree.body);
+ List<Type> thrownInTry = allowImprovedCatchAnalysis ?
+ chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType)) :
+ thrown;
+ thrown = thrownPrev;
+ caught = caughtPrev;
+ boolean aliveEnd = alive;
+
+ List<Type> caughtInTry = List.nil();
+ for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
+ alive = true;
+ JCVariableDecl param = l.head.param;
+ List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
+ ((JCTypeUnion)l.head.param.vartype).alternatives :
+ List.of(l.head.param.vartype);
+ List<Type> ctypes = List.nil();
+ List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
+ for (JCExpression ct : subClauses) {
+ Type exc = ct.type;
+ if (exc != syms.unknownType) {
+ ctypes = ctypes.append(exc);
+ if (types.isSameType(exc, syms.objectType))
+ continue;
+ checkCaughtType(l.head.pos(), exc, thrownInTry, caughtInTry);
+ caughtInTry = chk.incl(exc, caughtInTry);
+ }
+ }
+ scan(param);
+ preciseRethrowTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
+ scanStat(l.head.body);
+ preciseRethrowTypes.remove(param.sym);
+ aliveEnd |= alive;
+ }
+ if (tree.finalizer != null) {
+ List<Type> savedThrown = thrown;
+ thrown = List.nil();
+ ListBuffer<FlowPendingExit> exits = pendingExits;
+ pendingExits = prevPendingExits;
+ alive = true;
+ scanStat(tree.finalizer);
+ if (!alive) {
+ // discard exits and exceptions from try and finally
+ thrown = chk.union(thrown, thrownPrev);
+ if (lint.isEnabled(Lint.LintCategory.FINALLY)) {
+ log.warning(Lint.LintCategory.FINALLY,
+ TreeInfo.diagEndPos(tree.finalizer),
+ "finally.cannot.complete");
+ }
+ } else {
+ thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
+ thrown = chk.union(thrown, savedThrown);
+ // FIX: this doesn't preserve source order of exits in catch
+ // versus finally!
+ while (exits.nonEmpty()) {
+ pendingExits.append(exits.next());
+ }
+ alive = aliveEnd;
+ }
+ tree.finallyCanCompleteNormally = alive;
+ } else {
+ thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
+ alive = aliveEnd;
+ ListBuffer<FlowPendingExit> exits = pendingExits;
+ pendingExits = prevPendingExits;
+ while (exits.nonEmpty()) pendingExits.append(exits.next());
+ }
}
- }
+
+ @Override
+ public void visitIf(JCIf tree) {
+ scan(tree.cond);
+ scanStat(tree.thenpart);
+ if (tree.elsepart != null) {
+ boolean aliveAfterThen = alive;
+ alive = true;
+ scanStat(tree.elsepart);
+ alive = alive | aliveAfterThen;
+ } else {
+ alive = true;
+ }
+ }
- /** If tree is either a simple name or of the form this.name or
- * C.this.name, and tree represents a trackable variable,
- * record an initialization of the variable.
- */
- void letInit(JCTree tree) {
- tree = TreeInfo.skipParens(tree);
- if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
- Symbol sym = TreeInfo.symbol(tree);
- if (sym.kind == VAR) {
- letInit(tree.pos(), (VarSymbol)sym);
+ void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) {
+ if (chk.subset(exc, caughtInTry)) {
+ log.error(pos, "except.already.caught", exc);
+ } else if (!chk.isUnchecked(pos, exc) &&
+ !isExceptionOrThrowable(exc) &&
+ !chk.intersects(exc, thrownInTry)) {
+ log.error(pos, "except.never.thrown.in.try", exc);
+ } else if (allowImprovedCatchAnalysis) {
+ List<Type> catchableThrownTypes = chk.intersect(List.of(exc), thrownInTry);
+ // 'catchableThrownTypes' cannnot possibly be empty - if 'exc' was an
+ // unchecked exception, the result list would not be empty, as the augmented
+ // thrown set includes { RuntimeException, Error }; if 'exc' was a checked
+ // exception, that would have been covered in the branch above
+ if (chk.diff(catchableThrownTypes, caughtInTry).isEmpty() &&
+ !isExceptionOrThrowable(exc)) {
+ String key = catchableThrownTypes.length() == 1 ?
+ "unreachable.catch" :
+ "unreachable.catch.1";
+ log.warning(pos, key, catchableThrownTypes);
+ }
+ }
+ }
+ //where
+ private boolean isExceptionOrThrowable(Type exc) {
+ return exc.tsym == syms.throwableType.tsym ||
+ exc.tsym == syms.exceptionType.tsym;
+ }
+
+ public void visitBreak(JCBreak tree) {
+ recordExit(tree, new FlowPendingExit(tree, null));
+ }
+
+ public void visitContinue(JCContinue tree) {
+ recordExit(tree, new FlowPendingExit(tree, null));
+ }
+
+ public void visitReturn(JCReturn tree) {
+ scan(tree.expr);
+ // if not initial constructor, should markDead instead of recordExit
+ recordExit(tree, new FlowPendingExit(tree, null));
+ }
+
+ public void visitThrow(JCThrow tree) {
+ scan(tree.expr);
+ Symbol sym = TreeInfo.symbol(tree.expr);
+ if (sym != null &&
+ sym.kind == VAR &&
+ (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 &&
+ preciseRethrowTypes.get(sym) != null &&
+ allowImprovedRethrowAnalysis) {
+ for (Type t : preciseRethrowTypes.get(sym)) {
+ markThrown(tree, t);
+ }
+ }
+ else {
+ markThrown(tree, tree.expr.type);
+ }
+ markDead();
+ }
+
+ public void visitApply(JCMethodInvocation tree) {
+ scan(tree.meth);
+ scan(tree.args);
+ for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail)
+ markThrown(tree, l.head);
+ }
+
+ public void visitNewClass(JCNewClass tree) {
+ scan(tree.encl);
+ scan(tree.args);
+ // scan(tree.def);
+ for (List<Type> l = tree.constructorType.getThrownTypes();
+ l.nonEmpty();
+ l = l.tail) {
+ markThrown(tree, l.head);
+ }
+ List<Type> caughtPrev = caught;
+ try {
+ // If the new class expression defines an anonymous class,
+ // analysis of the anonymous constructor may encounter thrown
+ // types which are unsubstituted type variables.
+ // However, since the constructor's actual thrown types have
+ // already been marked as thrown, it is safe to simply include
+ // each of the constructor's formal thrown types in the set of
+ // 'caught/declared to be thrown' types, for the duration of
+ // the class def analysis.
+ if (tree.def != null)
+ for (List<Type> l = tree.constructor.type.getThrownTypes();
+ l.nonEmpty();
+ l = l.tail) {
+ caught = chk.incl(l.head, caught);
+ }
+ scan(tree.def);
+ }
+ finally {
+ caught = caughtPrev;
+ }
+ }
+
+ public void visitTopLevel(JCCompilationUnit tree) {
+ // Do nothing for TopLevel since each class is visited individually
+ }
+
+ /**************************************************************************
+ * main method
+ *************************************************************************/
+
+ /** Perform definite assignment/unassignment analysis on a tree.
+ */
+ public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
+ try {
+ attrEnv = env;
+ JCTree tree = env.tree;
+ Flow.this.make = make;
+ pendingExits = new ListBuffer<FlowPendingExit>();
+ preciseRethrowTypes = new HashMap<Symbol, List<Type>>();
+ alive = true;
+ this.thrown = this.caught = null;
+ this.classDef = null;
+ scan(tree);
+ } finally {
+ pendingExits = null;
+ Flow.this.make = null;
+ this.thrown = this.caught = null;
+ this.classDef = null;
}
}
}
- /** Check that trackable variable is initialized.
+ /**
+ * This pass implements (i) definite assignment analysis, which ensures that
+ * each variable is assigned when used and (ii) definite unassignment analysis,
+ * which ensures that no final variable is assigned more than once. This visitor
+ * depends on the results of the liveliness analyzer.
*/
- void checkInit(DiagnosticPosition pos, VarSymbol sym) {
- if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
- trackable(sym) &&
- !inits.isMember(sym.adr)) {
- log.error(pos, "var.might.not.have.been.initialized",
- sym);
- inits.incl(sym.adr);
- }
- }
+ class AssignAnalyzer extends BaseAnalyzer<AssignAnalyzer.AssignPendingExit> {
+
+ /** The set of definitely assigned variables.
+ */
+ Bits inits;
+
+ /** The set of definitely unassigned variables.
+ */
+ Bits uninits;
- /*-------------------- Handling jumps ----------------------*/
+ /** The set of variables that are definitely unassigned everywhere
+ * in current try block. This variable is maintained lazily; it is
+ * updated only when something gets removed from uninits,
+ * typically by being assigned in reachable code. To obtain the
+ * correct set of variables which are definitely unassigned
+ * anywhere in current try block, intersect uninitsTry and
+ * uninits.
+ */
+ Bits uninitsTry;
- /** Record an outward transfer of control. */
- void recordExit(JCTree tree) {
- pendingExits.append(new PendingExit(tree, inits, uninits));
- markDead();
- }
+ /** When analyzing a condition, inits and uninits are null.
+ * Instead we have:
+ */
+ Bits initsWhenTrue;
+ Bits initsWhenFalse;
+ Bits uninitsWhenTrue;
+ Bits uninitsWhenFalse;
- /** Resolve all breaks of this statement. */
- boolean resolveBreaks(JCTree tree,
- ListBuffer<PendingExit> oldPendingExits) {
- boolean result = false;
- List<PendingExit> exits = pendingExits.toList();
- pendingExits = oldPendingExits;
- for (; exits.nonEmpty(); exits = exits.tail) {
- PendingExit exit = exits.head;
- if (exit.tree.hasTag(BREAK) &&
- ((JCBreak) exit.tree).target == tree) {
- inits.andSet(exit.inits);
- uninits.andSet(exit.uninits);
- result = true;
- } else {
- pendingExits.append(exit);
+ /** A mapping from addresses to variable symbols.
+ */
+ VarSymbol[] vars;
+
+ /** The current class being defined.
+ */
+ JCClassDecl classDef;
+
+ /** The first variable sequence number in this class definition.
+ */
+ int firstadr;
+
+ /** The next available variable sequence number.
+ */
+ int nextadr;
+
+ /** The list of unreferenced automatic resources.
+ */
+ Scope unrefdResources;
+
+ /** Set when processing a loop body the second time for DU analysis. */
+ boolean loopPassTwo = false;
+
+ class AssignPendingExit extends BaseAnalyzer.PendingExit {
+
+ Bits exit_inits;
+ Bits exit_uninits;
+
+ AssignPendingExit(JCTree tree, Bits inits, Bits uninits) {
+ super(tree);
+ this.exit_inits = inits.dup();
+ this.exit_uninits = uninits.dup();
}
- }
- return result;
- }
- /** Resolve all continues of this statement. */
- boolean resolveContinues(JCTree tree) {
- boolean result = false;
- List<PendingExit> exits = pendingExits.toList();
- pendingExits = new ListBuffer<PendingExit>();
- for (; exits.nonEmpty(); exits = exits.tail) {
- PendingExit exit = exits.head;
- if (exit.tree.hasTag(CONTINUE) &&
- ((JCContinue) exit.tree).target == tree) {
- inits.andSet(exit.inits);
- uninits.andSet(exit.uninits);
- result = true;
- } else {
- pendingExits.append(exit);
+ void resolveJump() {
+ inits.andSet(exit_inits);
+ uninits.andSet(exit_uninits);
}
}
- return result;
- }
- /** Record that statement is unreachable.
- */
- void markDead() {
- inits.inclRange(firstadr, nextadr);
- uninits.inclRange(firstadr, nextadr);
- alive = false;
- }
+ @Override
+ void markDead() {
+ inits.inclRange(firstadr, nextadr);
+ uninits.inclRange(firstadr, nextadr);
+ }
+
+ /*-------------- Processing variables ----------------------*/
- /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
- */
- void split(boolean setToNull) {
- initsWhenFalse = inits.dup();
- uninitsWhenFalse = uninits.dup();
- initsWhenTrue = inits;
- uninitsWhenTrue = uninits;
- if (setToNull)
- inits = uninits = null;
- }
+ /** Do we need to track init/uninit state of this symbol?
+ * I.e. is symbol either a local or a blank final variable?
+ */
+ boolean trackable(VarSymbol sym) {
+ return
+ (sym.owner.kind == MTH ||
+ ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
+ classDef.sym.isEnclosedBy((ClassSymbol)sym.owner)));
+ }
- /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
- */
- void merge() {
- inits = initsWhenFalse.andSet(initsWhenTrue);
- uninits = uninitsWhenFalse.andSet(uninitsWhenTrue);
- }
-
-/* ************************************************************************
- * Visitor methods for statements and definitions
- *************************************************************************/
-
- /** Analyze a definition.
- */
- void scanDef(JCTree tree) {
- scanStat(tree);
- if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) {
- log.error(tree.pos(),
- "initializer.must.be.able.to.complete.normally");
+ /** Initialize new trackable variable by setting its address field
+ * to the next available sequence number and entering it under that
+ * index into the vars array.
+ */
+ void newVar(VarSymbol sym) {
+ if (nextadr == vars.length) {
+ VarSymbol[] newvars = new VarSymbol[nextadr * 2];
+ System.arraycopy(vars, 0, newvars, 0, nextadr);
+ vars = newvars;
+ }
+ sym.adr = nextadr;
+ vars[nextadr] = sym;
+ inits.excl(nextadr);
+ uninits.incl(nextadr);
+ nextadr++;
}
- }
- /** Analyze a statement. Check that statement is reachable.
- */
- void scanStat(JCTree tree) {
- if (!alive && tree != null) {
- log.error(tree.pos(), "unreachable.stmt");
- if (!tree.hasTag(SKIP)) alive = true;
- }
- scan(tree);
- }
-
- /** Analyze list of statements.
- */
- void scanStats(List<? extends JCStatement> trees) {
- if (trees != null)
- for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
- scanStat(l.head);
- }
-
- /** Analyze an expression. Make sure to set (un)inits rather than
- * (un)initsWhenTrue(WhenFalse) on exit.
- */
- void scanExpr(JCTree tree) {
- if (tree != null) {
- scan(tree);
- if (inits == null) merge();
+ /** Record an initialization of a trackable variable.
+ */
+ void letInit(DiagnosticPosition pos, VarSymbol sym) {
+ if (sym.adr >= firstadr && trackable(sym)) {
+ if ((sym.flags() & FINAL) != 0) {
+ if ((sym.flags() & PARAMETER) != 0) {
+ if ((sym.flags() & UNION) != 0) { //multi-catch parameter
+ log.error(pos, "multicatch.parameter.may.not.be.assigned",
+ sym);
+ }
+ else {
+ log.error(pos, "final.parameter.may.not.be.assigned",
+ sym);
+ }
+ } else if (!uninits.isMember(sym.adr)) {
+ log.error(pos,
+ loopPassTwo
+ ? "var.might.be.assigned.in.loop"
+ : "var.might.already.be.assigned",
+ sym);
+ } else if (!inits.isMember(sym.adr)) {
+ // reachable assignment
+ uninits.excl(sym.adr);
+ uninitsTry.excl(sym.adr);
+ } else {
+ //log.rawWarning(pos, "unreachable assignment");//DEBUG
+ uninits.excl(sym.adr);
+ }
+ }
+ inits.incl(sym.adr);
+ } else if ((sym.flags() & FINAL) != 0) {
+ log.error(pos, "var.might.already.be.assigned", sym);
+ }
}
- }
- /** Analyze a list of expressions.
- */
- void scanExprs(List<? extends JCExpression> trees) {
- if (trees != null)
- for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail)
- scanExpr(l.head);
- }
+ /** If tree is either a simple name or of the form this.name or
+ * C.this.name, and tree represents a trackable variable,
+ * record an initialization of the variable.
+ */
+ void letInit(JCTree tree) {
+ tree = TreeInfo.skipParens(tree);
+ if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
+ Symbol sym = TreeInfo.symbol(tree);
+ if (sym.kind == VAR) {
+ letInit(tree.pos(), (VarSymbol)sym);
+ }
+ }
+ }
- /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse)
- * rather than (un)inits on exit.
- */
- void scanCond(JCTree tree) {
- if (tree.type.isFalse()) {
- if (inits == null) merge();
- initsWhenTrue = inits.dup();
- initsWhenTrue.inclRange(firstadr, nextadr);
- uninitsWhenTrue = uninits.dup();
- uninitsWhenTrue.inclRange(firstadr, nextadr);
- initsWhenFalse = inits;
- uninitsWhenFalse = uninits;
- } else if (tree.type.isTrue()) {
- if (inits == null) merge();
+ /** Check that trackable variable is initialized.
+ */
+ void checkInit(DiagnosticPosition pos, VarSymbol sym) {
+ if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
+ trackable(sym) &&
+ !inits.isMember(sym.adr)) {
+ log.error(pos, "var.might.not.have.been.initialized",
+ sym);
+ inits.incl(sym.adr);
+ }
+ }
+
+ /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
+ */
+ void split(boolean setToNull) {
initsWhenFalse = inits.dup();
- initsWhenFalse.inclRange(firstadr, nextadr);
uninitsWhenFalse = uninits.dup();
- uninitsWhenFalse.inclRange(firstadr, nextadr);
initsWhenTrue = inits;
uninitsWhenTrue = uninits;
- } else {
- scan(tree);
- if (inits != null)
- split(tree.type != syms.unknownType);
+ if (setToNull)
+ inits = uninits = null;
}
- if (tree.type != syms.unknownType)
- inits = uninits = null;
- }
- /* ------------ Visitor methods for various sorts of trees -------------*/
+ /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
+ */
+ void merge() {
+ inits = initsWhenFalse.andSet(initsWhenTrue);
+ uninits = uninitsWhenFalse.andSet(uninitsWhenTrue);
+ }
- public void visitClassDef(JCClassDecl tree) {
- if (tree.sym == null) return;
+ /* ************************************************************************
+ * Visitor methods for statements and definitions
+ *************************************************************************/
- JCClassDecl classDefPrev = classDef;
- List<Type> thrownPrev = thrown;
- List<Type> caughtPrev = caught;
- boolean alivePrev = alive;
- int firstadrPrev = firstadr;
- int nextadrPrev = nextadr;
- ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
- Lint lintPrev = lint;
+ /** Analyze an expression. Make sure to set (un)inits rather than
+ * (un)initsWhenTrue(WhenFalse) on exit.
+ */
+ void scanExpr(JCTree tree) {
+ if (tree != null) {
+ scan(tree);
+ if (inits == null) merge();
+ }
+ }
- pendingExits = new ListBuffer<PendingExit>();
- if (tree.name != names.empty) {
- caught = List.nil();
- firstadr = nextadr;
+ /** Analyze a list of expressions.
+ */
+ void scanExprs(List<? extends JCExpression> trees) {
+ if (trees != null)
+ for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail)
+ scanExpr(l.head);
}
- classDef = tree;
- thrown = List.nil();
- lint = lint.augment(tree.sym.attributes_field);
- try {
- // define all the static fields
- for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
- if (l.head.hasTag(VARDEF)) {
- JCVariableDecl def = (JCVariableDecl)l.head;
- if ((def.mods.flags & STATIC) != 0) {
- VarSymbol sym = def.sym;
- if (trackable(sym))
- newVar(sym);
- }
- }
+ /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse)
+ * rather than (un)inits on exit.
+ */
+ void scanCond(JCTree tree) {
+ if (tree.type.isFalse()) {
+ if (inits == null) merge();
+ initsWhenTrue = inits.dup();
+ initsWhenTrue.inclRange(firstadr, nextadr);
+ uninitsWhenTrue = uninits.dup();
+ uninitsWhenTrue.inclRange(firstadr, nextadr);
+ initsWhenFalse = inits;
+ uninitsWhenFalse = uninits;
+ } else if (tree.type.isTrue()) {
+ if (inits == null) merge();
+ initsWhenFalse = inits.dup();
+ initsWhenFalse.inclRange(firstadr, nextadr);
+ uninitsWhenFalse = uninits.dup();
+ uninitsWhenFalse.inclRange(firstadr, nextadr);
+ initsWhenTrue = inits;
+ uninitsWhenTrue = uninits;
+ } else {
+ scan(tree);
+ if (inits != null)
+ split(tree.type != syms.unknownType);
}
+ if (tree.type != syms.unknownType)
+ inits = uninits = null;
+ }
- // process all the static initializers
- for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
- if (!l.head.hasTag(METHODDEF) &&
- (TreeInfo.flags(l.head) & STATIC) != 0) {
- scanDef(l.head);
- errorUncaught();
- }
- }
+ /* ------------ Visitor methods for various sorts of trees -------------*/
+
+ public void visitClassDef(JCClassDecl tree) {
+ if (tree.sym == null) return;
+
+ JCClassDecl classDefPrev = classDef;
+ int firstadrPrev = firstadr;
+ int nextadrPrev = nextadr;
+ ListBuffer<AssignPendingExit> pendingExitsPrev = pendingExits;
+ Lint lintPrev = lint;
- // add intersection of all thrown clauses of initial constructors
- // to set of caught exceptions, unless class is anonymous.
+ pendingExits = new ListBuffer<AssignPendingExit>();
if (tree.name != names.empty) {
- boolean firstConstructor = true;
+ firstadr = nextadr;
+ }
+ classDef = tree;
+ lint = lint.augment(tree.sym.attributes_field);
+
+ try {
+ // define all the static fields
for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
- if (TreeInfo.isInitialConstructor(l.head)) {
- List<Type> mthrown =
- ((JCMethodDecl) l.head).sym.type.getThrownTypes();
- if (firstConstructor) {
- caught = mthrown;
- firstConstructor = false;
- } else {
- caught = chk.intersect(mthrown, caught);
+ if (l.head.hasTag(VARDEF)) {
+ JCVariableDecl def = (JCVariableDecl)l.head;
+ if ((def.mods.flags & STATIC) != 0) {
+ VarSymbol sym = def.sym;
+ if (trackable(sym))
+ newVar(sym);
}
}
}
- }
- // define all the instance fields
- for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
- if (l.head.hasTag(VARDEF)) {
- JCVariableDecl def = (JCVariableDecl)l.head;
- if ((def.mods.flags & STATIC) == 0) {
- VarSymbol sym = def.sym;
- if (trackable(sym))
- newVar(sym);
+ // process all the static initializers
+ for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
+ if (!l.head.hasTag(METHODDEF) &&
+ (TreeInfo.flags(l.head) & STATIC) != 0) {
+ scan(l.head);
}
}
- }
- // process all the instance initializers
- for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
- if (!l.head.hasTag(METHODDEF) &&
- (TreeInfo.flags(l.head) & STATIC) == 0) {
- scanDef(l.head);
- errorUncaught();
+ // define all the instance fields
+ for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
+ if (l.head.hasTag(VARDEF)) {
+ JCVariableDecl def = (JCVariableDecl)l.head;
+ if ((def.mods.flags & STATIC) == 0) {
+ VarSymbol sym = def.sym;
+ if (trackable(sym))
+ newVar(sym);
+ }
+ }
}
- }
- // in an anonymous class, add the set of thrown exceptions to
- // the throws clause of the synthetic constructor and propagate
- // outwards.
- // Changing the throws clause on the fly is okay here because
- // the anonymous constructor can't be invoked anywhere else,
- // and its type hasn't been cached.
- if (tree.name == names.empty) {
+ // process all the instance initializers
for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
- if (TreeInfo.isInitialConstructor(l.head)) {
- JCMethodDecl mdef = (JCMethodDecl)l.head;
- mdef.thrown = make.Types(thrown);
- mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
+ if (!l.head.hasTag(METHODDEF) &&
+ (TreeInfo.flags(l.head) & STATIC) == 0) {
+ scan(l.head);
+ }
+ }
+
+ // process all the methods
+ for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
+ if (l.head.hasTag(METHODDEF)) {
+ scan(l.head);
}
}
- thrownPrev = chk.union(thrown, thrownPrev);
+ } finally {
+ pendingExits = pendingExitsPrev;
+ nextadr = nextadrPrev;
+ firstadr = firstadrPrev;
+ classDef = classDefPrev;
+ lint = lintPrev;
}
+ }
- // process all the methods
- for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
- if (l.head.hasTag(METHODDEF)) {
- scan(l.head);
- errorUncaught();
- }
- }
+ public void visitMethodDef(JCMethodDecl tree) {
+ if (tree.body == null) return;
- thrown = thrownPrev;
- } finally {
- pendingExits = pendingExitsPrev;
- alive = alivePrev;
- nextadr = nextadrPrev;
- firstadr = firstadrPrev;
- caught = caughtPrev;
- classDef = classDefPrev;
- lint = lintPrev;
- }
- }
+ Bits initsPrev = inits.dup();
+ Bits uninitsPrev = uninits.dup();
+ int nextadrPrev = nextadr;
+ int firstadrPrev = firstadr;
+ Lint lintPrev = lint;
- public void visitMethodDef(JCMethodDecl tree) {
- if (tree.body == null) return;
+ lint = lint.augment(tree.sym.attributes_field);
+
+ Assert.check(pendingExits.isEmpty());
- List<Type> caughtPrev = caught;
- List<Type> mthrown = tree.sym.type.getThrownTypes();
- Bits initsPrev = inits.dup();
- Bits uninitsPrev = uninits.dup();
- int nextadrPrev = nextadr;
- int firstadrPrev = firstadr;
- Lint lintPrev = lint;
-
- lint = lint.augment(tree.sym.attributes_field);
-
- Assert.check(pendingExits.isEmpty());
+ try {
+ boolean isInitialConstructor =
+ TreeInfo.isInitialConstructor(tree);
- try {
- boolean isInitialConstructor =
- TreeInfo.isInitialConstructor(tree);
-
- if (!isInitialConstructor)
- firstadr = nextadr;
- for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
- JCVariableDecl def = l.head;
- scan(def);
- inits.incl(def.sym.adr);
- uninits.excl(def.sym.adr);
- }
- if (isInitialConstructor)
- caught = chk.union(caught, mthrown);
- else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
- caught = mthrown;
- // else we are in an instance initializer block;
- // leave caught unchanged.
+ if (!isInitialConstructor)
+ firstadr = nextadr;
+ for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
+ JCVariableDecl def = l.head;
+ scan(def);
+ inits.incl(def.sym.adr);
+ uninits.excl(def.sym.adr);
+ }
+ // else we are in an instance initializer block;
+ // leave caught unchanged.
+ scan(tree.body);
- alive = true;
- scanStat(tree.body);
-
- if (alive && tree.sym.type.getReturnType().tag != VOID)
- log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
-
- if (isInitialConstructor) {
- for (int i = firstadr; i < nextadr; i++)
- if (vars[i].owner == classDef.sym)
- checkInit(TreeInfo.diagEndPos(tree.body), vars[i]);
- }
- List<PendingExit> exits = pendingExits.toList();
- pendingExits = new ListBuffer<PendingExit>();
- while (exits.nonEmpty()) {
- PendingExit exit = exits.head;
- exits = exits.tail;
- if (exit.thrown == null) {
- Assert.check(exit.tree.hasTag(RETURN));
+ if (isInitialConstructor) {
+ for (int i = firstadr; i < nextadr; i++)
+ if (vars[i].owner == classDef.sym)
+ checkInit(TreeInfo.diagEndPos(tree.body), vars[i]);
+ }
+ List<AssignPendingExit> exits = pendingExits.toList();
+ pendingExits = new ListBuffer<AssignPendingExit>();
+ while (exits.nonEmpty()) {
+ AssignPendingExit exit = exits.head;
+ exits = exits.tail;
+ Assert.check(exit.tree.hasTag(RETURN), exit.tree);
if (isInitialConstructor) {
- inits = exit.inits;
+ inits = exit.exit_inits;
for (int i = firstadr; i < nextadr; i++)
checkInit(exit.tree.pos(), vars[i]);
}
- } else {
- // uncaught throws will be reported later
- pendingExits.append(exit);
}
- }
- } finally {
- inits = initsPrev;
- uninits = uninitsPrev;
- nextadr = nextadrPrev;
- firstadr = firstadrPrev;
- caught = caughtPrev;
- lint = lintPrev;
- }
- }
-
- public void visitVarDef(JCVariableDecl tree) {
- boolean track = trackable(tree.sym);
- if (track && tree.sym.owner.kind == MTH) newVar(tree.sym);
- if (tree.init != null) {
- Lint lintPrev = lint;
- lint = lint.augment(tree.sym.attributes_field);
- try{
- scanExpr(tree.init);
- if (track) letInit(tree.pos(), tree.sym);
} finally {
+ inits = initsPrev;
+ uninits = uninitsPrev;
+ nextadr = nextadrPrev;
+ firstadr = firstadrPrev;
lint = lintPrev;
}
}
- }
-
- public void visitBlock(JCBlock tree) {
- int nextadrPrev = nextadr;
- scanStats(tree.stats);
- nextadr = nextadrPrev;
- }
- public void visitDoLoop(JCDoWhileLoop tree) {
- ListBuffer<PendingExit> prevPendingExits = pendingExits;
- boolean prevLoopPassTwo = loopPassTwo;
- pendingExits = new ListBuffer<PendingExit>();
- int prevErrors = log.nerrors;
- do {
- Bits uninitsEntry = uninits.dup();
- uninitsEntry.excludeFrom(nextadr);
- scanStat(tree.body);
- alive |= resolveContinues(tree);
- scanCond(tree.cond);
- if (log.nerrors != prevErrors ||
- loopPassTwo ||
- uninitsEntry.dup().diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
- break;
- inits = initsWhenTrue;
- uninits = uninitsEntry.andSet(uninitsWhenTrue);
- loopPassTwo = true;
- alive = true;
- } while (true);
- loopPassTwo = prevLoopPassTwo;
- inits = initsWhenFalse;
- uninits = uninitsWhenFalse;
- alive = alive && !tree.cond.type.isTrue();
- alive |= resolveBreaks(tree, prevPendingExits);
- }
+ public void visitVarDef(JCVariableDecl tree) {
+ boolean track = trackable(tree.sym);
+ if (track && tree.sym.owner.kind == MTH) newVar(tree.sym);
+ if (tree.init != null) {
+ Lint lintPrev = lint;
+ lint = lint.augment(tree.sym.attributes_field);
+ try{
+ scanExpr(tree.init);
+ if (track) letInit(tree.pos(), tree.sym);
+ } finally {
+ lint = lintPrev;
+ }
+ }
+ }
+
+ public void visitBlock(JCBlock tree) {
+ int nextadrPrev = nextadr;
+ scan(tree.stats);
+ nextadr = nextadrPrev;
+ }
- public void visitWhileLoop(JCWhileLoop tree) {
- ListBuffer<PendingExit> prevPendingExits = pendingExits;
- boolean prevLoopPassTwo = loopPassTwo;
- Bits initsCond;
- Bits uninitsCond;
- pendingExits = new ListBuffer<PendingExit>();
- int prevErrors = log.nerrors;
- do {
- Bits uninitsEntry = uninits.dup();
- uninitsEntry.excludeFrom(nextadr);
- scanCond(tree.cond);
- initsCond = initsWhenFalse;
- uninitsCond = uninitsWhenFalse;
- inits = initsWhenTrue;
- uninits = uninitsWhenTrue;
- alive = !tree.cond.type.isFalse();
- scanStat(tree.body);
- alive |= resolveContinues(tree);
- if (log.nerrors != prevErrors ||
- loopPassTwo ||
- uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
- break;
- uninits = uninitsEntry.andSet(uninits);
- loopPassTwo = true;
- alive = true;
- } while (true);
- loopPassTwo = prevLoopPassTwo;
- inits = initsCond;
- uninits = uninitsCond;
- alive = resolveBreaks(tree, prevPendingExits) ||
- !tree.cond.type.isTrue();
- }
+ public void visitDoLoop(JCDoWhileLoop tree) {
+ ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+ boolean prevLoopPassTwo = loopPassTwo;
+ pendingExits = new ListBuffer<AssignPendingExit>();
+ int prevErrors = log.nerrors;
+ do {
+ Bits uninitsEntry = uninits.dup();
+ uninitsEntry.excludeFrom(nextadr);
+ scan(tree.body);
+ resolveContinues(tree);
+ scanCond(tree.cond);
+ if (log.nerrors != prevErrors ||
+ loopPassTwo ||
+ uninitsEntry.dup().diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
+ break;
+ inits = initsWhenTrue;
+ uninits = uninitsEntry.andSet(uninitsWhenTrue);
+ loopPassTwo = true;
+ } while (true);
+ loopPassTwo = prevLoopPassTwo;
+ inits = initsWhenFalse;
+ uninits = uninitsWhenFalse;
+ resolveBreaks(tree, prevPendingExits);
+ }
- public void visitForLoop(JCForLoop tree) {
- ListBuffer<PendingExit> prevPendingExits = pendingExits;
- boolean prevLoopPassTwo = loopPassTwo;
- int nextadrPrev = nextadr;
- scanStats(tree.init);
- Bits initsCond;
- Bits uninitsCond;
- pendingExits = new ListBuffer<PendingExit>();
- int prevErrors = log.nerrors;
- do {
- Bits uninitsEntry = uninits.dup();
- uninitsEntry.excludeFrom(nextadr);
- if (tree.cond != null) {
+ public void visitWhileLoop(JCWhileLoop tree) {
+ ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+ boolean prevLoopPassTwo = loopPassTwo;
+ Bits initsCond;
+ Bits uninitsCond;
+ pendingExits = new ListBuffer<AssignPendingExit>();
+ int prevErrors = log.nerrors;
+ do {
+ Bits uninitsEntry = uninits.dup();
+ uninitsEntry.excludeFrom(nextadr);
scanCond(tree.cond);
initsCond = initsWhenFalse;
uninitsCond = uninitsWhenFalse;
inits = initsWhenTrue;
uninits = uninitsWhenTrue;
- alive = !tree.cond.type.isFalse();
- } else {
- initsCond = inits.dup();
- initsCond.inclRange(firstadr, nextadr);
- uninitsCond = uninits.dup();
- uninitsCond.inclRange(firstadr, nextadr);
- alive = true;
- }
- scanStat(tree.body);
- alive |= resolveContinues(tree);
- scan(tree.step);
- if (log.nerrors != prevErrors ||
- loopPassTwo ||
- uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
- break;
- uninits = uninitsEntry.andSet(uninits);
- loopPassTwo = true;
- alive = true;
- } while (true);
- loopPassTwo = prevLoopPassTwo;
- inits = initsCond;
- uninits = uninitsCond;
- alive = resolveBreaks(tree, prevPendingExits) ||
- tree.cond != null && !tree.cond.type.isTrue();
- nextadr = nextadrPrev;
- }
+ scan(tree.body);
+ resolveContinues(tree);
+ if (log.nerrors != prevErrors ||
+ loopPassTwo ||
+ uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
+ break;
+ uninits = uninitsEntry.andSet(uninits);
+ loopPassTwo = true;
+ } while (true);
+ loopPassTwo = prevLoopPassTwo;
+ inits = initsCond;
+ uninits = uninitsCond;
+ resolveBreaks(tree, prevPendingExits);
+ }
- public void visitForeachLoop(JCEnhancedForLoop tree) {
- visitVarDef(tree.var);
+ public void visitForLoop(JCForLoop tree) {
+ ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+ boolean prevLoopPassTwo = loopPassTwo;
+ int nextadrPrev = nextadr;
+ scan(tree.init);
+ Bits initsCond;
+ Bits uninitsCond;
+ pendingExits = new ListBuffer<AssignPendingExit>();
+ int prevErrors = log.nerrors;
+ do {
+ Bits uninitsEntry = uninits.dup();
+ uninitsEntry.excludeFrom(nextadr);
+ if (tree.cond != null) {
+ scanCond(tree.cond);
+ initsCond = initsWhenFalse;
+ uninitsCond = uninitsWhenFalse;
+ inits = initsWhenTrue;
+ uninits = uninitsWhenTrue;
+ } else {
+ initsCond = inits.dup();
+ initsCond.inclRange(firstadr, nextadr);
+ uninitsCond = uninits.dup();
+ uninitsCond.inclRange(firstadr, nextadr);
+ }
+ scan(tree.body);
+ resolveContinues(tree);
+ scan(tree.step);
+ if (log.nerrors != prevErrors ||
+ loopPassTwo ||
+ uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
+ break;
+ uninits = uninitsEntry.andSet(uninits);
+ loopPassTwo = true;
+ } while (true);
+ loopPassTwo = prevLoopPassTwo;
+ inits = initsCond;
+ uninits = uninitsCond;
+ resolveBreaks(tree, prevPendingExits);
+ nextadr = nextadrPrev;
+ }
- ListBuffer<PendingExit> prevPendingExits = pendingExits;
- boolean prevLoopPassTwo = loopPassTwo;
- int nextadrPrev = nextadr;
- scan(tree.expr);
- Bits initsStart = inits.dup();
- Bits uninitsStart = uninits.dup();
+ public void visitForeachLoop(JCEnhancedForLoop tree) {
+ visitVarDef(tree.var);
+
+ ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+ boolean prevLoopPassTwo = loopPassTwo;
+ int nextadrPrev = nextadr;
+ scan(tree.expr);
+ Bits initsStart = inits.dup();
+ Bits uninitsStart = uninits.dup();
+
+ letInit(tree.pos(), tree.var.sym);
+ pendingExits = new ListBuffer<AssignPendingExit>();
+ int prevErrors = log.nerrors;
+ do {
+ Bits uninitsEntry = uninits.dup();
+ uninitsEntry.excludeFrom(nextadr);
+ scan(tree.body);
+ resolveContinues(tree);
+ if (log.nerrors != prevErrors ||
+ loopPassTwo ||
+ uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
+ break;
+ uninits = uninitsEntry.andSet(uninits);
+ loopPassTwo = true;
+ } while (true);
+ loopPassTwo = prevLoopPassTwo;
+ inits = initsStart;
+ uninits = uninitsStart.andSet(uninits);
+ resolveBreaks(tree, prevPendingExits);
+ nextadr = nextadrPrev;
+ }
+
+ public void visitLabelled(JCLabeledStatement tree) {
+ ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+ pendingExits = new ListBuffer<AssignPendingExit>();
+ scan(tree.body);
+ resolveBreaks(tree, prevPendingExits);
+ }
- letInit(tree.pos(), tree.var.sym);
- pendingExits = new ListBuffer<PendingExit>();
- int prevErrors = log.nerrors;
- do {
- Bits uninitsEntry = uninits.dup();
- uninitsEntry.excludeFrom(nextadr);
- scanStat(tree.body);
- alive |= resolveContinues(tree);
- if (log.nerrors != prevErrors ||
- loopPassTwo ||
- uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
- break;
- uninits = uninitsEntry.andSet(uninits);
- loopPassTwo = true;
- alive = true;
- } while (true);
- loopPassTwo = prevLoopPassTwo;
- inits = initsStart;
- uninits = uninitsStart.andSet(uninits);
- resolveBreaks(tree, prevPendingExits);
- alive = true;
- nextadr = nextadrPrev;
- }
+ public void visitSwitch(JCSwitch tree) {
+ ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+ pendingExits = new ListBuffer<AssignPendingExit>();
+ int nextadrPrev = nextadr;
+ scanExpr(tree.selector);
+ Bits initsSwitch = inits;
+ Bits uninitsSwitch = uninits.dup();
+ boolean hasDefault = false;
+ for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
+ inits = initsSwitch.dup();
+ uninits = uninits.andSet(uninitsSwitch);
+ JCCase c = l.head;
+ if (c.pat == null)
+ hasDefault = true;
+ else
+ scanExpr(c.pat);
+ scan(c.stats);
+ addVars(c.stats, initsSwitch, uninitsSwitch);
+ // Warn about fall-through if lint switch fallthrough enabled.
+ }
+ if (!hasDefault) {
+ inits.andSet(initsSwitch);
+ }
+ resolveBreaks(tree, prevPendingExits);
+ nextadr = nextadrPrev;
+ }
+ // where
+ /** Add any variables defined in stats to inits and uninits. */
+ private void addVars(List<JCStatement> stats, Bits inits,
+ Bits uninits) {
+ for (;stats.nonEmpty(); stats = stats.tail) {
+ JCTree stat = stats.head;
+ if (stat.hasTag(VARDEF)) {
+ int adr = ((JCVariableDecl) stat).sym.adr;
+ inits.excl(adr);
+ uninits.incl(adr);
+ }
+ }
+ }
- public void visitLabelled(JCLabeledStatement tree) {
- ListBuffer<PendingExit> prevPendingExits = pendingExits;
- pendingExits = new ListBuffer<PendingExit>();
- scanStat(tree.body);
- alive |= resolveBreaks(tree, prevPendingExits);
- }
+ public void visitTry(JCTry tree) {
+ ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb();
+ Bits uninitsTryPrev = uninitsTry;
+ ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+ pendingExits = new ListBuffer<AssignPendingExit>();
+ Bits initsTry = inits.dup();
+ uninitsTry = uninits.dup();
+ for (JCTree resource : tree.resources) {
+ if (resource instanceof JCVariableDecl) {
+ JCVariableDecl vdecl = (JCVariableDecl) resource;
+ visitVarDef(vdecl);
+ unrefdResources.enter(vdecl.sym);
+ resourceVarDecls.append(vdecl);
+ } else if (resource instanceof JCExpression) {
+ scanExpr((JCExpression) resource);
+ } else {
+ throw new AssertionError(tree); // parser error
+ }
+ }
+ scan(tree.body);
+ uninitsTry.andSet(uninits);
+ Bits initsEnd = inits;
+ Bits uninitsEnd = uninits;
+ int nextadrCatch = nextadr;
+
+ if (!resourceVarDecls.isEmpty() &&
+ lint.isEnabled(Lint.LintCategory.TRY)) {
+ for (JCVariableDecl resVar : resourceVarDecls) {
+ if (unrefdResources.includes(resVar.sym)) {
+ log.warning(Lint.LintCategory.TRY, resVar.pos(),
+ "try.resource.not.referenced", resVar.sym);
+ unrefdResources.remove(resVar.sym);
+ }
+ }
+ }
- public void visitSwitch(JCSwitch tree) {
- ListBuffer<PendingExit> prevPendingExits = pendingExits;
- pendingExits = new ListBuffer<PendingExit>();
- int nextadrPrev = nextadr;
- scanExpr(tree.selector);
- Bits initsSwitch = inits;
- Bits uninitsSwitch = uninits.dup();
- boolean hasDefault = false;
- for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
- alive = true;
- inits = initsSwitch.dup();
- uninits = uninits.andSet(uninitsSwitch);
- JCCase c = l.head;
- if (c.pat == null)
- hasDefault = true;
- else
- scanExpr(c.pat);
- scanStats(c.stats);
- addVars(c.stats, initsSwitch, uninitsSwitch);
- // Warn about fall-through if lint switch fallthrough enabled.
- if (!loopPassTwo &&
- alive &&
- lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
- c.stats.nonEmpty() && l.tail.nonEmpty())
- log.warning(Lint.LintCategory.FALLTHROUGH,
- l.tail.head.pos(),
- "possible.fall-through.into.case");
+ for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
+ JCVariableDecl param = l.head.param;
+ inits = initsTry.dup();
+ uninits = uninitsTry.dup();
+ scan(param);
+ inits.incl(param.sym.adr);
+ uninits.excl(param.sym.adr);
+ scan(l.head.body);
+ initsEnd.andSet(inits);
+ uninitsEnd.andSet(uninits);
+ nextadr = nextadrCatch;
+ }
+ if (tree.finalizer != null) {
+ inits = initsTry.dup();
+ uninits = uninitsTry.dup();
+ ListBuffer<AssignPendingExit> exits = pendingExits;
+ pendingExits = prevPendingExits;
+ scan(tree.finalizer);
+ if (!tree.finallyCanCompleteNormally) {
+ // discard exits and exceptions from try and finally
+ } else {
+ uninits.andSet(uninitsEnd);
+ // FIX: this doesn't preserve source order of exits in catch
+ // versus finally!
+ while (exits.nonEmpty()) {
+ AssignPendingExit exit = exits.next();
+ if (exit.exit_inits != null) {
+ exit.exit_inits.orSet(inits);
+ exit.exit_uninits.andSet(uninits);
+ }
+ pendingExits.append(exit);
+ }
+ inits.orSet(initsEnd);
+ }
+ } else {
+ inits = initsEnd;
+ uninits = uninitsEnd;
+ ListBuffer<AssignPendingExit> exits = pendingExits;
+ pendingExits = prevPendingExits;
+ while (exits.nonEmpty()) pendingExits.append(exits.next());
+ }
+ uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
}
- if (!hasDefault) {
- inits.andSet(initsSwitch);
- alive = true;
- }
- alive |= resolveBreaks(tree, prevPendingExits);
- nextadr = nextadrPrev;
- }
- // where
- /** Add any variables defined in stats to inits and uninits. */
- private static void addVars(List<JCStatement> stats, Bits inits,
- Bits uninits) {
- for (;stats.nonEmpty(); stats = stats.tail) {
- JCTree stat = stats.head;
- if (stat.hasTag(VARDEF)) {
- int adr = ((JCVariableDecl) stat).sym.adr;
- inits.excl(adr);
- uninits.incl(adr);
- }
+
+ public void visitConditional(JCConditional tree) {
+ scanCond(tree.cond);
+ Bits initsBeforeElse = initsWhenFalse;
+ Bits uninitsBeforeElse = uninitsWhenFalse;
+ inits = initsWhenTrue;
+ uninits = uninitsWhenTrue;
+ if (tree.truepart.type.tag == BOOLEAN &&
+ tree.falsepart.type.tag == BOOLEAN) {
+ // if b and c are boolean valued, then
+ // v is (un)assigned after a?b:c when true iff
+ // v is (un)assigned after b when true and
+ // v is (un)assigned after c when true
+ scanCond(tree.truepart);
+ Bits initsAfterThenWhenTrue = initsWhenTrue.dup();
+ Bits initsAfterThenWhenFalse = initsWhenFalse.dup();
+ Bits uninitsAfterThenWhenTrue = uninitsWhenTrue.dup();
+ Bits uninitsAfterThenWhenFalse = uninitsWhenFalse.dup();
+ inits = initsBeforeElse;
+ uninits = uninitsBeforeElse;
+ scanCond(tree.falsepart);
+ initsWhenTrue.andSet(initsAfterThenWhenTrue);
+ initsWhenFalse.andSet(initsAfterThenWhenFalse);
+ uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue);
+ uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse);
+ } else {
+ scanExpr(tree.truepart);
+ Bits initsAfterThen = inits.dup();
+ Bits uninitsAfterThen = uninits.dup();
+ inits = initsBeforeElse;
+ uninits = uninitsBeforeElse;
+ scanExpr(tree.falsepart);
+ inits.andSet(initsAfterThen);
+ uninits.andSet(uninitsAfterThen);
}
}
- public void visitTry(JCTry tree) {
- List<Type> caughtPrev = caught;
- List<Type> thrownPrev = thrown;
- thrown = List.nil();
- for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
- List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
- ((JCTypeUnion)l.head.param.vartype).alternatives :
- List.of(l.head.param.vartype);
- for (JCExpression ct : subClauses) {
- caught = chk.incl(ct.type, caught);
- }
- }
- ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb();
- Bits uninitsTryPrev = uninitsTry;
- ListBuffer<PendingExit> prevPendingExits = pendingExits;
- pendingExits = new ListBuffer<PendingExit>();
- Bits initsTry = inits.dup();
- uninitsTry = uninits.dup();
- for (JCTree resource : tree.resources) {
- if (resource instanceof JCVariableDecl) {
- JCVariableDecl vdecl = (JCVariableDecl) resource;
- visitVarDef(vdecl);
- unrefdResources.enter(vdecl.sym);
- resourceVarDecls.append(vdecl);
- } else if (resource instanceof JCExpression) {
- scanExpr((JCExpression) resource);
+ public void visitIf(JCIf tree) {
+ scanCond(tree.cond);
+ Bits initsBeforeElse = initsWhenFalse;
+ Bits uninitsBeforeElse = uninitsWhenFalse;
+ inits = initsWhenTrue;
+ uninits = uninitsWhenTrue;
+ scan(tree.thenpart);
+ if (tree.elsepart != null) {
+ Bits initsAfterThen = inits.dup();
+ Bits uninitsAfterThen = uninits.dup();
+ inits = initsBeforeElse;
+ uninits = uninitsBeforeElse;
+ scan(tree.elsepart);
+ inits.andSet(initsAfterThen);
+ uninits.andSet(uninitsAfterThen);
} else {
- throw new AssertionError(tree); // parser error
- }
- }
- for (JCTree resource : tree.resources) {
- List<Type> closeableSupertypes = resource.type.isCompound() ?
- types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
- List.of(resource.type);
- for (Type sup : closeableSupertypes) {
- if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
- Symbol closeMethod = rs.resolveQualifiedMethod(tree,
- attrEnv,
- sup,
- names.close,
- List.<Type>nil(),
- List.<Type>nil());
- if (closeMethod.kind == MTH) {
- for (Type t : ((MethodSymbol)closeMethod).getThrownTypes()) {
- markThrown(resource, t);
- }
- }
- }
- }
- }
- scanStat(tree.body);
- List<Type> thrownInTry = allowImprovedCatchAnalysis ?
- chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType)) :
- thrown;
- thrown = thrownPrev;
- caught = caughtPrev;
- boolean aliveEnd = alive;
- uninitsTry.andSet(uninits);
- Bits initsEnd = inits;
- Bits uninitsEnd = uninits;
- int nextadrCatch = nextadr;
-
- if (!resourceVarDecls.isEmpty() &&
- lint.isEnabled(Lint.LintCategory.TRY)) {
- for (JCVariableDecl resVar : resourceVarDecls) {
- if (unrefdResources.includes(resVar.sym)) {
- log.warning(Lint.LintCategory.TRY, resVar.pos(),
- "try.resource.not.referenced", resVar.sym);
- unrefdResources.remove(resVar.sym);
- }
+ inits.andSet(initsBeforeElse);
+ uninits.andSet(uninitsBeforeElse);
}
}
- List<Type> caughtInTry = List.nil();
- for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
- alive = true;
- JCVariableDecl param = l.head.param;
- List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
- ((JCTypeUnion)l.head.param.vartype).alternatives :
- List.of(l.head.param.vartype);
- List<Type> ctypes = List.nil();
- List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
- for (JCExpression ct : subClauses) {
- Type exc = ct.type;
- if (exc != syms.unknownType) {
- ctypes = ctypes.append(exc);
- if (types.isSameType(exc, syms.objectType))
- continue;
- checkCaughtType(l.head.pos(), exc, thrownInTry, caughtInTry);
- caughtInTry = chk.incl(exc, caughtInTry);
- }
+ public void visitBreak(JCBreak tree) {
+ recordExit(tree, new AssignPendingExit(tree, inits, uninits));
+ }
+
+ public void visitContinue(JCContinue tree) {
+ recordExit(tree, new AssignPendingExit(tree, inits, uninits));
+ }
+
+ public void visitReturn(JCReturn tree) {
+ scanExpr(tree.expr);
+ // if not initial constructor, should markDead instead of recordExit
+ recordExit(tree, new AssignPendingExit(tree, inits, uninits));
+ }
+
+ public void visitThrow(JCThrow tree) {
+ scanExpr(tree.expr);
+ markDead();
+ }
+
+ public void visitApply(JCMethodInvocation tree) {
+ scanExpr(tree.meth);
+ scanExprs(tree.args);
+ }
+
+ public void visitNewClass(JCNewClass tree) {
+ scanExpr(tree.encl);
+ scanExprs(tree.args);
+ scan(tree.def);
+ }
+
+ public void visitNewArray(JCNewArray tree) {
+ scanExprs(tree.dims);
+ scanExprs(tree.elems);
+ }
+
+ public void visitAssert(JCAssert tree) {
+ Bits initsExit = inits.dup();
+ Bits uninitsExit = uninits.dup();
+ scanCond(tree.cond);
+ uninitsExit.andSet(uninitsWhenTrue);
+ if (tree.detail != null) {
+ inits = initsWhenFalse;
+ uninits = uninitsWhenFalse;
+ scanExpr(tree.detail);
}
- inits = initsTry.dup();
- uninits = uninitsTry.dup();
- scan(param);
- inits.incl(param.sym.adr);
- uninits.excl(param.sym.adr);
- preciseRethrowTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
- scanStat(l.head.body);
- initsEnd.andSet(inits);
- uninitsEnd.andSet(uninits);
- nextadr = nextadrCatch;
- preciseRethrowTypes.remove(param.sym);
- aliveEnd |= alive;
+ inits = initsExit;
+ uninits = uninitsExit;
+ }
+
+ public void visitAssign(JCAssign tree) {
+ JCTree lhs = TreeInfo.skipParens(tree.lhs);
+ if (!(lhs instanceof JCIdent)) scanExpr(lhs);
+ scanExpr(tree.rhs);
+ letInit(lhs);
+ }
+
+ public void visitAssignop(JCAssignOp tree) {
+ scanExpr(tree.lhs);
+ scanExpr(tree.rhs);
+ letInit(tree.lhs);
+ }
+
+ public void visitUnary(JCUnary tree) {
+ switch (tree.getTag()) {
+ case NOT:
+ scanCond(tree.arg);
+ Bits t = initsWhenFalse;
+ initsWhenFalse = initsWhenTrue;
+ initsWhenTrue = t;
+ t = uninitsWhenFalse;
+ uninitsWhenFalse = uninitsWhenTrue;
+ uninitsWhenTrue = t;
+ break;
+ case PREINC: case POSTINC:
+ case PREDEC: case POSTDEC:
+ scanExpr(tree.arg);
+ letInit(tree.arg);
+ break;
+ default:
+ scanExpr(tree.arg);
+ }
}
- if (tree.finalizer != null) {
- List<Type> savedThrown = thrown;
- thrown = List.nil();
- inits = initsTry.dup();
- uninits = uninitsTry.dup();
- ListBuffer<PendingExit> exits = pendingExits;
- pendingExits = prevPendingExits;
- alive = true;
- scanStat(tree.finalizer);
- if (!alive) {
- // discard exits and exceptions from try and finally
- thrown = chk.union(thrown, thrownPrev);
- if (!loopPassTwo &&
- lint.isEnabled(Lint.LintCategory.FINALLY)) {
- log.warning(Lint.LintCategory.FINALLY,
- TreeInfo.diagEndPos(tree.finalizer),
- "finally.cannot.complete");
- }
- } else {
- thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
- thrown = chk.union(thrown, savedThrown);
- uninits.andSet(uninitsEnd);
- // FIX: this doesn't preserve source order of exits in catch
- // versus finally!
- while (exits.nonEmpty()) {
- PendingExit exit = exits.next();
- if (exit.inits != null) {
- exit.inits.orSet(inits);
- exit.uninits.andSet(uninits);
- }
- pendingExits.append(exit);
- }
- inits.orSet(initsEnd);
- alive = aliveEnd;
+
+ public void visitBinary(JCBinary tree) {
+ switch (tree.getTag()) {
+ case AND:
+ scanCond(tree.lhs);
+ Bits initsWhenFalseLeft = initsWhenFalse;
+ Bits uninitsWhenFalseLeft = uninitsWhenFalse;
+ inits = initsWhenTrue;
+ uninits = uninitsWhenTrue;
+ scanCond(tree.rhs);
+ initsWhenFalse.andSet(initsWhenFalseLeft);
+ uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
+ break;
+ case OR:
+ scanCond(tree.lhs);
+ Bits initsWhenTrueLeft = initsWhenTrue;
+ Bits uninitsWhenTrueLeft = uninitsWhenTrue;
+ inits = initsWhenFalse;
+ uninits = uninitsWhenFalse;
+ scanCond(tree.rhs);
+ initsWhenTrue.andSet(initsWhenTrueLeft);
+ uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
+ break;
+ default:
+ scanExpr(tree.lhs);
+ scanExpr(tree.rhs);
+ }
+ }
+
+ public void visitIdent(JCIdent tree) {
+ if (tree.sym.kind == VAR) {
+ checkInit(tree.pos(), (VarSymbol)tree.sym);
+ referenced(tree.sym);
}
- } else {
- thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
- inits = initsEnd;
- uninits = uninitsEnd;
- alive = aliveEnd;
- ListBuffer<PendingExit> exits = pendingExits;
- pendingExits = prevPendingExits;
- while (exits.nonEmpty()) pendingExits.append(exits.next());
+ }
+
+ void referenced(Symbol sym) {
+ unrefdResources.remove(sym);
}
- uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
- }
+
+ public void visitTopLevel(JCCompilationUnit tree) {
+ // Do nothing for TopLevel since each class is visited individually
+ }
+
+ /**************************************************************************
+ * main method
+ *************************************************************************/
- void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) {
- if (chk.subset(exc, caughtInTry)) {
- log.error(pos, "except.already.caught", exc);
- } else if (!chk.isUnchecked(pos, exc) &&
- !isExceptionOrThrowable(exc) &&
- !chk.intersects(exc, thrownInTry)) {
- log.error(pos, "except.never.thrown.in.try", exc);
- } else if (allowImprovedCatchAnalysis) {
- List<Type> catchableThrownTypes = chk.intersect(List.of(exc), thrownInTry);
- // 'catchableThrownTypes' cannnot possibly be empty - if 'exc' was an
- // unchecked exception, the result list would not be empty, as the augmented
- // thrown set includes { RuntimeException, Error }; if 'exc' was a checked
- // exception, that would have been covered in the branch above
- if (chk.diff(catchableThrownTypes, caughtInTry).isEmpty() &&
- !isExceptionOrThrowable(exc)) {
- String key = catchableThrownTypes.length() == 1 ?
- "unreachable.catch" :
- "unreachable.catch.1";
- log.warning(pos, key, catchableThrownTypes);
+ /** Perform definite assignment/unassignment analysis on a tree.
+ */
+ public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
+ try {
+ attrEnv = env;
+ JCTree tree = env.tree;
+ Flow.this.make = make;
+ inits = new Bits();
+ uninits = new Bits();
+ uninitsTry = new Bits();
+ initsWhenTrue = initsWhenFalse =
+ uninitsWhenTrue = uninitsWhenFalse = null;
+ if (vars == null)
+ vars = new VarSymbol[32];
+ else
+ for (int i=0; i<vars.length; i++)
+ vars[i] = null;
+ firstadr = 0;
+ nextadr = 0;
+ pendingExits = new ListBuffer<AssignPendingExit>();
+ this.classDef = null;
+ unrefdResources = new Scope(env.enclClass.sym);
+ scan(tree);
+ } finally {
+ // note that recursive invocations of this method fail hard
+ inits = uninits = uninitsTry = null;
+ initsWhenTrue = initsWhenFalse =
+ uninitsWhenTrue = uninitsWhenFalse = null;
+ if (vars != null) for (int i=0; i<vars.length; i++)
+ vars[i] = null;
+ firstadr = 0;
+ nextadr = 0;
+ pendingExits = null;
+ Flow.this.make = null;
+ this.classDef = null;
+ unrefdResources = null;
}
}
}
- //where
- private boolean isExceptionOrThrowable(Type exc) {
- return exc.tsym == syms.throwableType.tsym ||
- exc.tsym == syms.exceptionType.tsym;
- }
-
-
- public void visitConditional(JCConditional tree) {
- scanCond(tree.cond);
- Bits initsBeforeElse = initsWhenFalse;
- Bits uninitsBeforeElse = uninitsWhenFalse;
- inits = initsWhenTrue;
- uninits = uninitsWhenTrue;
- if (tree.truepart.type.tag == BOOLEAN &&
- tree.falsepart.type.tag == BOOLEAN) {
- // if b and c are boolean valued, then
- // v is (un)assigned after a?b:c when true iff
- // v is (un)assigned after b when true and
- // v is (un)assigned after c when true
- scanCond(tree.truepart);
- Bits initsAfterThenWhenTrue = initsWhenTrue.dup();
- Bits initsAfterThenWhenFalse = initsWhenFalse.dup();
- Bits uninitsAfterThenWhenTrue = uninitsWhenTrue.dup();
- Bits uninitsAfterThenWhenFalse = uninitsWhenFalse.dup();
- inits = initsBeforeElse;
- uninits = uninitsBeforeElse;
- scanCond(tree.falsepart);
- initsWhenTrue.andSet(initsAfterThenWhenTrue);
- initsWhenFalse.andSet(initsAfterThenWhenFalse);
- uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue);
- uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse);
- } else {
- scanExpr(tree.truepart);
- Bits initsAfterThen = inits.dup();
- Bits uninitsAfterThen = uninits.dup();
- inits = initsBeforeElse;
- uninits = uninitsBeforeElse;
- scanExpr(tree.falsepart);
- inits.andSet(initsAfterThen);
- uninits.andSet(uninitsAfterThen);
- }
- }
-
- public void visitIf(JCIf tree) {
- scanCond(tree.cond);
- Bits initsBeforeElse = initsWhenFalse;
- Bits uninitsBeforeElse = uninitsWhenFalse;
- inits = initsWhenTrue;
- uninits = uninitsWhenTrue;
- scanStat(tree.thenpart);
- if (tree.elsepart != null) {
- boolean aliveAfterThen = alive;
- alive = true;
- Bits initsAfterThen = inits.dup();
- Bits uninitsAfterThen = uninits.dup();
- inits = initsBeforeElse;
- uninits = uninitsBeforeElse;
- scanStat(tree.elsepart);
- inits.andSet(initsAfterThen);
- uninits.andSet(uninitsAfterThen);
- alive = alive | aliveAfterThen;
- } else {
- inits.andSet(initsBeforeElse);
- uninits.andSet(uninitsBeforeElse);
- alive = true;
- }
- }
-
-
-
- public void visitBreak(JCBreak tree) {
- recordExit(tree);
- }
-
- public void visitContinue(JCContinue tree) {
- recordExit(tree);
- }
-
- public void visitReturn(JCReturn tree) {
- scanExpr(tree.expr);
- // if not initial constructor, should markDead instead of recordExit
- recordExit(tree);
- }
-
- public void visitThrow(JCThrow tree) {
- scanExpr(tree.expr);
- Symbol sym = TreeInfo.symbol(tree.expr);
- if (sym != null &&
- sym.kind == VAR &&
- (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 &&
- preciseRethrowTypes.get(sym) != null &&
- allowImprovedRethrowAnalysis) {
- for (Type t : preciseRethrowTypes.get(sym)) {
- markThrown(tree, t);
- }
- }
- else {
- markThrown(tree, tree.expr.type);
- }
- markDead();
- }
-
- public void visitApply(JCMethodInvocation tree) {
- scanExpr(tree.meth);
- scanExprs(tree.args);
- for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail)
- markThrown(tree, l.head);
- }
-
- public void visitNewClass(JCNewClass tree) {
- scanExpr(tree.encl);
- scanExprs(tree.args);
- // scan(tree.def);
- for (List<Type> l = tree.constructorType.getThrownTypes();
- l.nonEmpty();
- l = l.tail) {
- markThrown(tree, l.head);
- }
- List<Type> caughtPrev = caught;
- try {
- // If the new class expression defines an anonymous class,
- // analysis of the anonymous constructor may encounter thrown
- // types which are unsubstituted type variables.
- // However, since the constructor's actual thrown types have
- // already been marked as thrown, it is safe to simply include
- // each of the constructor's formal thrown types in the set of
- // 'caught/declared to be thrown' types, for the duration of
- // the class def analysis.
- if (tree.def != null)
- for (List<Type> l = tree.constructor.type.getThrownTypes();
- l.nonEmpty();
- l = l.tail) {
- caught = chk.incl(l.head, caught);
- }
- scan(tree.def);
- }
- finally {
- caught = caughtPrev;
- }
- }
-
- public void visitNewArray(JCNewArray tree) {
- scanExprs(tree.dims);
- scanExprs(tree.elems);
- }
-
- public void visitAssert(JCAssert tree) {
- Bits initsExit = inits.dup();
- Bits uninitsExit = uninits.dup();
- scanCond(tree.cond);
- uninitsExit.andSet(uninitsWhenTrue);
- if (tree.detail != null) {
- inits = initsWhenFalse;
- uninits = uninitsWhenFalse;
- scanExpr(tree.detail);
- }
- inits = initsExit;
- uninits = uninitsExit;
- }
-
- public void visitAssign(JCAssign tree) {
- JCTree lhs = TreeInfo.skipParens(tree.lhs);
- if (!(lhs instanceof JCIdent)) scanExpr(lhs);
- scanExpr(tree.rhs);
- letInit(lhs);
- }
-
- public void visitAssignop(JCAssignOp tree) {
- scanExpr(tree.lhs);
- scanExpr(tree.rhs);
- letInit(tree.lhs);
- }
-
- public void visitUnary(JCUnary tree) {
- switch (tree.getTag()) {
- case NOT:
- scanCond(tree.arg);
- Bits t = initsWhenFalse;
- initsWhenFalse = initsWhenTrue;
- initsWhenTrue = t;
- t = uninitsWhenFalse;
- uninitsWhenFalse = uninitsWhenTrue;
- uninitsWhenTrue = t;
- break;
- case PREINC: case POSTINC:
- case PREDEC: case POSTDEC:
- scanExpr(tree.arg);
- letInit(tree.arg);
- break;
- default:
- scanExpr(tree.arg);
- }
- }
-
- public void visitBinary(JCBinary tree) {
- switch (tree.getTag()) {
- case AND:
- scanCond(tree.lhs);
- Bits initsWhenFalseLeft = initsWhenFalse;
- Bits uninitsWhenFalseLeft = uninitsWhenFalse;
- inits = initsWhenTrue;
- uninits = uninitsWhenTrue;
- scanCond(tree.rhs);
- initsWhenFalse.andSet(initsWhenFalseLeft);
- uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
- break;
- case OR:
- scanCond(tree.lhs);
- Bits initsWhenTrueLeft = initsWhenTrue;
- Bits uninitsWhenTrueLeft = uninitsWhenTrue;
- inits = initsWhenFalse;
- uninits = uninitsWhenFalse;
- scanCond(tree.rhs);
- initsWhenTrue.andSet(initsWhenTrueLeft);
- uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
- break;
- default:
- scanExpr(tree.lhs);
- scanExpr(tree.rhs);
- }
- }
-
- public void visitIdent(JCIdent tree) {
- if (tree.sym.kind == VAR) {
- checkInit(tree.pos(), (VarSymbol)tree.sym);
- referenced(tree.sym);
- }
- }
-
- void referenced(Symbol sym) {
- unrefdResources.remove(sym);
- }
-
- public void visitTypeCast(JCTypeCast tree) {
- super.visitTypeCast(tree);
- if (!tree.type.isErroneous()
- && lint.isEnabled(Lint.LintCategory.CAST)
- && types.isSameType(tree.expr.type, tree.clazz.type)
- && !is292targetTypeCast(tree)) {
- log.warning(Lint.LintCategory.CAST,
- tree.pos(), "redundant.cast", tree.expr.type);
- }
- }
- //where
- private boolean is292targetTypeCast(JCTypeCast tree) {
- boolean is292targetTypeCast = false;
- JCExpression expr = TreeInfo.skipParens(tree.expr);
- if (expr.hasTag(APPLY)) {
- JCMethodInvocation apply = (JCMethodInvocation)expr;
- Symbol sym = TreeInfo.symbol(apply.meth);
- is292targetTypeCast = sym != null &&
- sym.kind == MTH &&
- (sym.flags() & POLYMORPHIC_SIGNATURE) != 0;
- }
- return is292targetTypeCast;
- }
-
- public void visitTopLevel(JCCompilationUnit tree) {
- // Do nothing for TopLevel since each class is visited individually
- }
-
-/**************************************************************************
- * main method
- *************************************************************************/
-
- /** Perform definite assignment/unassignment analysis on a tree.
- */
- public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
- try {
- attrEnv = env;
- JCTree tree = env.tree;
- this.make = make;
- inits = new Bits();
- uninits = new Bits();
- uninitsTry = new Bits();
- initsWhenTrue = initsWhenFalse =
- uninitsWhenTrue = uninitsWhenFalse = null;
- if (vars == null)
- vars = new VarSymbol[32];
- else
- for (int i=0; i<vars.length; i++)
- vars[i] = null;
- firstadr = 0;
- nextadr = 0;
- pendingExits = new ListBuffer<PendingExit>();
- preciseRethrowTypes = new HashMap<Symbol, List<Type>>();
- alive = true;
- this.thrown = this.caught = null;
- this.classDef = null;
- unrefdResources = new Scope(env.enclClass.sym);
- scan(tree);
- } finally {
- // note that recursive invocations of this method fail hard
- inits = uninits = uninitsTry = null;
- initsWhenTrue = initsWhenFalse =
- uninitsWhenTrue = uninitsWhenFalse = null;
- if (vars != null) for (int i=0; i<vars.length; i++)
- vars[i] = null;
- firstadr = 0;
- nextadr = 0;
- pendingExits = null;
- this.make = null;
- this.thrown = this.caught = null;
- this.classDef = null;
- unrefdResources = null;
- }
- }
}
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java Mon Apr 09 21:58:05 2012 -0700
@@ -347,7 +347,7 @@
that.tvars,
instantiateAsUninferredVars(undetvars, that.tvars));
}
- return chk.checkType(warn.pos(), that.inst(targs, types), to);
+ return that.inst(targs, types);
}
//where
private List<Type> instantiateAsUninferredVars(List<Type> undetvars, List<Type> tvars) {
@@ -603,8 +603,7 @@
* method signature. The target return type is computed from the immediately
* enclosing scope surrounding the polymorphic-signature call.
*/
- Type instantiatePolymorphicSignatureInstance(Env<AttrContext> env, Type site,
- Name name,
+ Type instantiatePolymorphicSignatureInstance(Env<AttrContext> env,
MethodSymbol spMethod, // sig. poly. method or null if none
List<Type> argtypes) {
final Type restype;
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java Mon Apr 09 21:58:05 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -781,20 +781,6 @@
&& s.owner.kind != MTH
&& types.isSameType(c.type, syms.deprecatedType))
s.flags_field |= Flags.DEPRECATED;
- // Internally to java.lang.invoke, a @PolymorphicSignature annotation
- // acts like a classfile attribute.
- if (!c.type.isErroneous() &&
- types.isSameType(c.type, syms.polymorphicSignatureType)) {
- if (!target.hasMethodHandles()) {
- // Somebody is compiling JDK7 source code to a JDK6 target.
- // Make it an error, since it is unlikely but important.
- log.error(env.tree.pos(),
- "wrong.target.for.polymorphic.signature.definition",
- target.name);
- }
- // Pull the flag through for better diagnostics, even on a bad target.
- s.flags_field |= Flags.POLYMORPHIC_SIGNATURE;
- }
if (!annotated.add(a.type.tsym))
log.error(a.pos, "duplicate.annotation");
}
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Apr 09 21:58:05 2012 -0700
@@ -29,6 +29,8 @@
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.comp.Attr.ResultInfo;
+import com.sun.tools.javac.comp.Check.CheckContext;
import com.sun.tools.javac.comp.Resolve.MethodResolutionContext.Candidate;
import com.sun.tools.javac.jvm.*;
import com.sun.tools.javac.tree.*;
@@ -70,6 +72,7 @@
Names names;
Log log;
Symtab syms;
+ Attr attr;
Check chk;
Infer infer;
ClassReader reader;
@@ -101,6 +104,7 @@
names = Names.instance(context);
log = Log.instance(context);
+ attr = Attr.instance(context);
chk = Check.instance(context);
infer = Infer.instance(context);
reader = ClassReader.instance(context);
@@ -395,7 +399,6 @@
else {
Symbol s2 = ((MethodSymbol)sym).implementation(site.tsym, types, true);
return (s2 == null || s2 == sym || sym.owner == s2.owner ||
- s2.isPolymorphicSignatureGeneric() ||
!types.isSubSignature(types.memberType(site, s2), types.memberType(site, sym)));
}
}
@@ -445,7 +448,6 @@
boolean useVarargs,
Warner warn)
throws Infer.InferenceException {
- boolean polymorphicSignature = m.isPolymorphicSignatureGeneric() && allowMethodHandles;
if (useVarargs && (m.flags() & VARARGS) == 0)
throw inapplicableMethodException.setMessage();
Type mt = types.memberType(site, m);
@@ -486,8 +488,7 @@
}
// find out whether we need to go the slow route via infer
- boolean instNeeded = tvars.tail != null || /*inlined: tvars.nonEmpty()*/
- polymorphicSignature;
+ boolean instNeeded = tvars.tail != null; /*inlined: tvars.nonEmpty()*/
for (List<Type> l = argtypes;
l.tail != null/*inlined: l.nonEmpty()*/ && !instNeeded;
l = l.tail) {
@@ -495,9 +496,7 @@
}
if (instNeeded)
- return polymorphicSignature ?
- infer.instantiatePolymorphicSignatureInstance(env, site, m.name, (MethodSymbol)m, argtypes) :
- infer.instantiateMethod(env,
+ return infer.instantiateMethod(env,
tvars,
(MethodType)mt,
m,
@@ -627,15 +626,8 @@
}
while (argtypes.nonEmpty() && formals.head != varargsFormal) {
- Type undetFormal = infer.asUndetType(formals.head, undetvars);
- Type capturedActual = types.capture(argtypes.head);
- boolean works = allowBoxing ?
- types.isConvertible(capturedActual, undetFormal, warn) :
- types.isSubtypeUnchecked(capturedActual, undetFormal, warn);
- if (!works) {
- throw handler.argumentMismatch(false, argtypes.head, formals.head);
- }
- checkedArgs.append(capturedActual);
+ ResultInfo resultInfo = methodCheckResult(formals.head, allowBoxing, false, undetvars, handler, warn);
+ checkedArgs.append(resultInfo.check(env.tree.pos(), argtypes.head));
argtypes = argtypes.tail;
formals = formals.tail;
}
@@ -648,13 +640,9 @@
//note: if applicability check is triggered by most specific test,
//the last argument of a varargs is _not_ an array type (see JLS 15.12.2.5)
Type elt = types.elemtype(varargsFormal);
- Type eltUndet = infer.asUndetType(elt, undetvars);
while (argtypes.nonEmpty()) {
- Type capturedActual = types.capture(argtypes.head);
- if (!types.isConvertible(capturedActual, eltUndet, warn)) {
- throw handler.argumentMismatch(true, argtypes.head, elt);
- }
- checkedArgs.append(capturedActual);
+ ResultInfo resultInfo = methodCheckResult(elt, allowBoxing, true, undetvars, handler, warn);
+ checkedArgs.append(resultInfo.check(env.tree.pos(), argtypes.head));
argtypes = argtypes.tail;
}
//check varargs element type accessibility
@@ -665,39 +653,116 @@
}
return checkedArgs.toList();
}
- // where
- public static class InapplicableMethodException extends RuntimeException {
- private static final long serialVersionUID = 0;
+
+ /**
+ * Check context to be used during method applicability checks. A method check
+ * context might contain inference variables.
+ */
+ abstract class MethodCheckContext implements CheckContext {
+
+ MethodCheckHandler handler;
+ boolean useVarargs;
+ List<Type> undetvars;
+ Warner rsWarner;
- JCDiagnostic diagnostic;
- JCDiagnostic.Factory diags;
+ public MethodCheckContext(MethodCheckHandler handler, boolean useVarargs, List<Type> undetvars, Warner rsWarner) {
+ this.handler = handler;
+ this.useVarargs = useVarargs;
+ this.undetvars = undetvars;
+ this.rsWarner = rsWarner;
+ }
+
+ public void report(DiagnosticPosition pos, Type found, Type req, JCDiagnostic details) {
+ throw handler.argumentMismatch(useVarargs, found, req);
+ }
+
+ public Type rawInstantiatePoly(ForAll found, Type req, Warner warn) {
+ throw new AssertionError("ForAll in argument position");
+ }
+
+ public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) {
+ return rsWarner;
+ }
+ }
- InapplicableMethodException(JCDiagnostic.Factory diags) {
- this.diagnostic = null;
- this.diags = diags;
- }
- InapplicableMethodException setMessage() {
- this.diagnostic = null;
- return this;
+ /**
+ * Subclass of method check context class that implements strict method conversion.
+ * Strict method conversion checks compatibility between types using subtyping tests.
+ */
+ class StrictMethodContext extends MethodCheckContext {
+
+ public StrictMethodContext(MethodCheckHandler handler, boolean useVarargs, List<Type> undetvars, Warner rsWarner) {
+ super(handler, useVarargs, undetvars, rsWarner);
+ }
+
+ public boolean compatible(Type found, Type req, Warner warn) {
+ return types.isSubtypeUnchecked(found, infer.asUndetType(req, undetvars), warn);
+ }
+ }
+
+ /**
+ * Subclass of method check context class that implements loose method conversion.
+ * Loose method conversion checks compatibility between types using method conversion tests.
+ */
+ class LooseMethodContext extends MethodCheckContext {
+
+ public LooseMethodContext(MethodCheckHandler handler, boolean useVarargs, List<Type> undetvars, Warner rsWarner) {
+ super(handler, useVarargs, undetvars, rsWarner);
+ }
+
+ public boolean compatible(Type found, Type req, Warner warn) {
+ return types.isConvertible(found, infer.asUndetType(req, undetvars), warn);
+ }
+ }
+
+ /**
+ * Create a method check context to be used during method applicability check
+ */
+ ResultInfo methodCheckResult(Type to, boolean allowBoxing, boolean useVarargs,
+ List<Type> undetvars, MethodCheckHandler methodHandler, Warner rsWarner) {
+ MethodCheckContext checkContext = allowBoxing ?
+ new LooseMethodContext(methodHandler, useVarargs, undetvars, rsWarner) :
+ new StrictMethodContext(methodHandler, useVarargs, undetvars, rsWarner);
+ return attr.new ResultInfo(VAL, to, checkContext) {
+ @Override
+ protected Type check(DiagnosticPosition pos, Type found) {
+ return super.check(pos, chk.checkNonVoid(pos, types.capture(types.upperBound(found))));
}
- InapplicableMethodException setMessage(String key) {
- this.diagnostic = key != null ? diags.fragment(key) : null;
- return this;
- }
- InapplicableMethodException setMessage(String key, Object... args) {
- this.diagnostic = key != null ? diags.fragment(key, args) : null;
- return this;
- }
- InapplicableMethodException setMessage(JCDiagnostic diag) {
- this.diagnostic = diag;
- return this;
- }
+ };
+ }
+
+ public static class InapplicableMethodException extends RuntimeException {
+ private static final long serialVersionUID = 0;
+
+ JCDiagnostic diagnostic;
+ JCDiagnostic.Factory diags;
- public JCDiagnostic getDiagnostic() {
- return diagnostic;
- }
+ InapplicableMethodException(JCDiagnostic.Factory diags) {
+ this.diagnostic = null;
+ this.diags = diags;
+ }
+ InapplicableMethodException setMessage() {
+ this.diagnostic = null;
+ return this;
+ }
+ InapplicableMethodException setMessage(String key) {
+ this.diagnostic = key != null ? diags.fragment(key) : null;
+ return this;
}
- private final InapplicableMethodException inapplicableMethodException;
+ InapplicableMethodException setMessage(String key, Object... args) {
+ this.diagnostic = key != null ? diags.fragment(key, args) : null;
+ return this;
+ }
+ InapplicableMethodException setMessage(JCDiagnostic diag) {
+ this.diagnostic = diag;
+ return this;
+ }
+
+ public JCDiagnostic getDiagnostic() {
+ return diagnostic;
+ }
+ }
+ private final InapplicableMethodException inapplicableMethodException;
/* ***************************************************************************
* Symbol lookup
@@ -1670,25 +1735,18 @@
steps = steps.tail;
}
if (sym.kind >= AMBIGUOUS) {
- if (site.tsym.isPolymorphicSignatureGeneric()) {
- //polymorphic receiver - synthesize new method symbol
+ //if nothing is found return the 'first' error
+ MethodResolutionPhase errPhase =
+ currentResolutionContext.firstErroneousResolutionPhase();
+ sym = access(currentResolutionContext.resolutionCache.get(errPhase),
+ pos, location, site, name, true, argtypes, typeargtypes);
+ env.info.varArgs = errPhase.isVarargsRequired;
+ } else if (allowMethodHandles) {
+ MethodSymbol msym = (MethodSymbol)sym;
+ if (msym.isSignaturePolymorphic(types)) {
env.info.varArgs = false;
- sym = findPolymorphicSignatureInstance(env,
- site, name, null, argtypes);
+ return findPolymorphicSignatureInstance(env, sym, argtypes);
}
- else {
- //if nothing is found return the 'first' error
- MethodResolutionPhase errPhase =
- currentResolutionContext.firstErroneousResolutionPhase();
- sym = access(currentResolutionContext.resolutionCache.get(errPhase),
- pos, location, site, name, true, argtypes, typeargtypes);
- env.info.varArgs = errPhase.isVarargsRequired;
- }
- } else if (allowMethodHandles && sym.isPolymorphicSignatureGeneric()) {
- //non-instantiated polymorphic signature - synthesize new method symbol
- env.info.varArgs = false;
- sym = findPolymorphicSignatureInstance(env,
- site, name, (MethodSymbol)sym, argtypes);
}
return sym;
}
@@ -1701,40 +1759,25 @@
* Searches in a side table, not the main scope of the site.
* This emulates the lookup process required by JSR 292 in JVM.
* @param env Attribution environment
- * @param site The original type from where the selection takes place.
- * @param name The method's name.
- * @param spMethod A template for the implicit method, or null.
- * @param argtypes The required argument types.
- * @param typeargtypes The required type arguments.
+ * @param spMethod signature polymorphic method - i.e. MH.invokeExact
+ * @param argtypes The required argument types
*/
- Symbol findPolymorphicSignatureInstance(Env<AttrContext> env, Type site,
- Name name,
- MethodSymbol spMethod, // sig. poly. method or null if none
+ Symbol findPolymorphicSignatureInstance(Env<AttrContext> env,
+ Symbol spMethod,
List<Type> argtypes) {
Type mtype = infer.instantiatePolymorphicSignatureInstance(env,
- site, name, spMethod, argtypes);
- long flags = ABSTRACT | HYPOTHETICAL | POLYMORPHIC_SIGNATURE |
- (spMethod != null ?
- spMethod.flags() & Flags.AccessFlags :
- Flags.PUBLIC | Flags.STATIC);
- Symbol m = null;
- for (Scope.Entry e = polymorphicSignatureScope.lookup(name);
- e.scope != null;
- e = e.next()) {
- Symbol sym = e.sym;
- if (types.isSameType(mtype, sym.type) &&
- (sym.flags() & Flags.STATIC) == (flags & Flags.STATIC) &&
- types.isSameType(sym.owner.type, site)) {
- m = sym;
- break;
+ (MethodSymbol)spMethod, argtypes);
+ for (Symbol sym : polymorphicSignatureScope.getElementsByName(spMethod.name)) {
+ if (types.isSameType(mtype, sym.type)) {
+ return sym;
}
}
- if (m == null) {
- // create the desired method
- m = new MethodSymbol(flags, name, mtype, site.tsym);
- polymorphicSignatureScope.enter(m);
- }
- return m;
+
+ // create the desired method
+ long flags = ABSTRACT | HYPOTHETICAL | spMethod.flags() & Flags.AccessFlags;
+ Symbol msym = new MethodSymbol(flags, spMethod.name, mtype, spMethod.owner);
+ polymorphicSignatureScope.enter(msym);
+ return msym;
}
/** Resolve a qualified method identifier, throw a fatal error if not
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Mon Apr 09 21:58:05 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1320,10 +1320,6 @@
sym.flags_field |= PROPRIETARY;
else
proxies.append(proxy);
- if (majorVersion >= V51.major &&
- proxy.type.tsym == syms.polymorphicSignatureType.tsym) {
- sym.flags_field |= POLYMORPHIC_SIGNATURE;
- }
}
annotate.later(new AnnotationCompleter(sym, proxies.toList()));
}
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Mon Apr 09 21:58:05 2012 -0700
@@ -983,12 +983,13 @@
t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos);
break;
}
- } else {
- Assert.check((mode & EXPR) != 0);
+ } else if ((mode & EXPR) != 0) {
mode = EXPR;
JCExpression e = term2Rest(t1, TreeInfo.shiftPrec);
t = F.at(pos1).Binary(op, t, e);
t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
+ } else {
+ accept(GT);
}
} else if ((mode & TYPE) != 0 &&
(token.kind == IDENTIFIER || token.kind == ELLIPSIS)) {
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Mon Apr 09 21:58:05 2012 -0700
@@ -134,12 +134,6 @@
compiler.err.array.req.but.found=\
array required, but {0} found
-compiler.err.assignment.from.super-bound=\
- assigning from wildcard {0}
-
-compiler.err.assignment.to.extends-bound=\
- assigning to wildcard {0}
-
compiler.err.attribute.value.must.be.constant=\
attribute value must be constant
@@ -223,9 +217,6 @@
compiler.err.no.superclass=\
{0} has no superclass
-compiler.err.wrong.target.for.polymorphic.signature.definition=\
- MethodHandle API building requires -target 7 runtimes or better; current is -target {0}
-
# 0: symbol, 1: type, 2: symbol, 3: type, 4: unused
compiler.err.concrete.inheritance.conflict=\
methods {0} from {1} and {2} from {3} are inherited with the same signature
@@ -779,25 +770,23 @@
compiler.err.undef.label=\
undefined label: {0}
-compiler.err.undetermined.type=\
- cannot infer type arguments for {0}
-
-# 0: type, 1: message segment
-compiler.err.undetermined.type.1=\
- cannot infer type arguments for {0};\n\
+# 0: list of type, 1: message segment
+compiler.misc.invalid.inferred.types=\
+ invalid inferred types for {0}\n\
reason: {1}
-# 0: list of type, 1: message segment
-compiler.err.invalid.inferred.types=\
- invalid inferred types for {0}; {1}
-
# 0: message segment, 1: unused
compiler.err.cant.apply.diamond=\
cannot infer type arguments for {0}
# 0: message segment or type, 1: message segment
compiler.err.cant.apply.diamond.1=\
- cannot infer type arguments for {0};\n\
+ cannot infer type arguments for {0}\n\
+ reason: {1}
+
+# 0: message segment or type, 1: message segment
+compiler.misc.cant.apply.diamond.1=\
+ cannot infer type arguments for {0}\n\
reason: {1}
compiler.err.unreachable.stmt=\
@@ -1503,11 +1492,15 @@
#####
-# 0: message segment, 1: type, 2: type
+# 0: type, 1: type
compiler.err.prob.found.req=\
- {0}\n\
- required: {2}\n\
- found: {1}
+ incompatible types\n\
+ required: {1}\n\
+ found: {0}
+
+# 0: message segment
+compiler.err.prob.found.req.1=\
+ incompatible types: {0}
# 0: message segment, 1: type, 2: type
compiler.warn.prob.found.req=\
@@ -1515,22 +1508,9 @@
required: {2}\n\
found: {1}
-compiler.err.prob.found.req.1=\
- {0} {3}\n\
- required: {2}\n\
- found: {1}
-
-## The following are all possible strings for the first argument ({0}) of the
-## above strings.
-compiler.misc.incompatible.types=\
- incompatible types
-
-# 0: message segment
-compiler.misc.incompatible.types.1=\
- incompatible types; {0}
-
+# 0: type, 1: type
compiler.misc.inconvertible.types=\
- inconvertible types
+ {0} cannot be converted to {1}
compiler.misc.possible.loss.of.precision=\
possible loss of precision
@@ -1545,19 +1525,15 @@
compiler.misc.unchecked.cast.to.type=\
unchecked cast
-compiler.misc.assignment.from.super-bound=\
- assignment from super-bound type {0}
-
-compiler.misc.assignment.to.extends-bound=\
- assignment to extends-bound type {0}
-
# compiler.err.star.expected=\
# ''*'' expected
# compiler.err.no.elem.type=\
# \[\*\] cannot have a type
+# 0: type
compiler.misc.try.not.applicable.to.type=\
- try-with-resources not applicable to variable type
+ try-with-resources not applicable to variable type {0}\n\
+ (expected a variable of type java.lang.AutoCloseable)
#####
@@ -1592,8 +1568,11 @@
## The following are all possible strings for the last argument of all those
## diagnostics whose key ends in ".1"
+
+# 0: type, 1: message segment
compiler.misc.undetermined.type=\
- undetermined type
+ cannot infer type arguments for {0}\n\
+ reason: {1}
compiler.misc.type.variable.has.undetermined.type=\
type variable {0} has undetermined type
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java Mon Apr 09 21:58:05 2012 -0700
@@ -1083,6 +1083,7 @@
public List<JCCatch> catchers;
public JCBlock finalizer;
public List<JCTree> resources;
+ public boolean finallyCanCompleteNormally;
protected JCTry(List<JCTree> resources,
JCBlock body,
List<JCCatch> catchers,
--- a/langtools/test/tools/javac/6979683/TestCast6979683_BAD34.java.errlog Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/6979683/TestCast6979683_BAD34.java.errlog Mon Apr 09 21:58:05 2012 -0700
@@ -1,2 +1,2 @@
-TestCast6979683_BAD34.java:34:49: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.lang.Number, boolean
+TestCast6979683_BAD34.java:34:49: compiler.err.prob.found.req: java.lang.Number, boolean
1 error
--- a/langtools/test/tools/javac/6979683/TestCast6979683_BAD35.java.errlog Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/6979683/TestCast6979683_BAD35.java.errlog Mon Apr 09 21:58:05 2012 -0700
@@ -1,2 +1,2 @@
-TestCast6979683_BAD35.java:35:45: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.lang.Number, int
+TestCast6979683_BAD35.java:35:45: compiler.err.prob.found.req: java.lang.Number, int
1 error
--- a/langtools/test/tools/javac/6979683/TestCast6979683_BAD36.java.errlog Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/6979683/TestCast6979683_BAD36.java.errlog Mon Apr 09 21:58:05 2012 -0700
@@ -1,2 +1,2 @@
-TestCast6979683_BAD36.java:36:58: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.lang.Comparable<java.lang.Integer>, int
+TestCast6979683_BAD36.java:36:58: compiler.err.prob.found.req: java.lang.Comparable<java.lang.Integer>, int
1 error
--- a/langtools/test/tools/javac/6979683/TestCast6979683_BAD37.java.errlog Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/6979683/TestCast6979683_BAD37.java.errlog Mon Apr 09 21:58:05 2012 -0700
@@ -1,2 +1,2 @@
-TestCast6979683_BAD37.java:37:61: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), java.lang.Comparable<java.lang.Short>, int
+TestCast6979683_BAD37.java:37:61: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: java.lang.Comparable<java.lang.Short>, int)
1 error
--- a/langtools/test/tools/javac/6979683/TestCast6979683_BAD38.java.errlog Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/6979683/TestCast6979683_BAD38.java.errlog Mon Apr 09 21:58:05 2012 -0700
@@ -1,2 +1,2 @@
-TestCast6979683_BAD38.java:38:62: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.lang.Comparable<java.lang.Character>, float
+TestCast6979683_BAD38.java:38:62: compiler.err.prob.found.req: java.lang.Comparable<java.lang.Character>, float
1 error
--- a/langtools/test/tools/javac/6979683/TestCast6979683_BAD39.java.errlog Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/6979683/TestCast6979683_BAD39.java.errlog Mon Apr 09 21:58:05 2012 -0700
@@ -1,2 +1,2 @@
-TestCast6979683_BAD39.java:39:53: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), java.lang.Number, char
+TestCast6979683_BAD39.java:39:53: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: java.lang.Number, char)
1 error
--- a/langtools/test/tools/javac/Diagnostics/6722234/T6722234d_1.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/Diagnostics/6722234/T6722234d_1.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,3 +1,3 @@
-T6722234d.java:18:20: compiler.err.prob.found.req: (compiler.misc.incompatible.types), compiler.misc.intersection.type: 1, T6722234d.A
+T6722234d.java:18:20: compiler.err.prob.found.req: compiler.misc.intersection.type: 1, T6722234d.A
- compiler.misc.where.description.intersection: compiler.misc.intersection.type: 1,{(compiler.misc.where.intersection: compiler.misc.intersection.type: 1, java.lang.Object,T6722234d.I1,T6722234d.I2)}
1 error
--- a/langtools/test/tools/javac/Diagnostics/6722234/T6722234d_2.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/Diagnostics/6722234/T6722234d_2.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,3 +1,3 @@
-T6722234d.java:18:20: compiler.err.prob.found.req: (compiler.misc.incompatible.types), compiler.misc.intersection.type: 1, T6722234d.A
+T6722234d.java:18:20: compiler.err.prob.found.req: compiler.misc.intersection.type: 1, T6722234d.A
- compiler.misc.where.description.intersection: compiler.misc.intersection.type: 1,{(compiler.misc.where.intersection: compiler.misc.intersection.type: 1, Object,I1,I2)}
1 error
--- a/langtools/test/tools/javac/OverrideChecks/6400189/T6400189a.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/OverrideChecks/6400189/T6400189a.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,4 +1,4 @@
T6400189a.java:14:35: compiler.warn.unchecked.call.mbr.of.raw.type: <T>getAnnotation(java.lang.Class<T>), java.lang.reflect.Constructor
-T6400189a.java:14:35: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.lang.annotation.Annotation, java.lang.annotation.Documented
+T6400189a.java:14:35: compiler.err.prob.found.req: java.lang.annotation.Annotation, java.lang.annotation.Documented
1 error
1 warning
--- a/langtools/test/tools/javac/OverrideChecks/6400189/T6400189b.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/OverrideChecks/6400189/T6400189b.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,4 +1,4 @@
T6400189b.java:24:24: compiler.warn.unchecked.call.mbr.of.raw.type: <T>m(T6400189b<T>), T6400189b.B
-T6400189b.java:24:24: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.lang.Object, java.lang.Integer
+T6400189b.java:24:24: compiler.err.prob.found.req: java.lang.Object, java.lang.Integer
1 error
1 warning
--- a/langtools/test/tools/javac/StringsInSwitch/BadlyTypedLabel1.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/StringsInSwitch/BadlyTypedLabel1.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,2 +1,2 @@
-BadlyTypedLabel1.java:13:14: compiler.err.prob.found.req: (compiler.misc.incompatible.types), int, java.lang.String
+BadlyTypedLabel1.java:13:14: compiler.err.prob.found.req: int, java.lang.String
1 error
--- a/langtools/test/tools/javac/StringsInSwitch/BadlyTypedLabel2.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/StringsInSwitch/BadlyTypedLabel2.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,2 +1,2 @@
-BadlyTypedLabel2.java:15:14: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.math.RoundingMode, java.lang.String
+BadlyTypedLabel2.java:15:14: compiler.err.prob.found.req: java.math.RoundingMode, java.lang.String
1 error
--- a/langtools/test/tools/javac/T6326754.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/T6326754.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,6 +1,6 @@
T6326754.java:44:12: compiler.err.name.clash.same.erasure: TestConstructor(T), TestConstructor(K)
T6326754.java:52:17: compiler.err.name.clash.same.erasure: setT(K), setT(T)
-T6326754.java:64:18: compiler.err.prob.found.req: (compiler.misc.incompatible.types), T, T
+T6326754.java:64:18: compiler.err.prob.found.req: T, T
T6326754.java:70:11: compiler.err.cant.apply.symbol.1: kindname.method, setT, java.lang.Object, compiler.misc.no.args, kindname.class, TestC<T>, (compiler.misc.arg.length.mismatch)
- compiler.note.unchecked.filename: T6326754.java
- compiler.note.unchecked.recompile
--- a/langtools/test/tools/javac/TryWithResources/TwrOnNonResource.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/TryWithResources/TwrOnNonResource.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,4 +1,4 @@
-TwrOnNonResource.java:12:30: compiler.err.prob.found.req: (compiler.misc.try.not.applicable.to.type), TwrOnNonResource, java.lang.AutoCloseable
-TwrOnNonResource.java:15:30: compiler.err.prob.found.req: (compiler.misc.try.not.applicable.to.type), TwrOnNonResource, java.lang.AutoCloseable
-TwrOnNonResource.java:18:30: compiler.err.prob.found.req: (compiler.misc.try.not.applicable.to.type), TwrOnNonResource, java.lang.AutoCloseable
+TwrOnNonResource.java:12:30: compiler.err.prob.found.req.1: (compiler.misc.try.not.applicable.to.type: TwrOnNonResource)
+TwrOnNonResource.java:15:30: compiler.err.prob.found.req.1: (compiler.misc.try.not.applicable.to.type: TwrOnNonResource)
+TwrOnNonResource.java:18:30: compiler.err.prob.found.req.1: (compiler.misc.try.not.applicable.to.type: TwrOnNonResource)
3 errors
--- a/langtools/test/tools/javac/cast/6270087/T6270087neg.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/cast/6270087/T6270087neg.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,2 +1,2 @@
-T6270087neg.java:36:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6270087neg.Foo<V>, T6270087neg.Foo<U>
+T6270087neg.java:36:29: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: T6270087neg.Foo<V>, T6270087neg.Foo<U>)
1 error
--- a/langtools/test/tools/javac/cast/6557182/T6557182.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/cast/6557182/T6557182.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,4 +1,4 @@
-T6557182.java:12:56: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T, java.lang.Comparable<java.lang.Integer>
+T6557182.java:12:56: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: T, java.lang.Comparable<java.lang.Integer>)
T6557182.java:16:56: compiler.warn.prob.found.req: (compiler.misc.unchecked.cast.to.type), T, java.lang.Comparable<java.lang.Integer>
1 error
1 warning
--- a/langtools/test/tools/javac/cast/6665356/T6665356.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/cast/6665356/T6665356.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,8 +1,8 @@
-T6665356.java:31:55: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<? super java.lang.Number>.Inner<java.lang.Long>
-T6665356.java:35:58: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<java.lang.Integer>.Inner<? super java.lang.Number>
-T6665356.java:39:65: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<? super java.lang.Number>.Inner<? super java.lang.Number>
-T6665356.java:43:57: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<? extends java.lang.String>.Inner<java.lang.Long>
-T6665356.java:47:60: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<java.lang.Integer>.Inner<? extends java.lang.String>
-T6665356.java:51:55: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<? super java.lang.String>.Inner<java.lang.Long>
-T6665356.java:55:58: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<java.lang.Integer>.Inner<? super java.lang.String>
+T6665356.java:31:55: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<? super java.lang.Number>.Inner<java.lang.Long>)
+T6665356.java:35:58: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<java.lang.Integer>.Inner<? super java.lang.Number>)
+T6665356.java:39:65: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<? super java.lang.Number>.Inner<? super java.lang.Number>)
+T6665356.java:43:57: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<? extends java.lang.String>.Inner<java.lang.Long>)
+T6665356.java:47:60: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<java.lang.Integer>.Inner<? extends java.lang.String>)
+T6665356.java:51:55: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<? super java.lang.String>.Inner<java.lang.Long>)
+T6665356.java:55:58: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: T6665356.Outer<java.lang.Integer>.Inner<java.lang.Long>, T6665356.Outer<java.lang.Integer>.Inner<? super java.lang.String>)
7 errors
--- a/langtools/test/tools/javac/cast/6795580/T6795580.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/cast/6795580/T6795580.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,8 +1,8 @@
-T6795580.java:31:57: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<? super java.lang.Number>.Inner<java.lang.Long>[]
-T6795580.java:35:60: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<java.lang.Integer>.Inner<? super java.lang.Number>[]
-T6795580.java:39:67: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<? super java.lang.Number>.Inner<? super java.lang.Number>[]
-T6795580.java:43:59: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<? extends java.lang.String>.Inner<java.lang.Long>[]
-T6795580.java:47:62: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<java.lang.Integer>.Inner<? extends java.lang.String>[]
-T6795580.java:51:57: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<? super java.lang.String>.Inner<java.lang.Long>[]
-T6795580.java:55:60: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<java.lang.Integer>.Inner<? super java.lang.String>[]
+T6795580.java:31:57: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<? super java.lang.Number>.Inner<java.lang.Long>[])
+T6795580.java:35:60: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<java.lang.Integer>.Inner<? super java.lang.Number>[])
+T6795580.java:39:67: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<? super java.lang.Number>.Inner<? super java.lang.Number>[])
+T6795580.java:43:59: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<? extends java.lang.String>.Inner<java.lang.Long>[])
+T6795580.java:47:62: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<java.lang.Integer>.Inner<? extends java.lang.String>[])
+T6795580.java:51:57: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<? super java.lang.String>.Inner<java.lang.Long>[])
+T6795580.java:55:60: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: T6795580.Outer<java.lang.Integer>.Inner<java.lang.Long>[], T6795580.Outer<java.lang.Integer>.Inner<? super java.lang.String>[])
7 errors
--- a/langtools/test/tools/javac/cast/6932571/T6932571neg.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/cast/6932571/T6932571neg.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,2 +1,2 @@
-T6932571neg.java:39:19: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6932571neg.S, G
+T6932571neg.java:39:19: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: T6932571neg.S, G)
1 error
--- a/langtools/test/tools/javac/cast/7005095/T7005095neg.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/cast/7005095/T7005095neg.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,2 +1,2 @@
-T7005095neg.java:13:25: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T7005095pos.FooImpl, T7005095pos.Foo<T>
+T7005095neg.java:13:25: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: T7005095pos.FooImpl, T7005095pos.Foo<T>)
1 error
--- a/langtools/test/tools/javac/cast/7005671/T7005671.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/cast/7005671/T7005671.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,17 +1,17 @@
-T7005671.java:12:26: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), byte[], X[]
-T7005671.java:13:26: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), short[], X[]
-T7005671.java:14:26: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), int[], X[]
-T7005671.java:15:26: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), long[], X[]
-T7005671.java:16:26: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), float[], X[]
-T7005671.java:17:26: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), double[], X[]
-T7005671.java:18:26: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), char[], X[]
-T7005671.java:19:26: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), boolean[], X[]
-T7005671.java:23:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), X[], byte[]
-T7005671.java:24:30: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), X[], short[]
-T7005671.java:25:28: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), X[], int[]
-T7005671.java:26:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), X[], long[]
-T7005671.java:27:30: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), X[], float[]
-T7005671.java:28:31: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), X[], double[]
-T7005671.java:29:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), X[], char[]
-T7005671.java:30:32: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), X[], boolean[]
+T7005671.java:12:26: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: byte[], X[])
+T7005671.java:13:26: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: short[], X[])
+T7005671.java:14:26: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: int[], X[])
+T7005671.java:15:26: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: long[], X[])
+T7005671.java:16:26: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: float[], X[])
+T7005671.java:17:26: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: double[], X[])
+T7005671.java:18:26: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: char[], X[])
+T7005671.java:19:26: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: boolean[], X[])
+T7005671.java:23:29: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: X[], byte[])
+T7005671.java:24:30: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: X[], short[])
+T7005671.java:25:28: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: X[], int[])
+T7005671.java:26:29: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: X[], long[])
+T7005671.java:27:30: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: X[], float[])
+T7005671.java:28:31: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: X[], double[])
+T7005671.java:29:29: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: X[], char[])
+T7005671.java:30:32: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: X[], boolean[])
16 errors
--- a/langtools/test/tools/javac/diags/examples.not-yet.txt Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/diags/examples.not-yet.txt Mon Apr 09 21:58:05 2012 -0700
@@ -1,8 +1,6 @@
compiler.err.already.annotated # internal compiler error?
compiler.err.already.defined.this.unit # seems to be masked by compiler.err.duplicate.class
compiler.err.annotation.value.not.allowable.type # cannot happen: precluded by complete type-specific tests
-compiler.err.assignment.from.super-bound # DEAD
-compiler.err.assignment.to.extends-bound # DEAD
compiler.err.cant.apply.symbol
compiler.err.cant.read.file # (apt.JavaCompiler?)
compiler.err.cant.select.static.class.from.param.type
@@ -24,7 +22,6 @@
compiler.err.no.encl.instance.of.type.in.scope # cannot occur; always followed by assert false;
compiler.err.no.match.entry # UNUSED?
compiler.err.not.annotation.type # cannot occur given preceding checkType
-compiler.err.prob.found.req.1 # Check: DEAD, in unused method
compiler.err.proc.bad.config.file # JavacProcessingEnvironment
compiler.err.proc.cant.access # completion failure
compiler.err.proc.cant.access.1 # completion failure, no stack trace
@@ -38,12 +35,8 @@
compiler.err.stack.sim.error
compiler.err.type.var.more.than.once # UNUSED
compiler.err.type.var.more.than.once.in.result # UNUSED
-compiler.err.undetermined.type
compiler.err.unexpected.type
compiler.err.unsupported.cross.fp.lit # Scanner: host system dependent
-compiler.err.wrong.target.for.polymorphic.signature.definition # Transitional 292
-compiler.misc.assignment.from.super-bound
-compiler.misc.assignment.to.extends-bound
compiler.misc.bad.class.file.header # bad class file
compiler.misc.bad.class.signature # bad class file
compiler.misc.bad.const.pool.tag # bad class file
@@ -88,7 +81,6 @@
compiler.misc.type.variable.has.undetermined.type
compiler.misc.unable.to.access.file # ClassFile
compiler.misc.undecl.type.var # ClassReader
-compiler.misc.undetermined.type
compiler.misc.unicode.str.not.supported # ClassReader
compiler.misc.verbose.retro # UNUSED
compiler.misc.verbose.retro.with # UNUSED
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/CantApplyDiamond1.java Mon Apr 09 21:58:05 2012 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.prob.found.req.1
+// key: compiler.misc.cant.apply.diamond.1
+// key: compiler.misc.infer.no.conforming.instance.exists
+// key: compiler.misc.diamond
+
+class CantApplyDiamond1<X> {
+
+ CantApplyDiamond1(CantApplyDiamond1<? super X> lz) { }
+
+ void test(CantApplyDiamond1<Integer> li) {
+ CantApplyDiamond1<String> ls = new CantApplyDiamond1<>(li);
+ }
+}
--- a/langtools/test/tools/javac/diags/examples/IncompatibleTypes1.java Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/diags/examples/IncompatibleTypes1.java Mon Apr 09 21:58:05 2012 -0700
@@ -21,9 +21,8 @@
* questions.
*/
-// key: compiler.misc.incompatible.types.1
// key: compiler.misc.infer.no.conforming.instance.exists
-// key: compiler.err.prob.found.req
+// key: compiler.err.prob.found.req.1
class IncompatibleTypes1<V> {
<T extends Integer & Runnable> IncompatibleTypes1<T> m() {
--- a/langtools/test/tools/javac/diags/examples/InconvertibleTypes.java Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/diags/examples/InconvertibleTypes.java Mon Apr 09 21:58:05 2012 -0700
@@ -22,7 +22,7 @@
*/
// key: compiler.misc.inconvertible.types
-// key: compiler.err.prob.found.req
+// key: compiler.err.prob.found.req.1
class InconvertibleTypes {
class Outer<S> {
--- a/langtools/test/tools/javac/diags/examples/InvalidInferredTypes.java Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/diags/examples/InvalidInferredTypes.java Mon Apr 09 21:58:05 2012 -0700
@@ -21,7 +21,8 @@
* questions.
*/
-// key: compiler.err.invalid.inferred.types
+// key: compiler.err.prob.found.req.1
+// key: compiler.misc.invalid.inferred.types
// key: compiler.misc.inferred.do.not.conform.to.bounds
import java.util.*;
--- a/langtools/test/tools/javac/diags/examples/PossibleLossPrecision.java Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/diags/examples/PossibleLossPrecision.java Mon Apr 09 21:58:05 2012 -0700
@@ -22,7 +22,7 @@
*/
// key: compiler.misc.possible.loss.of.precision
-// key: compiler.err.prob.found.req
+// key: compiler.err.prob.found.req.1
class PossibleLossPrecision {
long l;
--- a/langtools/test/tools/javac/diags/examples/ResourceNotApplicableToType.java Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/diags/examples/ResourceNotApplicableToType.java Mon Apr 09 21:58:05 2012 -0700
@@ -22,7 +22,7 @@
*/
// key: compiler.misc.try.not.applicable.to.type
-// key: compiler.err.prob.found.req
+// key: compiler.err.prob.found.req.1
class ResourceNotApplicableToType {
void m() {
--- a/langtools/test/tools/javac/diags/examples/UndeterminedType1.java Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/diags/examples/UndeterminedType1.java Mon Apr 09 21:58:05 2012 -0700
@@ -21,7 +21,8 @@
* questions.
*/
-// key: compiler.err.undetermined.type.1
+// key: compiler.err.prob.found.req.1
+// key: compiler.misc.undetermined.type
// key: compiler.misc.no.unique.maximal.instance.exists
class UndeterminedType1<V> {
--- a/langtools/test/tools/javac/diags/examples/WhereIntersection.java Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/diags/examples/WhereIntersection.java Mon Apr 09 21:58:05 2012 -0700
@@ -24,7 +24,6 @@
// key: compiler.misc.where.intersection
// key: compiler.misc.where.description.intersection
// key: compiler.misc.intersection.type
-// key: compiler.misc.incompatible.types
// key: compiler.err.prob.found.req
// options: -XDdiags=where
// run: simple
--- a/langtools/test/tools/javac/generics/6207386/T6207386.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/generics/6207386/T6207386.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,2 +1,2 @@
-T6207386.java:13:30: compiler.err.prob.found.req: (compiler.misc.incompatible.types), X, T6207386.F<? super X>
+T6207386.java:13:30: compiler.err.prob.found.req: X, T6207386.F<? super X>
1 error
--- a/langtools/test/tools/javac/generics/diamond/neg/Neg05.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/generics/diamond/neg/Neg05.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,19 +1,19 @@
Neg05.java:19:48: compiler.err.improperly.formed.type.inner.raw.param
-Neg05.java:19:35: compiler.err.prob.found.req: (compiler.misc.incompatible.types), Neg05.Foo<java.lang.String>, Neg05<?>.Foo<java.lang.String>
+Neg05.java:19:35: compiler.err.prob.found.req: Neg05.Foo<java.lang.String>, Neg05<?>.Foo<java.lang.String>
Neg05.java:20:58: compiler.err.improperly.formed.type.inner.raw.param
-Neg05.java:20:45: compiler.err.prob.found.req: (compiler.misc.incompatible.types), Neg05.Foo<java.lang.String>, Neg05<?>.Foo<? extends java.lang.String>
+Neg05.java:20:45: compiler.err.prob.found.req: Neg05.Foo<java.lang.String>, Neg05<?>.Foo<? extends java.lang.String>
Neg05.java:21:43: compiler.err.improperly.formed.type.inner.raw.param
-Neg05.java:21:30: compiler.err.prob.found.req: (compiler.misc.incompatible.types), Neg05.Foo<java.lang.String>, Neg05<?>.Foo<?>
+Neg05.java:21:30: compiler.err.prob.found.req: Neg05.Foo<java.lang.String>, Neg05<?>.Foo<?>
Neg05.java:22:56: compiler.err.improperly.formed.type.inner.raw.param
-Neg05.java:22:43: compiler.err.prob.found.req: (compiler.misc.incompatible.types), Neg05.Foo<java.lang.String>, Neg05<?>.Foo<? super java.lang.String>
+Neg05.java:22:43: compiler.err.prob.found.req: Neg05.Foo<java.lang.String>, Neg05<?>.Foo<? super java.lang.String>
Neg05.java:24:48: compiler.err.improperly.formed.type.inner.raw.param
-Neg05.java:24:35: compiler.err.prob.found.req: (compiler.misc.incompatible.types), Neg05.Foo<java.lang.String>, Neg05<?>.Foo<java.lang.String>
+Neg05.java:24:35: compiler.err.prob.found.req: Neg05.Foo<java.lang.String>, Neg05<?>.Foo<java.lang.String>
Neg05.java:25:58: compiler.err.improperly.formed.type.inner.raw.param
-Neg05.java:25:45: compiler.err.prob.found.req: (compiler.misc.incompatible.types), Neg05.Foo<java.lang.String>, Neg05<?>.Foo<? extends java.lang.String>
+Neg05.java:25:45: compiler.err.prob.found.req: Neg05.Foo<java.lang.String>, Neg05<?>.Foo<? extends java.lang.String>
Neg05.java:26:43: compiler.err.improperly.formed.type.inner.raw.param
-Neg05.java:26:30: compiler.err.prob.found.req: (compiler.misc.incompatible.types), Neg05.Foo<java.lang.String>, Neg05<?>.Foo<?>
+Neg05.java:26:30: compiler.err.prob.found.req: Neg05.Foo<java.lang.String>, Neg05<?>.Foo<?>
Neg05.java:27:56: compiler.err.improperly.formed.type.inner.raw.param
-Neg05.java:27:43: compiler.err.prob.found.req: (compiler.misc.incompatible.types), Neg05.Foo<java.lang.String>, Neg05<?>.Foo<? super java.lang.String>
+Neg05.java:27:43: compiler.err.prob.found.req: Neg05.Foo<java.lang.String>, Neg05<?>.Foo<? super java.lang.String>
Neg05.java:31:37: compiler.err.improperly.formed.type.inner.raw.param
Neg05.java:32:47: compiler.err.improperly.formed.type.inner.raw.param
Neg05.java:33:32: compiler.err.improperly.formed.type.inner.raw.param
--- a/langtools/test/tools/javac/generics/diamond/neg/Neg06.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/generics/diamond/neg/Neg06.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,2 +1,2 @@
-Neg06.java:16:37: compiler.err.cant.apply.diamond.1: (compiler.misc.diamond: Neg06.CFoo), (compiler.misc.infer.no.conforming.instance.exists: X, Neg06.CFoo<X>, Neg06.CSuperFoo<java.lang.String>)
+Neg06.java:16:37: compiler.err.prob.found.req.1: (compiler.misc.cant.apply.diamond.1: (compiler.misc.diamond: Neg06.CFoo), (compiler.misc.infer.no.conforming.instance.exists: X, Neg06.CFoo<X>, Neg06.CSuperFoo<java.lang.String>))
1 error
--- a/langtools/test/tools/javac/generics/diamond/neg/Neg10.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/generics/diamond/neg/Neg10.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,2 +1,2 @@
-Neg10.java:16:22: compiler.err.prob.found.req: (compiler.misc.incompatible.types), Neg10.Foo<java.lang.Integer>, Neg10.Foo<java.lang.Number>
+Neg10.java:16:22: compiler.err.prob.found.req: Neg10.Foo<java.lang.Integer>, Neg10.Foo<java.lang.Number>
1 error
--- a/langtools/test/tools/javac/generics/inference/6315770/T6315770.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/generics/inference/6315770/T6315770.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,3 +1,3 @@
-T6315770.java:16:42: compiler.err.undetermined.type.1: <T>T6315770<T>, (compiler.misc.no.unique.maximal.instance.exists: T, java.lang.String,java.lang.Integer,java.lang.Runnable)
-T6315770.java:17:40: compiler.err.prob.found.req: (compiler.misc.incompatible.types.1: (compiler.misc.infer.no.conforming.instance.exists: T, T6315770<T>, T6315770<? super java.lang.String>)), <T>T6315770<T>, T6315770<? super java.lang.String>
+T6315770.java:16:42: compiler.err.prob.found.req.1: (compiler.misc.undetermined.type: <T>T6315770<T>, (compiler.misc.no.unique.maximal.instance.exists: T, java.lang.String,java.lang.Integer,java.lang.Runnable))
+T6315770.java:17:40: compiler.err.prob.found.req.1: (compiler.misc.infer.no.conforming.instance.exists: T, T6315770<T>, T6315770<? super java.lang.String>)
2 errors
--- a/langtools/test/tools/javac/generics/inference/6638712/T6638712b.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/generics/inference/6638712/T6638712b.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,2 +1,2 @@
-T6638712b.java:14:21: compiler.err.prob.found.req: (compiler.misc.incompatible.types.1: (compiler.misc.infer.no.conforming.instance.exists: T, T, java.lang.String)), <T>T, java.lang.String
+T6638712b.java:14:21: compiler.err.prob.found.req.1: (compiler.misc.infer.no.conforming.instance.exists: T, T, java.lang.String)
1 error
--- a/langtools/test/tools/javac/generics/inference/6638712/T6638712e.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/generics/inference/6638712/T6638712e.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,2 +1,2 @@
-T6638712e.java:17:27: compiler.err.prob.found.req: (compiler.misc.incompatible.types.1: (compiler.misc.infer.no.conforming.instance.exists: X, T6638712e.Foo<X,java.lang.String>, T6638712e.Foo<java.lang.Object,java.lang.String>)), <X>T6638712e.Foo<X,java.lang.String>, T6638712e.Foo<java.lang.Object,java.lang.String>
+T6638712e.java:17:27: compiler.err.prob.found.req.1: (compiler.misc.infer.no.conforming.instance.exists: X, T6638712e.Foo<X,java.lang.String>, T6638712e.Foo<java.lang.Object,java.lang.String>)
1 error
--- a/langtools/test/tools/javac/generics/inference/6650759/T6650759m.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/generics/inference/6650759/T6650759m.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,2 +1,2 @@
-T6650759m.java:43:36: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.util.List<? super java.lang.Integer>, java.util.List<? super java.lang.String>
+T6650759m.java:43:36: compiler.err.prob.found.req: java.util.List<? super java.lang.Integer>, java.util.List<? super java.lang.String>
1 error
--- a/langtools/test/tools/javac/generics/rawOverride/7062745/T7062745neg.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/generics/rawOverride/7062745/T7062745neg.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,2 +1,2 @@
-T7062745neg.java:16:36: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.lang.Object, java.lang.Number
+T7062745neg.java:16:36: compiler.err.prob.found.req: java.lang.Object, java.lang.Number
1 error
--- a/langtools/test/tools/javac/generics/wildcards/6886247/T6886247_2.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/generics/wildcards/6886247/T6886247_2.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,2 +1,2 @@
-T6886247_2.java:35:28: compiler.err.prob.found.req: (compiler.misc.incompatible.types), compiler.misc.type.captureof: 1, ?, E
+T6886247_2.java:35:28: compiler.err.prob.found.req: compiler.misc.type.captureof: 1, ?, E
1 error
--- a/langtools/test/tools/javac/multicatch/Neg06.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/multicatch/Neg06.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,3 +1,3 @@
-Neg06.java:14:16: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.lang.String, java.lang.Throwable
-Neg06.java:14:25: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.lang.Integer, java.lang.Throwable
+Neg06.java:14:16: compiler.err.prob.found.req: java.lang.String, java.lang.Throwable
+Neg06.java:14:25: compiler.err.prob.found.req: java.lang.Integer, java.lang.Throwable
2 errors
--- a/langtools/test/tools/javac/multicatch/Neg07.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/multicatch/Neg07.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,2 +1,2 @@
-Neg07.java:14:56: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.lang.Class<compiler.misc.type.captureof: 1, ? extends Neg07.ParentException>, java.lang.Class<? extends Neg07.HasFoo>
+Neg07.java:14:56: compiler.err.prob.found.req: java.lang.Class<compiler.misc.type.captureof: 1, ? extends Neg07.ParentException>, java.lang.Class<? extends Neg07.HasFoo>
1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/parser/7157165/T7157165.java Mon Apr 09 21:58:05 2012 -0700
@@ -0,0 +1,12 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 7157165
+ *
+ * @summary Regression: code with disjunctive type crashes javac
+ * @compile/fail/ref=T7157165.out -XDrawDiagnostics T7157165.java
+ *
+ */
+
+class T7157165 {
+ Foo<? extends A|B> foo1 = null;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/parser/7157165/T7157165.out Mon Apr 09 21:58:05 2012 -0700
@@ -0,0 +1,4 @@
+T7157165.java:11:20: compiler.err.expected: >
+T7157165.java:11:21: compiler.err.expected: ';'
+T7157165.java:11:22: compiler.err.illegal.start.of.type
+3 errors
--- a/langtools/test/tools/javac/processing/TestWarnErrorCount.java Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/processing/TestWarnErrorCount.java Mon Apr 09 21:58:05 2012 -0700
@@ -327,7 +327,7 @@
Writer out = fo.openWriter();
try {
out.write("class " + name + " {\n"
- + (warn ? " int i = (int) 0;\n" : "")
+ + (warn ? " void m() throws Exception { try (AutoCloseable ac = null) { } }" : "")
+ (error ? " ERROR\n" : "")
+ "}\n");
} finally {
--- a/langtools/test/tools/javac/types/CastObjectToPrimitiveTest.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/types/CastObjectToPrimitiveTest.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,2 +1,2 @@
-CastObjectToPrimitiveTest.java:36:23: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), java.lang.Object, int
+CastObjectToPrimitiveTest.java:36:23: compiler.err.prob.found.req.1: (compiler.misc.inconvertible.types: java.lang.Object, int)
1 error
--- a/langtools/test/tools/javac/varargs/6313164/T6313164.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/varargs/6313164/T6313164.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,6 +1,6 @@
T6313164.java:12:8: compiler.err.cant.apply.symbol.1: kindname.method, foo1, p1.A[], p1.B,p1.B, kindname.class, p1.B, (compiler.misc.inaccessible.varargs.type: p1.A, kindname.class, T6313164)
-T6313164.java:14:13: compiler.err.invalid.inferred.types: X, (compiler.misc.inaccessible.varargs.type: p1.A, kindname.class, T6313164)
-T6313164.java:15:13: compiler.err.invalid.inferred.types: X, (compiler.misc.inaccessible.varargs.type: p1.A, kindname.class, T6313164)
+T6313164.java:14:13: compiler.err.prob.found.req.1: (compiler.misc.invalid.inferred.types: X, (compiler.misc.inaccessible.varargs.type: p1.A, kindname.class, T6313164))
+T6313164.java:15:13: compiler.err.prob.found.req.1: (compiler.misc.invalid.inferred.types: X, (compiler.misc.inaccessible.varargs.type: p1.A, kindname.class, T6313164))
- compiler.note.unchecked.filename: B.java
- compiler.note.unchecked.recompile
3 errors
--- a/langtools/test/tools/javac/varargs/7097436/T7097436.out Thu Apr 05 13:05:08 2012 -0700
+++ b/langtools/test/tools/javac/varargs/7097436/T7097436.out Mon Apr 09 21:58:05 2012 -0700
@@ -1,6 +1,6 @@
T7097436.java:13:20: compiler.warn.varargs.unsafe.use.varargs.param: ls
T7097436.java:14:25: compiler.warn.varargs.unsafe.use.varargs.param: ls
-T7097436.java:15:20: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.util.List<java.lang.String>[], java.lang.String
-T7097436.java:16:26: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.util.List<java.lang.String>[], java.lang.Integer[]
+T7097436.java:15:20: compiler.err.prob.found.req: java.util.List<java.lang.String>[], java.lang.String
+T7097436.java:16:26: compiler.err.prob.found.req: java.util.List<java.lang.String>[], java.lang.Integer[]
2 errors
2 warnings