7177387: Add target-typing support in method context
Summary: Add support for deferred types and speculative attribution
Reviewed-by: jjg, dlsmith
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Printer.java Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Printer.java Thu Oct 04 13:04:53 2012 +0100
@@ -30,6 +30,10 @@
import com.sun.tools.javac.api.Messages;
import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.comp.DeferredAttr.DeferredType;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.Pretty;
+import com.sun.tools.javac.util.Assert;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
@@ -50,6 +54,11 @@
List<Type> seenCaptured = List.nil();
static final int PRIME = 997; // largest prime less than 1000
+ boolean raw;
+
+ protected Printer(boolean raw) {
+ this.raw = raw;
+ }
/**
* This method should be overriden in order to provide proper i18n support.
@@ -78,7 +87,7 @@
* @return printer visitor instance
*/
public static Printer createStandardPrinter(final Messages messages) {
- return new Printer() {
+ return new Printer(false) {
@Override
protected String localize(Locale locale, String key, Object... args) {
return messages.getLocalizedString(locale, key, args);
@@ -165,6 +174,34 @@
return "<" + visitTypes(t.tvars, locale) + ">" + visit(t.qtype, locale);
}
+ public String visitDeferredType(DeferredType t, Locale locale) {
+ return raw ? localize(locale, getDeferredKey(t.tree)) :
+ deferredTypeTree2String(t.tree);
+ }
+ //where
+ private String deferredTypeTree2String(JCTree tree) {
+ switch(tree.getTag()) {
+ case PARENS:
+ return deferredTypeTree2String(((JCTree.JCParens)tree).expr);
+ case CONDEXPR:
+ return Pretty.toSimpleString(tree, 15);
+ default:
+ Assert.error("unexpected tree kind " + tree.getKind());
+ return null;
+ }
+ }
+ private String getDeferredKey (JCTree tree) {
+ switch (tree.getTag()) {
+ case PARENS:
+ return getDeferredKey(((JCTree.JCParens)tree).expr);
+ case CONDEXPR:
+ return "compiler.misc.type.conditional";
+ default:
+ Assert.error("unexpected tree kind " + tree.getKind());
+ return null;
+ }
+ }
+
@Override
public String visitUndetVar(UndetVar t, Locale locale) {
if (t.inst != null) {
@@ -228,10 +265,14 @@
}
public String visitType(Type t, Locale locale) {
- String s = (t.tsym == null || t.tsym.name == null)
- ? localize(locale, "compiler.misc.type.none")
- : t.tsym.name.toString();
- return s;
+ if (t.tag == DEFERRED) {
+ return visitDeferredType((DeferredType)t, locale);
+ } else {
+ String s = (t.tsym == null || t.tsym.name == null)
+ ? localize(locale, "compiler.misc.type.none")
+ : t.tsym.name.toString();
+ return s;
+ }
}
/**
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java Thu Oct 04 13:04:53 2012 +0100
@@ -194,6 +194,9 @@
public boolean allowObjectToPrimitiveCast() {
return compareTo(JDK1_7) >= 0;
}
+ public boolean allowPoly() {
+ return compareTo(JDK1_8) >= 0;
+ }
public boolean allowLambda() {
return compareTo(JDK1_8) >= 0;
}
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java Thu Oct 04 13:04:53 2012 +0100
@@ -183,6 +183,10 @@
*/
public final Name[] boxedName = new Name[TypeTags.TypeTagCount];
+ /** A set containing all operator names.
+ */
+ public final Set<Name> operatorNames = new HashSet<Name>();
+
/** A hashtable containing the encountered top-level and member classes,
* indexed by flat names. The table does not contain local classes.
* It should be updated from the outside to reflect classes defined
@@ -244,7 +248,7 @@
int opcode) {
predefClass.members().enter(
new OperatorSymbol(
- names.fromString(name),
+ makeOperatorName(name),
new MethodType(List.of(left, right), res,
List.<Type>nil(), methodClass),
opcode,
@@ -275,7 +279,7 @@
Type res,
int opcode) {
OperatorSymbol sym =
- new OperatorSymbol(names.fromString(name),
+ new OperatorSymbol(makeOperatorName(name),
new MethodType(List.of(arg),
res,
List.<Type>nil(),
@@ -286,6 +290,16 @@
return sym;
}
+ /**
+ * Create a new operator name from corresponding String representation
+ * and add the name to the set of known operator names.
+ */
+ private Name makeOperatorName(String name) {
+ Name opName = names.fromString(name);
+ operatorNames.add(opName);
+ return opName;
+ }
+
/** Enter a class into symbol table.
* @param The name of the class.
*/
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java Thu Oct 04 13:04:53 2012 +0100
@@ -75,6 +75,9 @@
/** Constant type: no type at all. */
public static final JCNoType noType = new JCNoType(NONE);
+ /** Constant type: special type to be used during recovery of deferred expressions. */
+ public static final JCNoType recoveryType = new JCNoType(NONE);
+
/** If this switch is turned on, the names of type variables
* and anonymous classes are printed with hashcodes appended.
*/
--- a/langtools/src/share/classes/com/sun/tools/javac/code/TypeTags.java Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/TypeTags.java Thu Oct 04 13:04:53 2012 +0100
@@ -102,9 +102,13 @@
*/
public static final int FORALL = WILDCARD+1;
+ /** The tag of deferred expression types in method context
+ */
+ public static final int DEFERRED = FORALL+1;
+
/** The tag of the bottom type <null>.
*/
- public static final int BOT = FORALL+1;
+ public static final int BOT = DEFERRED+1;
/** The tag of a missing type.
*/
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Thu Oct 04 13:04:53 2012 +0100
@@ -3154,6 +3154,14 @@
}
return Type.noType;
}
+
+ /**
+ * Return the unboxed type if 't' is a boxed class, otherwise return 't' itself.
+ */
+ public Type unboxedTypeOrType(Type t) {
+ Type unboxedType = unboxedType(t);
+ return unboxedType.tag == NONE ? t : unboxedType;
+ }
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Capture conversion">
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Thu Oct 04 13:04:53 2012 +0100
@@ -25,12 +25,10 @@
package com.sun.tools.javac.comp;
-import java.util.*;
-import java.util.Set;
-import javax.lang.model.element.ElementKind;
-import javax.tools.JavaFileObject;
-
import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
+import com.sun.tools.javac.comp.Infer.InferenceContext;
+import com.sun.tools.javac.comp.Infer.InferenceContext.FreeTypeListener;
import com.sun.tools.javac.jvm.*;
import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.util.*;
@@ -49,6 +47,11 @@
import com.sun.source.tree.TreeVisitor;
import com.sun.source.util.SimpleTreeVisitor;
+import java.util.*;
+import java.util.Set;
+import javax.lang.model.element.ElementKind;
+import javax.tools.JavaFileObject;
+
import static com.sun.tools.javac.code.Flags.*;
import static com.sun.tools.javac.code.Flags.ANNOTATION;
import static com.sun.tools.javac.code.Flags.BLOCK;
@@ -80,6 +83,7 @@
final Symtab syms;
final Resolve rs;
final Infer infer;
+ final DeferredAttr deferredAttr;
final Check chk;
final MemberEnter memberEnter;
final TreeMaker make;
@@ -110,6 +114,7 @@
make = TreeMaker.instance(context);
enter = Enter.instance(context);
infer = Infer.instance(context);
+ deferredAttr = DeferredAttr.instance(context);
cfolder = ConstFold.instance(context);
target = Target.instance(context);
types = Types.instance(context);
@@ -127,6 +132,7 @@
allowCovariantReturns = source.allowCovariantReturns();
allowAnonOuterThis = source.allowAnonOuterThis();
allowStringsInSwitch = source.allowStringsInSwitch();
+ allowPoly = source.allowPoly() && options.isSet("allowPoly");
sourceName = source.name;
relax = (options.isSet("-retrofit") ||
options.isSet("-relax"));
@@ -144,6 +150,10 @@
*/
boolean relax;
+ /** Switch: support target-typing inference
+ */
+ boolean allowPoly;
+
/** Switch: support generics?
*/
boolean allowGenerics;
@@ -207,15 +217,29 @@
* @param ownkind The computed kind of the tree
* @param resultInfo The expected result of the tree
*/
- Type check(JCTree tree, Type owntype, int ownkind, ResultInfo resultInfo) {
+ Type check(final JCTree tree, final Type found, final int ownkind, final ResultInfo resultInfo) {
+ InferenceContext inferenceContext = resultInfo.checkContext.inferenceContext();
+ Type owntype = found;
if (owntype.tag != ERROR && resultInfo.pt.tag != METHOD && resultInfo.pt.tag != FORALL) {
- if ((ownkind & ~resultInfo.pkind) == 0) {
- owntype = resultInfo.check(tree, owntype);
+ if (inferenceContext.free(found)) {
+ inferenceContext.addFreeTypeListener(List.of(found, resultInfo.pt), new FreeTypeListener() {
+ @Override
+ public void typesInferred(InferenceContext inferenceContext) {
+ ResultInfo pendingResult =
+ resultInfo.dup(inferenceContext.asInstType(resultInfo.pt, types));
+ check(tree, inferenceContext.asInstType(found, types), ownkind, pendingResult);
+ }
+ });
+ return tree.type = resultInfo.pt;
} else {
- log.error(tree.pos(), "unexpected.type",
- kindNames(resultInfo.pkind),
- kindName(ownkind));
- owntype = types.createErrorType(owntype);
+ if ((ownkind & ~resultInfo.pkind) == 0) {
+ owntype = resultInfo.check(tree, owntype);
+ } else {
+ log.error(tree.pos(), "unexpected.type",
+ kindNames(resultInfo.pkind),
+ kindName(ownkind));
+ owntype = types.createErrorType(owntype);
+ }
}
}
tree.type = owntype;
@@ -297,8 +321,6 @@
} else {
log.error(pos, "cant.assign.val.to.final.var", v);
}
- } else if ((v.flags() & EFFECTIVELY_FINAL) != 0) {
- v.flags_field &= ~EFFECTIVELY_FINAL;
}
}
@@ -431,14 +453,38 @@
static final long serialVersionUID = -6924771130405446405L;
private Env<AttrContext> env;
private BreakAttr(Env<AttrContext> env) {
- this.env = env;
+ this.env = copyEnv(env);
+ }
+
+ private Env<AttrContext> copyEnv(Env<AttrContext> env) {
+ Env<AttrContext> newEnv =
+ env.dup(env.tree, env.info.dup(copyScope(env.info.scope)));
+ if (newEnv.outer != null) {
+ newEnv.outer = copyEnv(newEnv.outer);
+ }
+ return newEnv;
+ }
+
+ private Scope copyScope(Scope sc) {
+ Scope newScope = new Scope(sc.owner);
+ List<Symbol> elemsList = List.nil();
+ while (sc != null) {
+ for (Scope.Entry e = sc.elems ; e != null ; e = e.sibling) {
+ elemsList = elemsList.prepend(e.sym);
+ }
+ sc = sc.next;
+ }
+ for (Symbol s : elemsList) {
+ newScope.enter(s);
+ }
+ return newScope;
}
}
class ResultInfo {
- int pkind;
- Type pt;
- CheckContext checkContext;
+ final int pkind;
+ final Type pt;
+ final CheckContext checkContext;
ResultInfo(int pkind, Type pt) {
this(pkind, pt, chk.basicHandler);
@@ -450,15 +496,19 @@
this.checkContext = checkContext;
}
- protected Type check(DiagnosticPosition pos, Type found) {
+ protected Type check(final DiagnosticPosition pos, final Type found) {
return chk.checkType(pos, found, pt, checkContext);
}
+
+ protected ResultInfo dup(Type newPt) {
+ return new ResultInfo(pkind, newPt, checkContext);
+ }
}
- private final ResultInfo statInfo;
- private final ResultInfo varInfo;
- private final ResultInfo unknownExprInfo;
- private final ResultInfo unknownTypeInfo;
+ final ResultInfo statInfo;
+ final ResultInfo varInfo;
+ final ResultInfo unknownExprInfo;
+ final ResultInfo unknownTypeInfo;
Type pt() {
return resultInfo.pt;
@@ -491,7 +541,7 @@
* @param env The environment visitor argument.
* @param resultInfo The result info visitor argument.
*/
- private Type attribTree(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
+ Type attribTree(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
Env<AttrContext> prevEnv = this.env;
ResultInfo prevResult = this.resultInfo;
try {
@@ -563,9 +613,12 @@
*/
List<Type> attribArgs(List<JCExpression> trees, Env<AttrContext> env) {
ListBuffer<Type> argtypes = new ListBuffer<Type>();
- for (List<JCExpression> l = trees; l.nonEmpty(); l = l.tail)
- argtypes.append(chk.checkNonVoid(
- l.head.pos(), types.upperBound(attribExpr(l.head, env, Infer.anyPoly))));
+ for (JCExpression arg : trees) {
+ Type argtype = allowPoly && TreeInfo.isPoly(arg, env.tree) ?
+ deferredAttr.new DeferredType(arg, env) :
+ chk.checkNonVoid(arg, attribExpr(arg, env, Infer.anyPoly));
+ argtypes.append(argtype);
+ }
return argtypes.toList();
}
@@ -979,8 +1032,11 @@
// Create a new local environment with a local scope.
Env<AttrContext> localEnv =
env.dup(tree, env.info.dup(env.info.scope.dup()));
- attribStats(tree.stats, localEnv);
- localEnv.info.scope.leave();
+ try {
+ attribStats(tree.stats, localEnv);
+ } finally {
+ localEnv.info.scope.leave();
+ }
}
result = null;
}
@@ -1000,43 +1056,51 @@
public void visitForLoop(JCForLoop tree) {
Env<AttrContext> loopEnv =
env.dup(env.tree, env.info.dup(env.info.scope.dup()));
- attribStats(tree.init, loopEnv);
- if (tree.cond != null) attribExpr(tree.cond, loopEnv, syms.booleanType);
- loopEnv.tree = tree; // before, we were not in loop!
- attribStats(tree.step, loopEnv);
- attribStat(tree.body, loopEnv);
- loopEnv.info.scope.leave();
- result = null;
+ try {
+ attribStats(tree.init, loopEnv);
+ if (tree.cond != null) attribExpr(tree.cond, loopEnv, syms.booleanType);
+ loopEnv.tree = tree; // before, we were not in loop!
+ attribStats(tree.step, loopEnv);
+ attribStat(tree.body, loopEnv);
+ result = null;
+ }
+ finally {
+ loopEnv.info.scope.leave();
+ }
}
public void visitForeachLoop(JCEnhancedForLoop tree) {
Env<AttrContext> loopEnv =
env.dup(env.tree, env.info.dup(env.info.scope.dup()));
- attribStat(tree.var, loopEnv);
- Type exprType = types.upperBound(attribExpr(tree.expr, loopEnv));
- chk.checkNonVoid(tree.pos(), exprType);
- Type elemtype = types.elemtype(exprType); // perhaps expr is an array?
- if (elemtype == null) {
- // or perhaps expr implements Iterable<T>?
- Type base = types.asSuper(exprType, syms.iterableType.tsym);
- if (base == null) {
- log.error(tree.expr.pos(),
- "foreach.not.applicable.to.type",
- exprType,
- diags.fragment("type.req.array.or.iterable"));
- elemtype = types.createErrorType(exprType);
- } else {
- List<Type> iterableParams = base.allparams();
- elemtype = iterableParams.isEmpty()
- ? syms.objectType
- : types.upperBound(iterableParams.head);
+ try {
+ attribStat(tree.var, loopEnv);
+ Type exprType = types.upperBound(attribExpr(tree.expr, loopEnv));
+ chk.checkNonVoid(tree.pos(), exprType);
+ Type elemtype = types.elemtype(exprType); // perhaps expr is an array?
+ if (elemtype == null) {
+ // or perhaps expr implements Iterable<T>?
+ Type base = types.asSuper(exprType, syms.iterableType.tsym);
+ if (base == null) {
+ log.error(tree.expr.pos(),
+ "foreach.not.applicable.to.type",
+ exprType,
+ diags.fragment("type.req.array.or.iterable"));
+ elemtype = types.createErrorType(exprType);
+ } else {
+ List<Type> iterableParams = base.allparams();
+ elemtype = iterableParams.isEmpty()
+ ? syms.objectType
+ : types.upperBound(iterableParams.head);
+ }
}
+ chk.checkType(tree.expr.pos(), elemtype, tree.var.sym.type);
+ loopEnv.tree = tree; // before, we were not in loop!
+ attribStat(tree.body, loopEnv);
+ result = null;
}
- chk.checkType(tree.expr.pos(), elemtype, tree.var.sym.type);
- loopEnv.tree = tree; // before, we were not in loop!
- attribStat(tree.body, loopEnv);
- loopEnv.info.scope.leave();
- result = null;
+ finally {
+ loopEnv.info.scope.leave();
+ }
}
public void visitLabelled(JCLabeledStatement tree) {
@@ -1062,61 +1126,69 @@
Env<AttrContext> switchEnv =
env.dup(tree, env.info.dup(env.info.scope.dup()));
- boolean enumSwitch =
- allowEnums &&
- (seltype.tsym.flags() & Flags.ENUM) != 0;
- boolean stringSwitch = false;
- if (types.isSameType(seltype, syms.stringType)) {
- if (allowStringsInSwitch) {
- stringSwitch = true;
- } else {
- log.error(tree.selector.pos(), "string.switch.not.supported.in.source", sourceName);
+ try {
+
+ boolean enumSwitch =
+ allowEnums &&
+ (seltype.tsym.flags() & Flags.ENUM) != 0;
+ boolean stringSwitch = false;
+ if (types.isSameType(seltype, syms.stringType)) {
+ if (allowStringsInSwitch) {
+ stringSwitch = true;
+ } else {
+ log.error(tree.selector.pos(), "string.switch.not.supported.in.source", sourceName);
+ }
}
+ if (!enumSwitch && !stringSwitch)
+ seltype = chk.checkType(tree.selector.pos(), seltype, syms.intType);
+
+ // Attribute all cases and
+ // check that there are no duplicate case labels or default clauses.
+ Set<Object> labels = new HashSet<Object>(); // The set of case labels.
+ boolean hasDefault = false; // Is there a default label?
+ for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
+ JCCase c = l.head;
+ Env<AttrContext> caseEnv =
+ switchEnv.dup(c, env.info.dup(switchEnv.info.scope.dup()));
+ try {
+ if (c.pat != null) {
+ if (enumSwitch) {
+ Symbol sym = enumConstant(c.pat, seltype);
+ if (sym == null) {
+ log.error(c.pat.pos(), "enum.label.must.be.unqualified.enum");
+ } else if (!labels.add(sym)) {
+ log.error(c.pos(), "duplicate.case.label");
+ }
+ } else {
+ Type pattype = attribExpr(c.pat, switchEnv, seltype);
+ if (pattype.tag != ERROR) {
+ if (pattype.constValue() == null) {
+ log.error(c.pat.pos(),
+ (stringSwitch ? "string.const.req" : "const.expr.req"));
+ } else if (labels.contains(pattype.constValue())) {
+ log.error(c.pos(), "duplicate.case.label");
+ } else {
+ labels.add(pattype.constValue());
+ }
+ }
+ }
+ } else if (hasDefault) {
+ log.error(c.pos(), "duplicate.default.label");
+ } else {
+ hasDefault = true;
+ }
+ attribStats(c.stats, caseEnv);
+ } finally {
+ caseEnv.info.scope.leave();
+ addVars(c.stats, switchEnv.info.scope);
+ }
+ }
+
+ result = null;
}
- if (!enumSwitch && !stringSwitch)
- seltype = chk.checkType(tree.selector.pos(), seltype, syms.intType);
-
- // Attribute all cases and
- // check that there are no duplicate case labels or default clauses.
- Set<Object> labels = new HashSet<Object>(); // The set of case labels.
- boolean hasDefault = false; // Is there a default label?
- for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
- JCCase c = l.head;
- Env<AttrContext> caseEnv =
- switchEnv.dup(c, env.info.dup(switchEnv.info.scope.dup()));
- if (c.pat != null) {
- if (enumSwitch) {
- Symbol sym = enumConstant(c.pat, seltype);
- if (sym == null) {
- log.error(c.pat.pos(), "enum.label.must.be.unqualified.enum");
- } else if (!labels.add(sym)) {
- log.error(c.pos(), "duplicate.case.label");
- }
- } else {
- Type pattype = attribExpr(c.pat, switchEnv, seltype);
- if (pattype.tag != ERROR) {
- if (pattype.constValue() == null) {
- log.error(c.pat.pos(),
- (stringSwitch ? "string.const.req" : "const.expr.req"));
- } else if (labels.contains(pattype.constValue())) {
- log.error(c.pos(), "duplicate.case.label");
- } else {
- labels.add(pattype.constValue());
- }
- }
- }
- } else if (hasDefault) {
- log.error(c.pos(), "duplicate.default.label");
- } else {
- hasDefault = true;
- }
- attribStats(c.stats, caseEnv);
- caseEnv.info.scope.leave();
- addVars(c.stats, switchEnv.info.scope);
+ finally {
+ switchEnv.info.scope.leave();
}
-
- switchEnv.info.scope.leave();
- result = null;
}
// where
/** Add any variables defined in stats to the switch scope. */
@@ -1158,63 +1230,72 @@
public void visitTry(JCTry tree) {
// Create a new local environment with a local
Env<AttrContext> localEnv = env.dup(tree, env.info.dup(env.info.scope.dup()));
- boolean isTryWithResource = tree.resources.nonEmpty();
- // Create a nested environment for attributing the try block if needed
- Env<AttrContext> tryEnv = isTryWithResource ?
- env.dup(tree, localEnv.info.dup(localEnv.info.scope.dup())) :
- localEnv;
- // Attribute resource declarations
- for (JCTree resource : tree.resources) {
- CheckContext twrContext = new Check.NestedCheckContext(resultInfo.checkContext) {
- @Override
- public void report(DiagnosticPosition pos, JCDiagnostic details) {
- chk.basicHandler.report(pos, diags.fragment("try.not.applicable.to.type", details));
+ try {
+ boolean isTryWithResource = tree.resources.nonEmpty();
+ // Create a nested environment for attributing the try block if needed
+ Env<AttrContext> tryEnv = isTryWithResource ?
+ env.dup(tree, localEnv.info.dup(localEnv.info.scope.dup())) :
+ localEnv;
+ try {
+ // Attribute resource declarations
+ for (JCTree resource : tree.resources) {
+ CheckContext twrContext = new Check.NestedCheckContext(resultInfo.checkContext) {
+ @Override
+ public void report(DiagnosticPosition pos, JCDiagnostic details) {
+ chk.basicHandler.report(pos, diags.fragment("try.not.applicable.to.type", details));
+ }
+ };
+ ResultInfo twrResult = new ResultInfo(VAL, syms.autoCloseableType, twrContext);
+ if (resource.hasTag(VARDEF)) {
+ attribStat(resource, tryEnv);
+ twrResult.check(resource, resource.type);
+
+ //check that resource type cannot throw InterruptedException
+ checkAutoCloseable(resource.pos(), localEnv, resource.type);
+
+ VarSymbol var = (VarSymbol)TreeInfo.symbolFor(resource);
+ var.setData(ElementKind.RESOURCE_VARIABLE);
+ } else {
+ attribTree(resource, tryEnv, twrResult);
+ }
}
- };
- ResultInfo twrResult = new ResultInfo(VAL, syms.autoCloseableType, twrContext);
- if (resource.hasTag(VARDEF)) {
- attribStat(resource, tryEnv);
- twrResult.check(resource, resource.type);
-
- //check that resource type cannot throw InterruptedException
- checkAutoCloseable(resource.pos(), localEnv, resource.type);
-
- VarSymbol var = (VarSymbol)TreeInfo.symbolFor(resource);
- var.setData(ElementKind.RESOURCE_VARIABLE);
- } else {
- attribTree(resource, tryEnv, twrResult);
+ // Attribute body
+ attribStat(tree.body, tryEnv);
+ } finally {
+ if (isTryWithResource)
+ tryEnv.info.scope.leave();
}
+
+ // Attribute catch clauses
+ for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
+ JCCatch c = l.head;
+ Env<AttrContext> catchEnv =
+ localEnv.dup(c, localEnv.info.dup(localEnv.info.scope.dup()));
+ try {
+ Type ctype = attribStat(c.param, catchEnv);
+ if (TreeInfo.isMultiCatch(c)) {
+ //multi-catch parameter is implicitly marked as final
+ c.param.sym.flags_field |= FINAL | UNION;
+ }
+ if (c.param.sym.kind == Kinds.VAR) {
+ c.param.sym.setData(ElementKind.EXCEPTION_PARAMETER);
+ }
+ chk.checkType(c.param.vartype.pos(),
+ chk.checkClassType(c.param.vartype.pos(), ctype),
+ syms.throwableType);
+ attribStat(c.body, catchEnv);
+ } finally {
+ catchEnv.info.scope.leave();
+ }
+ }
+
+ // Attribute finalizer
+ if (tree.finalizer != null) attribStat(tree.finalizer, localEnv);
+ result = null;
}
- // Attribute body
- attribStat(tree.body, tryEnv);
- if (isTryWithResource)
- tryEnv.info.scope.leave();
-
- // Attribute catch clauses
- for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
- JCCatch c = l.head;
- Env<AttrContext> catchEnv =
- localEnv.dup(c, localEnv.info.dup(localEnv.info.scope.dup()));
- Type ctype = attribStat(c.param, catchEnv);
- if (TreeInfo.isMultiCatch(c)) {
- //multi-catch parameter is implicitly marked as final
- c.param.sym.flags_field |= FINAL | UNION;
- }
- if (c.param.sym.kind == Kinds.VAR) {
- c.param.sym.setData(ElementKind.EXCEPTION_PARAMETER);
- }
- chk.checkType(c.param.vartype.pos(),
- chk.checkClassType(c.param.vartype.pos(), ctype),
- syms.throwableType);
- attribStat(c.body, catchEnv);
- catchEnv.info.scope.leave();
+ finally {
+ localEnv.info.scope.leave();
}
-
- // Attribute finalizer
- if (tree.finalizer != null) attribStat(tree.finalizer, localEnv);
-
- localEnv.info.scope.leave();
- result = null;
}
void checkAutoCloseable(DiagnosticPosition pos, Env<AttrContext> env, Type resource) {
@@ -1222,10 +1303,10 @@
types.asSuper(resource, syms.autoCloseableType.tsym) != null &&
!types.isSameType(resource, syms.autoCloseableType)) { // Don't emit warning for AutoCloseable itself
Symbol close = syms.noSymbol;
- boolean prevDeferDiags = log.deferDiagnostics;
+ Filter<JCDiagnostic> prevDeferDiagsFilter = log.deferredDiagFilter;
Queue<JCDiagnostic> prevDeferredDiags = log.deferredDiagnostics;
try {
- log.deferDiagnostics = true;
+ log.deferAll();
log.deferredDiagnostics = ListBuffer.lb();
close = rs.resolveQualifiedMethod(pos,
env,
@@ -1235,7 +1316,7 @@
List.<Type>nil());
}
finally {
- log.deferDiagnostics = prevDeferDiags;
+ log.deferredDiagFilter = prevDeferDiagsFilter;
log.deferredDiagnostics = prevDeferredDiags;
}
if (close.kind == MTH &&
@@ -1248,50 +1329,71 @@
}
public void visitConditional(JCConditional tree) {
- attribExpr(tree.cond, env, syms.booleanType);
- attribExpr(tree.truepart, env);
- attribExpr(tree.falsepart, env);
- result = check(tree,
- capture(condType(tree.pos(), tree.cond.type,
- tree.truepart.type, tree.falsepart.type)),
- VAL, resultInfo);
+ Type condtype = attribExpr(tree.cond, env, syms.booleanType);
+
+ boolean standaloneConditional = !allowPoly ||
+ pt().tag == NONE && pt() != Type.recoveryType ||
+ isBooleanOrNumeric(env, tree);
+
+ if (!standaloneConditional && resultInfo.pt.tag == VOID) {
+ //cannot get here (i.e. it means we are returning from void method - which is already an error)
+ result = tree.type = types.createErrorType(resultInfo.pt);
+ return;
+ }
+
+ ResultInfo condInfo = standaloneConditional ?
+ unknownExprInfo :
+ new ResultInfo(VAL, pt(), new Check.NestedCheckContext(resultInfo.checkContext) {
+ //this will use enclosing check context to check compatibility of
+ //subexpression against target type; if we are in a method check context,
+ //depending on whether boxing is allowed, we could have incompatibilities
+ @Override
+ public void report(DiagnosticPosition pos, JCDiagnostic details) {
+ enclosingContext.report(pos, diags.fragment("incompatible.type.in.conditional", details));
+ }
+ });
+
+ Type truetype = attribTree(tree.truepart, env, condInfo);
+ Type falsetype = attribTree(tree.falsepart, env, condInfo);
+
+ Type owntype = standaloneConditional ? condType(tree, truetype, falsetype) : pt();
+ if (condtype.constValue() != null &&
+ truetype.constValue() != null &&
+ falsetype.constValue() != null) {
+ //constant folding
+ owntype = cfolder.coerce(condtype.isTrue() ? truetype : falsetype, owntype);
+ }
+ result = check(tree, owntype, VAL, resultInfo);
}
//where
+ @SuppressWarnings("fallthrough")
+ private boolean isBooleanOrNumeric(Env<AttrContext> env, JCExpression tree) {
+ switch (tree.getTag()) {
+ case LITERAL: return ((JCLiteral)tree).typetag < CLASS;
+ case LAMBDA: case REFERENCE: return false;
+ case PARENS: return isBooleanOrNumeric(env, ((JCParens)tree).expr);
+ case CONDEXPR:
+ JCConditional condTree = (JCConditional)tree;
+ return isBooleanOrNumeric(env, condTree.truepart) &&
+ isBooleanOrNumeric(env, condTree.falsepart);
+ default:
+ Type speculativeType = deferredAttr.attribSpeculative(tree, env, unknownExprInfo).type;
+ speculativeType = types.unboxedTypeOrType(speculativeType);
+ return speculativeType.tag <= BOOLEAN;
+ }
+ }
+
/** Compute the type of a conditional expression, after
- * checking that it exists. See Spec 15.25.
- *
- * @param pos The source position to be used for
- * error diagnostics.
- * @param condtype The type of the expression's condition.
- * @param thentype The type of the expression's then-part.
- * @param elsetype The type of the expression's else-part.
- */
- private Type condType(DiagnosticPosition pos,
- Type condtype,
- Type thentype,
- Type elsetype) {
- Type ctype = condType1(pos, condtype, thentype, elsetype);
-
- // If condition and both arms are numeric constants,
- // evaluate at compile-time.
- return ((condtype.constValue() != null) &&
- (thentype.constValue() != null) &&
- (elsetype.constValue() != null))
- ? cfolder.coerce(condtype.isTrue()?thentype:elsetype, ctype)
- : ctype;
- }
- /** Compute the type of a conditional expression, after
- * checking that it exists. Does not take into
+ * checking that it exists. See JLS 15.25. Does not take into
* account the special case where condition and both arms
* are constants.
*
* @param pos The source position to be used for error
* diagnostics.
- * @param condtype The type of the expression's condition.
* @param thentype The type of the expression's then-part.
* @param elsetype The type of the expression's else-part.
*/
- private Type condType1(DiagnosticPosition pos, Type condtype,
+ private Type condType(DiagnosticPosition pos,
Type thentype, Type elsetype) {
// If same type, that is the result
if (types.isSameType(thentype, elsetype))
@@ -1445,22 +1547,19 @@
public void visitReturn(JCReturn tree) {
// Check that there is an enclosing method which is
// nested within than the enclosing class.
- if (env.enclMethod == null ||
- env.enclMethod.sym.owner != env.enclClass.sym) {
+ if (env.info.returnResult == null) {
log.error(tree.pos(), "ret.outside.meth");
-
} else {
// Attribute return expression, if it exists, and check that
// it conforms to result type of enclosing method.
- Symbol m = env.enclMethod.sym;
- if (m.type.getReturnType().tag == VOID) {
- if (tree.expr != null)
+ if (tree.expr != null) {
+ if (env.info.returnResult.pt.tag == VOID) {
log.error(tree.expr.pos(),
"cant.ret.val.from.meth.decl.void");
- } else if (tree.expr == null) {
+ }
+ attribTree(tree.expr, env, env.info.returnResult);
+ } else if (env.info.returnResult.pt.tag != VOID) {
log.error(tree.pos(), "missing.ret.val");
- } else {
- attribExpr(tree.expr, env, m.type.getReturnType());
}
}
result = null;
@@ -1562,7 +1661,7 @@
// current instance (JLS ???).
boolean selectSuperPrev = localEnv.info.selectSuper;
localEnv.info.selectSuper = true;
- localEnv.info.varArgs = false;
+ localEnv.info.pendingResolutionPhase = null;
Symbol sym = rs.resolveConstructor(
tree.meth.pos(), localEnv, site, argtypes, typeargtypes);
localEnv.info.selectSuper = selectSuperPrev;
@@ -1573,8 +1672,7 @@
// ...and check that it is legal in the current context.
// (this will also set the tree's type)
Type mpt = newMethodTemplate(resultInfo.pt, argtypes, typeargtypes);
- checkId(tree.meth, site, sym, localEnv, new ResultInfo(MTH, mpt),
- tree.varargsElement != null);
+ checkId(tree.meth, site, sym, localEnv, new ResultInfo(MTH, mpt));
}
// Otherwise, `site' is an error type and we do nothing
}
@@ -1589,8 +1687,8 @@
// whose formal argument types is exactly the list of actual
// arguments (this will also set the method symbol).
Type mpt = newMethodTemplate(resultInfo.pt, argtypes, typeargtypes);
- localEnv.info.varArgs = false;
- Type mtype = attribExpr(tree.meth, localEnv, mpt);
+ localEnv.info.pendingResolutionPhase = null;
+ Type mtype = attribTree(tree.meth, localEnv, new ResultInfo(VAL, mpt, resultInfo.checkContext));
// Compute the result type.
Type restype = mtype.getReturnType();
@@ -1625,7 +1723,7 @@
// current context. Also, capture the return type
result = check(tree, capture(restype), VAL, resultInfo);
- if (localEnv.info.varArgs)
+ if (localEnv.info.lastResolveVarargs())
Assert.check(result.isErroneous() || tree.varargsElement != null);
}
chk.validate(tree.typeargs, localEnv);
@@ -1652,11 +1750,11 @@
/** Obtain a method type with given argument types.
*/
Type newMethodTemplate(Type restype, List<Type> argtypes, List<Type> typeargtypes) {
- MethodType mt = new MethodType(argtypes, restype, null, syms.methodClass);
+ MethodType mt = new MethodType(argtypes, restype, List.<Type>nil(), syms.methodClass);
return (typeargtypes == null) ? mt : (Type)new ForAll(typeargtypes, mt);
}
- public void visitNewClass(JCNewClass tree) {
+ public void visitNewClass(final JCNewClass tree) {
Type owntype = types.createErrorType(tree.type);
// The local environment of a class creation is
@@ -1729,19 +1827,6 @@
List<Type> argtypes = attribArgs(tree.args, localEnv);
List<Type> typeargtypes = attribTypes(tree.typeargs, localEnv);
- if (TreeInfo.isDiamond(tree) && !clazztype.isErroneous()) {
- Pair<Symbol, Type> diamondResult =
- attribDiamond(localEnv, tree, clazztype, argtypes, typeargtypes);
- tree.clazz.type = types.createErrorType(clazztype);
- tree.constructor = diamondResult.fst;
- tree.constructorType = diamondResult.snd;
- if (!diamondResult.snd.isErroneous()) {
- tree.clazz.type = clazztype = diamondResult.snd.getReturnType();
- tree.constructorType = types.createMethodTypeWithReturn(diamondResult.snd, syms.voidType);
- }
- clazztype = chk.checkClassType(tree.clazz, tree.clazz.type, true);
- }
-
// If we have made no mistakes in the class type...
if (clazztype.tag == CLASS) {
// Enums may not be instantiated except implicitly
@@ -1768,18 +1853,57 @@
// Error recovery: pretend no arguments were supplied.
argtypes = List.nil();
typeargtypes = List.nil();
+ } else if (TreeInfo.isDiamond(tree)) {
+ ClassType site = new ClassType(clazztype.getEnclosingType(),
+ clazztype.tsym.type.getTypeArguments(),
+ clazztype.tsym);
+
+ Env<AttrContext> diamondEnv = localEnv.dup(tree);
+ diamondEnv.info.selectSuper = cdef != null;
+ diamondEnv.info.pendingResolutionPhase = null;
+
+ //if the type of the instance creation expression is a class type
+ //apply method resolution inference (JLS 15.12.2.7). The return type
+ //of the resolved constructor will be a partially instantiated type
+ Symbol constructor = rs.resolveDiamond(tree.pos(),
+ diamondEnv,
+ site,
+ argtypes,
+ typeargtypes);
+ tree.constructor = constructor.baseSymbol();
+
+ final TypeSymbol csym = clazztype.tsym;
+ ResultInfo diamondResult = new ResultInfo(MTH, newMethodTemplate(resultInfo.pt, argtypes, typeargtypes), new Check.NestedCheckContext(resultInfo.checkContext) {
+ @Override
+ public void report(DiagnosticPosition _unused, JCDiagnostic details) {
+ enclosingContext.report(tree.clazz,
+ diags.fragment("cant.apply.diamond.1", diags.fragment("diamond", csym), details));
+ }
+ });
+ Type constructorType = tree.constructorType = types.createErrorType(clazztype);
+ constructorType = checkId(tree, site,
+ constructor,
+ diamondEnv,
+ diamondResult);
+
+ tree.clazz.type = types.createErrorType(clazztype);
+ if (!constructorType.isErroneous()) {
+ tree.clazz.type = clazztype = constructorType.getReturnType();
+ tree.constructorType = types.createMethodTypeWithReturn(constructorType, syms.voidType);
+ }
+ clazztype = chk.checkClassType(tree.clazz, tree.clazz.type, true);
}
// Resolve the called constructor under the assumption
// that we are referring to a superclass instance of the
// current instance (JLS ???).
- else if (!TreeInfo.isDiamond(tree)) {
+ else {
//the following code alters some of the fields in the current
//AttrContext - hence, the current context must be dup'ed in
//order to avoid downstream failures
Env<AttrContext> rsEnv = localEnv.dup(tree);
rsEnv.info.selectSuper = cdef != null;
- rsEnv.info.varArgs = false;
+ rsEnv.info.pendingResolutionPhase = null;
tree.constructor = rs.resolveConstructor(
tree.pos(), rsEnv, clazztype, argtypes, typeargtypes);
if (cdef == null) { //do not check twice!
@@ -1787,42 +1911,11 @@
clazztype,
tree.constructor,
rsEnv,
- new ResultInfo(MTH, newMethodTemplate(syms.voidType, argtypes, typeargtypes)),
- rsEnv.info.varArgs);
- if (rsEnv.info.varArgs)
+ new ResultInfo(MTH, newMethodTemplate(syms.voidType, argtypes, typeargtypes)));
+ if (rsEnv.info.lastResolveVarargs())
Assert.check(tree.constructorType.isErroneous() || tree.varargsElement != null);
}
- if (tree.def == null &&
- !clazztype.isErroneous() &&
- clazztype.getTypeArguments().nonEmpty() &&
- findDiamonds) {
- boolean prevDeferDiags = log.deferDiagnostics;
- Queue<JCDiagnostic> prevDeferredDiags = log.deferredDiagnostics;
- Type inferred = null;
- try {
- //disable diamond-related diagnostics
- log.deferDiagnostics = true;
- log.deferredDiagnostics = ListBuffer.lb();
- inferred = attribDiamond(localEnv,
- tree,
- clazztype,
- argtypes,
- typeargtypes).snd;
- } finally {
- log.deferDiagnostics = prevDeferDiags;
- log.deferredDiagnostics = prevDeferredDiags;
- }
- if (!inferred.isErroneous()) {
- inferred = inferred.getReturnType();
- }
- if (inferred != null &&
- types.isAssignable(inferred, pt().tag == NONE ? syms.objectType : pt(), Warner.noWarnings)) {
- String key = types.isSameType(clazztype, inferred) ?
- "diamond.redundant.args" :
- "diamond.redundant.args.1";
- log.warning(tree.clazz.pos(), key, clazztype, inferred);
- }
- }
+ findDiamondIfNeeded(localEnv, tree, clazztype);
}
if (cdef != null) {
@@ -1887,8 +1980,7 @@
clazztype,
tree.constructor,
localEnv,
- new ResultInfo(VAL, newMethodTemplate(syms.voidType, argtypes, typeargtypes)),
- localEnv.info.varArgs);
+ new ResultInfo(VAL, newMethodTemplate(syms.voidType, argtypes, typeargtypes)));
}
if (tree.constructor != null && tree.constructor.kind == MTH)
@@ -1897,53 +1989,33 @@
result = check(tree, owntype, VAL, resultInfo);
chk.validate(tree.typeargs, localEnv);
}
-
- Pair<Symbol, Type> attribDiamond(Env<AttrContext> env,
- final JCNewClass tree,
- final Type clazztype,
- List<Type> argtypes,
- List<Type> typeargtypes) {
- if (clazztype.isErroneous() ||
- clazztype.isInterface()) {
- //if the type of the instance creation expression is erroneous,
- //or if it's an interface, or if something prevented us to form a valid
- //mapping, return the (possibly erroneous) type unchanged
- return new Pair<Symbol, Type>(syms.noSymbol, clazztype);
+ //where
+ void findDiamondIfNeeded(Env<AttrContext> env, JCNewClass tree, Type clazztype) {
+ if (tree.def == null &&
+ !clazztype.isErroneous() &&
+ clazztype.getTypeArguments().nonEmpty() &&
+ findDiamonds) {
+ JCTypeApply ta = (JCTypeApply)tree.clazz;
+ List<JCExpression> prevTypeargs = ta.arguments;
+ try {
+ //create a 'fake' diamond AST node by removing type-argument trees
+ ta.arguments = List.nil();
+ ResultInfo findDiamondResult = new ResultInfo(VAL,
+ resultInfo.checkContext.inferenceContext().free(resultInfo.pt) ? Type.noType : pt());
+ Type inferred = deferredAttr.attribSpeculative(tree, env, findDiamondResult).type;
+ if (!inferred.isErroneous() &&
+ types.isAssignable(inferred, pt().tag == NONE ? syms.objectType : pt(), Warner.noWarnings)) {
+ String key = types.isSameType(clazztype, inferred) ?
+ "diamond.redundant.args" :
+ "diamond.redundant.args.1";
+ log.warning(tree.clazz.pos(), key, clazztype, inferred);
+ }
+ } finally {
+ ta.arguments = prevTypeargs;
+ }
+ }
}
- //dup attribution environment and augment the set of inference variables
- Env<AttrContext> localEnv = env.dup(tree);
-
- ClassType site = new ClassType(clazztype.getEnclosingType(),
- clazztype.tsym.type.getTypeArguments(),
- clazztype.tsym);
-
- //if the type of the instance creation expression is a class type
- //apply method resolution inference (JLS 15.12.2.7). The return type
- //of the resolved constructor will be a partially instantiated type
- Symbol constructor = rs.resolveDiamond(tree.pos(),
- localEnv,
- site,
- argtypes,
- typeargtypes);
-
- Type constructorType = types.createErrorType(clazztype);
- ResultInfo diamondResult = new ResultInfo(MTH, newMethodTemplate(resultInfo.pt, argtypes, typeargtypes), new Check.NestedCheckContext(resultInfo.checkContext) {
- @Override
- public void report(DiagnosticPosition _unused, JCDiagnostic details) {
- enclosingContext.report(tree.clazz,
- diags.fragment("cant.apply.diamond.1", diags.fragment("diamond", clazztype.tsym), details));
- }
- });
- constructorType = checkId(tree, site,
- constructor,
- localEnv,
- diamondResult,
- localEnv.info.varArgs);
-
- return new Pair<Symbol, Type>(constructor.baseSymbol(), constructorType);
- }
-
/** Make an attributed null check tree.
*/
public JCExpression makeNullCheck(JCExpression arg) {
@@ -1960,13 +2032,14 @@
public void visitNewArray(JCNewArray tree) {
Type owntype = types.createErrorType(tree.type);
+ Env<AttrContext> localEnv = env.dup(tree);
Type elemtype;
if (tree.elemtype != null) {
- elemtype = attribType(tree.elemtype, env);
- chk.validate(tree.elemtype, env);
+ elemtype = attribType(tree.elemtype, localEnv);
+ chk.validate(tree.elemtype, localEnv);
owntype = elemtype;
for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) {
- attribExpr(l.head, env, syms.intType);
+ attribExpr(l.head, localEnv, syms.intType);
owntype = new ArrayType(owntype, syms.arrayClass);
}
} else {
@@ -1983,7 +2056,7 @@
}
}
if (tree.elems != null) {
- attribExprs(tree.elems, env, elemtype);
+ attribExprs(tree.elems, localEnv, elemtype);
owntype = new ArrayType(elemtype, syms.arrayClass);
}
if (!types.isReifiable(elemtype))
@@ -2132,18 +2205,34 @@
result = check(tree, owntype, VAL, resultInfo);
}
- public void visitTypeCast(JCTypeCast tree) {
+ public void visitTypeCast(final JCTypeCast tree) {
Type clazztype = attribType(tree.clazz, env);
chk.validate(tree.clazz, env, false);
//a fresh environment is required for 292 inference to work properly ---
//see Infer.instantiatePolymorphicSignatureInstance()
Env<AttrContext> localEnv = env.dup(tree);
- Type exprtype = attribExpr(tree.expr, localEnv, Infer.anyPoly);
- Type owntype = chk.checkCastable(tree.expr.pos(), exprtype, clazztype);
+ //should we propagate the target type?
+ final ResultInfo castInfo;
+ final boolean isPoly = TreeInfo.isPoly(tree.expr, tree);
+ if (isPoly) {
+ //expression is a poly - we need to propagate target type info
+ castInfo = new ResultInfo(VAL, clazztype, new Check.NestedCheckContext(resultInfo.checkContext) {
+ @Override
+ public boolean compatible(Type found, Type req, Warner warn) {
+ return types.isCastable(found, req, warn);
+ }
+ });
+ } else {
+ //standalone cast - target-type info is not propagated
+ castInfo = unknownExprInfo;
+ }
+ Type exprtype = attribTree(tree.expr, localEnv, castInfo);
+ Type owntype = isPoly ? clazztype : chk.checkCastable(tree.expr.pos(), exprtype, clazztype);
if (exprtype.constValue() != null)
owntype = cfolder.coerce(exprtype, owntype);
result = check(tree, capture(owntype), VAL, resultInfo);
- chk.checkRedundantCast(localEnv, tree);
+ if (!isPoly)
+ chk.checkRedundantCast(localEnv, tree);
}
public void visitTypeTest(JCInstanceOf tree) {
@@ -2170,15 +2259,13 @@
public void visitIdent(JCIdent tree) {
Symbol sym;
- boolean varArgs = false;
// Find symbol
if (pt().tag == METHOD || pt().tag == FORALL) {
// If we are looking for a method, the prototype `pt' will be a
// method type with the type of the call's arguments as parameters.
- env.info.varArgs = false;
+ env.info.pendingResolutionPhase = null;
sym = rs.resolveMethod(tree.pos(), env, tree.name, pt().getParameterTypes(), pt().getTypeArguments());
- varArgs = env.info.varArgs;
} else if (tree.sym != null && tree.sym.kind != VAR) {
sym = tree.sym;
} else {
@@ -2240,7 +2327,7 @@
while (env1.outer != null && !rs.isAccessible(env, env1.enclClass.sym.type, sym))
env1 = env1.outer;
}
- result = checkId(tree, env1.enclClass.sym.type, sym, env, resultInfo, varArgs);
+ result = checkId(tree, env1.enclClass.sym.type, sym, env, resultInfo);
}
public void visitSelect(JCFieldAccess tree) {
@@ -2283,13 +2370,13 @@
sitesym.name == names._super;
// Determine the symbol represented by the selection.
- env.info.varArgs = false;
+ env.info.pendingResolutionPhase = null;
Symbol sym = selectSym(tree, sitesym, site, env, resultInfo);
if (sym.exists() && !isType(sym) && (pkind() & (PCK | TYP)) != 0) {
site = capture(site);
sym = selectSym(tree, sitesym, site, env, resultInfo);
}
- boolean varArgs = env.info.varArgs;
+ boolean varArgs = env.info.lastResolveVarargs();
tree.sym = sym;
if (site.tag == TYPEVAR && !isType(sym) && sym.kind != ERR) {
@@ -2340,7 +2427,7 @@
if ((sym.flags() & STATIC) == 0 &&
sym.name != names._super &&
(sym.kind == VAR || sym.kind == MTH)) {
- rs.access(rs.new StaticError(sym),
+ rs.accessBase(rs.new StaticError(sym),
tree.pos(), site, sym.name, true);
}
}
@@ -2364,7 +2451,7 @@
}
env.info.selectSuper = selectSuperPrev;
- result = checkId(tree, site, sym, env, resultInfo, varArgs);
+ result = checkId(tree, site, sym, env, resultInfo);
}
//where
/** Determine symbol referenced by a Select expression,
@@ -2383,7 +2470,7 @@
Name name = tree.name;
switch (site.tag) {
case PACKAGE:
- return rs.access(
+ return rs.accessBase(
rs.findIdentInPackage(env, site.tsym, name, resultInfo.pkind),
pos, location, site, name, true);
case ARRAY:
@@ -2407,7 +2494,7 @@
// We are seeing a plain identifier as selector.
Symbol sym = rs.findIdentInType(env, site, name, resultInfo.pkind);
if ((resultInfo.pkind & ERRONEOUS) == 0)
- sym = rs.access(sym, pos, location, site, name, true);
+ sym = rs.accessBase(sym, pos, location, site, name, true);
return sym;
}
case WILDCARD:
@@ -2429,7 +2516,7 @@
Symbol sym2 = (sym.flags() & Flags.PRIVATE) != 0 ?
rs.new AccessError(env, site, sym) :
sym;
- rs.access(sym2, pos, location, site, name, true);
+ rs.accessBase(sym2, pos, location, site, name, true);
return sym;
}
case ERROR:
@@ -2480,9 +2567,18 @@
Type site,
Symbol sym,
Env<AttrContext> env,
- ResultInfo resultInfo,
- boolean useVarargs) {
- if (resultInfo.pt.isErroneous()) return types.createErrorType(site);
+ ResultInfo resultInfo) {
+ Type pt = resultInfo.pt.tag == FORALL || resultInfo.pt.tag == METHOD ?
+ resultInfo.pt.map(deferredAttr.new DeferredTypeMap(AttrMode.SPECULATIVE, sym, env.info.pendingResolutionPhase)) :
+ resultInfo.pt;
+
+ DeferredAttr.DeferredTypeMap recoveryMap =
+ deferredAttr.new RecoveryDeferredTypeMap(AttrMode.CHECK, sym, env.info.pendingResolutionPhase);
+
+ if (pt.isErroneous()) {
+ Type.map(resultInfo.pt.getParameterTypes(), recoveryMap);
+ return types.createErrorType(site);
+ }
Type owntype; // The computed type of this identifier occurrence.
switch (sym.kind) {
case TYP:
@@ -2560,10 +2656,11 @@
owntype = checkMethod(site, sym,
new ResultInfo(VAL, resultInfo.pt.getReturnType(), resultInfo.checkContext),
env, TreeInfo.args(env.tree), resultInfo.pt.getParameterTypes(),
- resultInfo.pt.getTypeArguments(), env.info.varArgs);
+ resultInfo.pt.getTypeArguments());
break;
}
case PCK: case ERR:
+ Type.map(resultInfo.pt.getParameterTypes(), recoveryMap);
owntype = sym.type;
break;
default:
@@ -2703,8 +2800,7 @@
Env<AttrContext> env,
final List<JCExpression> argtrees,
List<Type> argtypes,
- List<Type> typeargtypes,
- boolean useVarargs) {
+ List<Type> typeargtypes) {
// Test (5): if symbol is an instance method of a raw type, issue
// an unchecked warning if its argument types change under erasure.
if (allowGenerics &&
@@ -2726,18 +2822,16 @@
// any type arguments and value arguments.
noteWarner.clear();
try {
- Type owntype = rs.rawInstantiate(
+ Type owntype = rs.checkMethod(
env,
site,
sym,
resultInfo,
argtypes,
typeargtypes,
- allowBoxing,
- useVarargs,
noteWarner);
- return chk.checkMethod(owntype, sym, env, argtrees, argtypes, useVarargs,
+ return chk.checkMethod(owntype, sym, env, argtrees, argtypes, env.info.lastResolveVarargs(),
noteWarner.hasNonSilentLint(LintCategory.UNCHECKED));
} catch (Infer.InferenceException ex) {
//invalid target type - propagate exception outwards or report error
@@ -2745,7 +2839,7 @@
resultInfo.checkContext.report(env.tree.pos(), ex.getDiagnostic());
return types.createErrorType(site);
} catch (Resolve.InapplicableMethodException ex) {
- Assert.error();
+ Assert.error(ex.getDiagnostic().getMessage(Locale.getDefault()));
return null;
}
}
@@ -3053,8 +3147,10 @@
Lint prevLint = chk.setLint(env.info.lint);
JavaFileObject prev = log.useSource(c.sourcefile);
+ ResultInfo prevReturnRes = env.info.returnResult;
try {
+ env.info.returnResult = null;
// java.lang.Enum may not be subclassed by a non-enum
if (st.tsym == syms.enumSym &&
((c.flags_field & (Flags.ENUM|Flags.COMPOUND)) == 0))
@@ -3071,6 +3167,7 @@
chk.checkDeprecatedAnnotation(env.tree.pos(), c);
} finally {
+ env.info.returnResult = prevReturnRes;
log.useSource(prev);
chk.setLint(prevLint);
}
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/AttrContext.java Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/AttrContext.java Thu Oct 04 13:04:53 2012 +0100
@@ -56,7 +56,7 @@
/** Are arguments to current function applications boxed into an array for varargs?
*/
- boolean varArgs = false;
+ Resolve.MethodResolutionPhase pendingResolutionPhase = null;
/** A record of the lint/SuppressWarnings currently in effect
*/
@@ -67,6 +67,11 @@
*/
Symbol enclVar = null;
+ /** ResultInfo to be used for attributing 'return' statement expressions
+ * (set by Attr.visitMethod and Attr.visitLambda)
+ */
+ Attr.ResultInfo returnResult = null;
+
/** Duplicate this context, replacing scope field and copying all others.
*/
AttrContext dup(Scope scope) {
@@ -75,9 +80,10 @@
info.staticLevel = staticLevel;
info.isSelfCall = isSelfCall;
info.selectSuper = selectSuper;
- info.varArgs = varArgs;
+ info.pendingResolutionPhase = pendingResolutionPhase;
info.lint = lint;
info.enclVar = enclVar;
+ info.returnResult = returnResult;
return info;
}
@@ -93,6 +99,11 @@
return scope.getElements();
}
+ boolean lastResolveVarargs() {
+ return pendingResolutionPhase != null &&
+ pendingResolutionPhase.isVarargsRequired();
+ }
+
public String toString() {
return "AttrContext[" + scope.toString() + "]";
}
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java Thu Oct 04 13:04:53 2012 +0100
@@ -40,6 +40,7 @@
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext;
import com.sun.tools.javac.comp.Infer.InferenceContext;
import com.sun.tools.javac.comp.Infer.InferenceContext.FreeTypeListener;
@@ -68,6 +69,7 @@
private final Resolve rs;
private final Symtab syms;
private final Enter enter;
+ private final DeferredAttr deferredAttr;
private final Infer infer;
private final Types types;
private final JCDiagnostic.Factory diags;
@@ -100,6 +102,7 @@
rs = Resolve.instance(context);
syms = Symtab.instance(context);
enter = Enter.instance(context);
+ deferredAttr = DeferredAttr.instance(context);
infer = Infer.instance(context);
this.types = Types.instance(context);
diags = JCDiagnostic.Factory.instance(context);
@@ -433,6 +436,8 @@
public Warner checkWarner(DiagnosticPosition pos, Type found, Type req);
public Infer.InferenceContext inferenceContext();
+
+ public DeferredAttr.DeferredAttrContext deferredAttrContext();
}
/**
@@ -463,6 +468,10 @@
public Infer.InferenceContext inferenceContext() {
return enclosingContext.inferenceContext();
}
+
+ public DeferredAttrContext deferredAttrContext() {
+ return enclosingContext.deferredAttrContext();
+ }
}
/**
@@ -483,6 +492,10 @@
public InferenceContext inferenceContext() {
return infer.emptyContext;
}
+
+ public DeferredAttrContext deferredAttrContext() {
+ return deferredAttr.emptyDeferredAttrContext;
+ }
};
/** Check that a given type is assignable to a given proto-type.
@@ -817,6 +830,8 @@
sym.owner == syms.enumSym)
formals = formals.tail.tail;
List<JCExpression> args = argtrees;
+ DeferredAttr.DeferredTypeMap checkDeferredMap =
+ deferredAttr.new DeferredTypeMap(DeferredAttr.AttrMode.CHECK, sym, env.info.pendingResolutionPhase);
while (formals.head != last) {
JCTree arg = args.head;
Warner warn = convertWarner(arg.pos(), arg.type, formals.head);
@@ -835,7 +850,7 @@
} else if ((sym.flags() & VARARGS) != 0 && allowVarargs) {
// non-varargs call to varargs method
Type varParam = owntype.getParameterTypes().last();
- Type lastArg = argtypes.last();
+ Type lastArg = checkDeferredMap.apply(argtypes.last());
if (types.isSubtypeUnchecked(lastArg, types.elemtype(varParam)) &&
!types.isSameType(types.erasure(varParam), types.erasure(lastArg)))
log.warning(argtrees.last().pos(), "inexact.non-varargs.call",
@@ -847,7 +862,7 @@
kindName(sym),
sym.name,
rs.methodArguments(sym.type.getParameterTypes()),
- rs.methodArguments(argtypes),
+ rs.methodArguments(Type.map(argtypes, checkDeferredMap)),
kindName(sym.location()),
sym.location());
owntype = new MethodType(owntype.getParameterTypes(),
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Thu Oct 04 13:04:53 2012 +0100
@@ -0,0 +1,553 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package com.sun.tools.javac.comp;
+
+import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.tree.*;
+import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.code.Type.*;
+import com.sun.tools.javac.comp.Attr.ResultInfo;
+import com.sun.tools.javac.comp.Infer.InferenceContext;
+import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
+import com.sun.tools.javac.tree.JCTree.*;
+
+import javax.tools.JavaFileObject;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import static com.sun.tools.javac.code.TypeTags.*;
+import static com.sun.tools.javac.tree.JCTree.Tag.*;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+
+/**
+ * This is an helper class that is used to perform deferred type-analysis.
+ * Each time a poly expression occurs in argument position, javac attributes it
+ * with a temporary 'deferred type' that is checked (possibly multiple times)
+ * against an expected formal type.
+ *
+ * <p><b>This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.</b>
+ */
+public class DeferredAttr extends JCTree.Visitor {
+ protected static final Context.Key<DeferredAttr> deferredAttrKey =
+ new Context.Key<DeferredAttr>();
+
+ final Attr attr;
+ final Check chk;
+ final Enter enter;
+ final Infer infer;
+ final Log log;
+ final Symtab syms;
+ final TreeMaker make;
+ final Types types;
+
+ public static DeferredAttr instance(Context context) {
+ DeferredAttr instance = context.get(deferredAttrKey);
+ if (instance == null)
+ instance = new DeferredAttr(context);
+ return instance;
+ }
+
+ protected DeferredAttr(Context context) {
+ context.put(deferredAttrKey, this);
+ attr = Attr.instance(context);
+ chk = Check.instance(context);
+ enter = Enter.instance(context);
+ infer = Infer.instance(context);
+ log = Log.instance(context);
+ syms = Symtab.instance(context);
+ make = TreeMaker.instance(context);
+ types = Types.instance(context);
+ }
+
+ /**
+ * This type represents a deferred type. A deferred type starts off with
+ * no information on the underlying expression type. Such info needs to be
+ * discovered through type-checking the deferred type against a target-type.
+ * Every deferred type keeps a pointer to the AST node from which it originated.
+ */
+ public class DeferredType extends Type {
+
+ public JCExpression tree;
+ Env<AttrContext> env;
+ AttrMode mode;
+ SpeculativeCache speculativeCache;
+
+ DeferredType(JCExpression tree, Env<AttrContext> env) {
+ super(DEFERRED, null);
+ this.tree = tree;
+ this.env = env.dup(tree, env.info.dup());
+ this.speculativeCache = new SpeculativeCache();
+ }
+
+ /**
+ * A speculative cache is used to keep track of all overload resolution rounds
+ * that triggered speculative attribution on a given deferred type. Each entry
+ * stores a pointer to the speculative tree and the resolution phase in which the entry
+ * has been added.
+ */
+ class SpeculativeCache {
+
+ private Map<Symbol, List<Entry>> cache =
+ new WeakHashMap<Symbol, List<Entry>>();
+
+ class Entry {
+ JCTree speculativeTree;
+ Resolve.MethodResolutionPhase phase;
+
+ public Entry(JCTree speculativeTree, MethodResolutionPhase phase) {
+ this.speculativeTree = speculativeTree;
+ this.phase = phase;
+ }
+
+ boolean matches(Resolve.MethodResolutionPhase phase) {
+ return this.phase == phase;
+ }
+ }
+
+ /**
+ * Clone a speculative cache entry as a fresh entry associated
+ * with a new method (this maybe required to fixup speculative cache
+ * misses after Resolve.access())
+ */
+ void dupAllTo(Symbol from, Symbol to) {
+ Assert.check(cache.get(to) == null);
+ List<Entry> entries = cache.get(from);
+ if (entries != null) {
+ cache.put(to, entries);
+ }
+ }
+
+ /**
+ * Retrieve a speculative cache entry corresponding to given symbol
+ * and resolution phase
+ */
+ Entry get(Symbol msym, MethodResolutionPhase phase) {
+ List<Entry> entries = cache.get(msym);
+ if (entries == null) return null;
+ for (Entry e : entries) {
+ if (e.matches(phase)) return e;
+ }
+ return null;
+ }
+
+ /**
+ * Stores a speculative cache entry corresponding to given symbol
+ * and resolution phase
+ */
+ void put(Symbol msym, JCTree speculativeTree, MethodResolutionPhase phase) {
+ List<Entry> entries = cache.get(msym);
+ if (entries == null) {
+ entries = List.nil();
+ }
+ cache.put(msym, entries.prepend(new Entry(speculativeTree, phase)));
+ }
+ }
+
+ /**
+ * Get the type that has been computed during a speculative attribution round
+ */
+ Type speculativeType(Symbol msym, MethodResolutionPhase phase) {
+ SpeculativeCache.Entry e = speculativeCache.get(msym, phase);
+ return e != null ? e.speculativeTree.type : Type.noType;
+ }
+
+ /**
+ * Check a deferred type against a potential target-type. Depending on
+ * the current attribution mode, a normal vs. speculative attribution
+ * round is performed on the underlying AST node. There can be only one
+ * speculative round for a given target method symbol; moreover, a normal
+ * attribution round must follow one or more speculative rounds.
+ */
+ Type check(ResultInfo resultInfo) {
+ DeferredAttrContext deferredAttrContext =
+ resultInfo.checkContext.deferredAttrContext();
+ Assert.check(deferredAttrContext != emptyDeferredAttrContext);
+ List<Type> stuckVars = stuckVars(tree, resultInfo);
+ if (stuckVars.nonEmpty()) {
+ deferredAttrContext.addDeferredAttrNode(this, resultInfo, stuckVars);
+ return Type.noType;
+ } else {
+ try {
+ switch (deferredAttrContext.mode) {
+ case SPECULATIVE:
+ Assert.check(mode == null ||
+ (mode == AttrMode.SPECULATIVE &&
+ speculativeType(deferredAttrContext.msym, deferredAttrContext.phase).tag == NONE));
+ JCTree speculativeTree = attribSpeculative(tree, env, resultInfo);
+ speculativeCache.put(deferredAttrContext.msym, speculativeTree, deferredAttrContext.phase);
+ return speculativeTree.type;
+ case CHECK:
+ Assert.check(mode == AttrMode.SPECULATIVE);
+ return attr.attribTree(tree, env, resultInfo);
+ }
+ Assert.error();
+ return null;
+ } finally {
+ mode = deferredAttrContext.mode;
+ }
+ }
+ }
+ }
+
+ /**
+ * The 'mode' in which the deferred type is to be type-checked
+ */
+ public enum AttrMode {
+ /**
+ * A speculative type-checking round is used during overload resolution
+ * mainly to generate constraints on inference variables. Side-effects
+ * arising from type-checking the expression associated with the deferred
+ * type are reversed after the speculative round finishes. This means the
+ * expression tree will be left in a blank state.
+ */
+ SPECULATIVE,
+ /**
+ * This is the plain type-checking mode. Produces side-effects on the underlying AST node
+ */
+ CHECK;
+ }
+
+ /**
+ * Routine that performs speculative type-checking; the input AST node is
+ * cloned (to avoid side-effects cause by Attr) and compiler state is
+ * restored after type-checking. All diagnostics (but critical ones) are
+ * disabled during speculative type-checking.
+ */
+ JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
+ JCTree newTree = new TreeCopier<Object>(make).copy(tree);
+ Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared()));
+ speculativeEnv.info.scope.owner = env.info.scope.owner;
+ Filter<JCDiagnostic> prevDeferDiagsFilter = log.deferredDiagFilter;
+ Queue<JCDiagnostic> prevDeferredDiags = log.deferredDiagnostics;
+ final JavaFileObject currentSource = log.currentSourceFile();
+ try {
+ log.deferredDiagnostics = new ListBuffer<JCDiagnostic>();
+ log.deferredDiagFilter = new Filter<JCDiagnostic>() {
+ public boolean accepts(JCDiagnostic t) {
+ return t.getDiagnosticSource().getFile().equals(currentSource);
+ }
+ };
+ attr.attribTree(newTree, speculativeEnv, resultInfo);
+ unenterScanner.scan(newTree);
+ return newTree;
+ } catch (Abort ex) {
+ //if some very bad condition occurred during deferred attribution
+ //we should dump all errors before killing javac
+ log.reportDeferredDiagnostics();
+ throw ex;
+ } finally {
+ unenterScanner.scan(newTree);
+ log.deferredDiagFilter = prevDeferDiagsFilter;
+ log.deferredDiagnostics = prevDeferredDiags;
+ }
+ }
+ //where
+ protected TreeScanner unenterScanner = new TreeScanner() {
+ @Override
+ public void visitClassDef(JCClassDecl tree) {
+ ClassSymbol csym = tree.sym;
+ enter.typeEnvs.remove(csym);
+ chk.compiled.remove(csym.flatname);
+ syms.classes.remove(csym.flatname);
+ super.visitClassDef(tree);
+ }
+ };
+
+ /**
+ * A deferred context is created on each method check. A deferred context is
+ * used to keep track of information associated with the method check, such as
+ * the symbol of the method being checked, the overload resolution phase,
+ * the kind of attribution mode to be applied to deferred types and so forth.
+ * As deferred types are processed (by the method check routine) stuck AST nodes
+ * are added (as new deferred attribution nodes) to this context. The complete()
+ * routine makes sure that all pending nodes are properly processed, by
+ * progressively instantiating all inference variables on which one or more
+ * deferred attribution node is stuck.
+ */
+ class DeferredAttrContext {
+
+ /** attribution mode */
+ final AttrMode mode;
+
+ /** symbol of the method being checked */
+ final Symbol msym;
+
+ /** method resolution step */
+ final Resolve.MethodResolutionPhase phase;
+
+ /** inference context */
+ final InferenceContext inferenceContext;
+
+ /** list of deferred attribution nodes to be processed */
+ ArrayList<DeferredAttrNode> deferredAttrNodes = new ArrayList<DeferredAttrNode>();
+
+ DeferredAttrContext(AttrMode mode, Symbol msym, MethodResolutionPhase phase, InferenceContext inferenceContext) {
+ this.mode = mode;
+ this.msym = msym;
+ this.phase = phase;
+ this.inferenceContext = inferenceContext;
+ }
+
+ /**
+ * Adds a node to the list of deferred attribution nodes - used by Resolve.rawCheckArgumentsApplicable
+ * Nodes added this way act as 'roots' for the out-of-order method checking process.
+ */
+ void addDeferredAttrNode(final DeferredType dt, ResultInfo resultInfo, List<Type> stuckVars) {
+ deferredAttrNodes.add(new DeferredAttrNode(dt, resultInfo, stuckVars));
+ }
+
+ /**
+ * Incrementally process all nodes, by skipping 'stuck' nodes and attributing
+ * 'unstuck' ones. If at any point no progress can be made (no 'unstuck' nodes)
+ * some inference variable might get eagerly instantiated so that all nodes
+ * can be type-checked.
+ */
+ void complete() {
+ while (!deferredAttrNodes.isEmpty()) {
+ Set<Type> stuckVars = new HashSet<Type>();
+ boolean progress = false;
+ //scan a defensive copy of the node list - this is because a deferred
+ //attribution round can add new nodes to the list
+ for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) {
+ if (!deferredAttrNode.isStuck()) {
+ deferredAttrNode.process();
+ deferredAttrNodes.remove(deferredAttrNode);
+ progress = true;
+ } else {
+ stuckVars.addAll(deferredAttrNode.stuckVars);
+ }
+ }
+ if (!progress) {
+ //remove all variables that have already been instantiated
+ //from the list of stuck variables
+ inferenceContext.solveAny(inferenceContext.freeVarsIn(List.from(stuckVars)), types, infer);
+ inferenceContext.notifyChange(types);
+ }
+ }
+ }
+
+ /**
+ * Class representing a deferred attribution node. It keeps track of
+ * a deferred type, along with the expected target type information.
+ */
+ class DeferredAttrNode implements Infer.InferenceContext.FreeTypeListener {
+
+ /** underlying deferred type */
+ DeferredType dt;
+
+ /** underlying target type information */
+ ResultInfo resultInfo;
+
+ /** list of uninferred inference variables causing this node to be stuck */
+ List<Type> stuckVars;
+
+ DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, List<Type> stuckVars) {
+ this.dt = dt;
+ this.resultInfo = resultInfo;
+ this.stuckVars = stuckVars;
+ if (!stuckVars.isEmpty()) {
+ resultInfo.checkContext.inferenceContext().addFreeTypeListener(stuckVars, this);
+ }
+ }
+
+ @Override
+ public void typesInferred(InferenceContext inferenceContext) {
+ stuckVars = List.nil();
+ resultInfo = resultInfo.dup(inferenceContext.asInstType(resultInfo.pt, types));
+ }
+
+ /**
+ * is this node stuck?
+ */
+ boolean isStuck() {
+ return stuckVars.nonEmpty();
+ }
+
+ /**
+ * Process a deferred attribution node.
+ * Invariant: a stuck node cannot be processed.
+ */
+ void process() {
+ if (isStuck()) {
+ throw new IllegalStateException("Cannot process a stuck deferred node");
+ }
+ dt.check(resultInfo);
+ }
+ }
+ }
+
+ /** an empty deferred attribution context - all methods throw exceptions */
+ final DeferredAttrContext emptyDeferredAttrContext =
+ new DeferredAttrContext(null, null, null, null) {
+ @Override
+ void addDeferredAttrNode(DeferredType dt, ResultInfo ri, List<Type> stuckVars) {
+ Assert.error("Empty deferred context!");
+ }
+ @Override
+ void complete() {
+ Assert.error("Empty deferred context!");
+ }
+ };
+
+ /**
+ * Map a list of types possibly containing one or more deferred types
+ * into a list of ordinary types. Each deferred type D is mapped into a type T,
+ * where T is computed by retrieving the type that has already been
+ * computed for D during a previous deferred attribution round of the given kind.
+ */
+ class DeferredTypeMap extends Type.Mapping {
+
+ DeferredAttrContext deferredAttrContext;
+
+ protected DeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
+ super(String.format("deferredTypeMap[%s]", mode));
+ this.deferredAttrContext = new DeferredAttrContext(mode, msym, phase, infer.emptyContext);
+ }
+
+ protected boolean validState(DeferredType dt) {
+ return dt.mode != null &&
+ deferredAttrContext.mode.ordinal() <= dt.mode.ordinal();
+ }
+
+ @Override
+ public Type apply(Type t) {
+ if (t.tag != DEFERRED) {
+ return t.map(this);
+ } else {
+ DeferredType dt = (DeferredType)t;
+ Assert.check(validState(dt));
+ return typeOf(dt);
+ }
+ }
+
+ protected Type typeOf(DeferredType dt) {
+ switch (deferredAttrContext.mode) {
+ case CHECK:
+ return dt.tree.type == null ? Type.noType : dt.tree.type;
+ case SPECULATIVE:
+ return dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase);
+ }
+ Assert.error();
+ return null;
+ }
+ }
+
+ /**
+ * Specialized recovery deferred mapping.
+ * Each deferred type D is mapped into a type T, where T is computed either by
+ * (i) retrieving the type that has already been computed for D during a previous
+ * attribution round (as before), or (ii) by synthesizing a new type R for D
+ * (the latter step is useful in a recovery scenario).
+ */
+ public class RecoveryDeferredTypeMap extends DeferredTypeMap {
+
+ public RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
+ super(mode, msym, phase);
+ }
+
+ @Override
+ protected Type typeOf(DeferredType dt) {
+ Type owntype = super.typeOf(dt);
+ return owntype.tag == NONE ?
+ recover(dt) : owntype;
+ }
+
+ @Override
+ protected boolean validState(DeferredType dt) {
+ return true;
+ }
+
+ /**
+ * Synthesize a type for a deferred type that hasn't been previously
+ * reduced to an ordinary type. Functional deferred types and conditionals
+ * are mapped to themselves, in order to have a richer diagnostic
+ * representation. Remaining deferred types are attributed using
+ * a default expected type (j.l.Object).
+ */
+ private Type recover(DeferredType dt) {
+ dt.check(new RecoveryInfo());
+ switch (TreeInfo.skipParens(dt.tree).getTag()) {
+ case LAMBDA:
+ case REFERENCE:
+ case CONDEXPR:
+ //propagate those deferred types to the
+ //diagnostic formatter
+ return dt;
+ default:
+ return super.apply(dt);
+ }
+ }
+
+ class RecoveryInfo extends ResultInfo {
+
+ public RecoveryInfo() {
+ attr.super(Kinds.VAL, Type.recoveryType, new Check.NestedCheckContext(chk.basicHandler) {
+ @Override
+ public DeferredAttrContext deferredAttrContext() {
+ return deferredAttrContext;
+ }
+ @Override
+ public boolean compatible(Type found, Type req, Warner warn) {
+ return true;
+ }
+ @Override
+ public void report(DiagnosticPosition pos, JCDiagnostic details) {
+ //do nothing
+ }
+ });
+ }
+
+ @Override
+ protected Type check(DiagnosticPosition pos, Type found) {
+ return chk.checkNonVoid(pos, super.check(pos, found));
+ }
+ }
+ }
+
+ /**
+ * Retrieves the list of inference variables that need to be inferred before
+ * an AST node can be type-checked
+ */
+ @SuppressWarnings("fallthrough")
+ List<Type> stuckVars(JCExpression tree, ResultInfo resultInfo) {
+ switch (tree.getTag()) {
+ case LAMBDA:
+ case REFERENCE:
+ Assert.error("not supported yet");
+ default:
+ return List.nil();
+ }
+ }
+}
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java Thu Oct 04 13:04:53 2012 +0100
@@ -29,6 +29,7 @@
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
+import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
import com.sun.tools.javac.comp.Resolve.InapplicableMethodException;
import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode;
import com.sun.tools.javac.tree.JCTree;
@@ -62,6 +63,7 @@
Types types;
Check chk;
Resolve rs;
+ DeferredAttr deferredAttr;
Log log;
JCDiagnostic.Factory diags;
@@ -77,6 +79,7 @@
syms = Symtab.instance(context);
types = Types.instance(context);
rs = Resolve.instance(context);
+ deferredAttr = DeferredAttr.instance(context);
log = Log.instance(context);
chk = Check.instance(context);
diags = JCDiagnostic.Factory.instance(context);
@@ -187,7 +190,7 @@
Attr.ResultInfo resultInfo,
Warner warn) throws InferenceException {
Type to = resultInfo.pt;
- if (to.tag == NONE) {
+ if (to.tag == NONE || resultInfo.checkContext.inferenceContext().free(resultInfo.pt)) {
to = mtype.getReturnType().tag <= VOID ?
mtype.getReturnType() : syms.objectType;
}
@@ -268,14 +271,16 @@
List<Type> argtypes,
boolean allowBoxing,
boolean useVarargs,
+ Resolve.MethodResolutionContext resolveContext,
Warner warn) throws InferenceException {
//-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
final InferenceContext inferenceContext = new InferenceContext(tvars, this);
inferenceException.clear();
try {
- rs.checkRawArgumentsAcceptable(env, inferenceContext, argtypes, mt.getParameterTypes(),
- allowBoxing, useVarargs, warn, new InferenceCheckHandler(inferenceContext));
+ rs.checkRawArgumentsAcceptable(env, msym, resolveContext.attrMode(), inferenceContext,
+ argtypes, mt.getParameterTypes(), allowBoxing, useVarargs, warn,
+ new InferenceCheckHandler(inferenceContext));
// minimize as yet undetermined type variables
for (Type t : inferenceContext.undetvars) {
@@ -469,6 +474,7 @@
*/
Type instantiatePolymorphicSignatureInstance(Env<AttrContext> env,
MethodSymbol spMethod, // sig. poly. method or null if none
+ Resolve.MethodResolutionContext resolveContext,
List<Type> argtypes) {
final Type restype;
@@ -498,7 +504,7 @@
restype = syms.objectType;
}
- List<Type> paramtypes = Type.map(argtypes, implicitArgType);
+ List<Type> paramtypes = Type.map(argtypes, new ImplicitArgType(spMethod, resolveContext.step));
List<Type> exType = spMethod != null ?
spMethod.getThrownTypes() :
List.of(syms.throwableType); // make it throw all exceptions
@@ -510,16 +516,21 @@
return mtype;
}
//where
- Mapping implicitArgType = new Mapping ("implicitArgType") {
- public Type apply(Type t) {
- t = types.erasure(t);
- if (t.tag == BOT)
- // nulls type as the marker type Null (which has no instances)
- // infer as java.lang.Void for now
- t = types.boxedClass(syms.voidType).type;
- return t;
- }
- };
+ class ImplicitArgType extends DeferredAttr.DeferredTypeMap {
+
+ public ImplicitArgType(Symbol msym, Resolve.MethodResolutionPhase phase) {
+ deferredAttr.super(AttrMode.SPECULATIVE, msym, phase);
+ }
+
+ public Type apply(Type t) {
+ t = types.erasure(super.apply(t));
+ if (t.tag == BOT)
+ // nulls type as the marker type Null (which has no instances)
+ // infer as java.lang.Void for now
+ t = types.boxedClass(syms.voidType).type;
+ return t;
+ }
+ }
/**
* Mapping that turns inference variables into undet vars
@@ -708,6 +719,22 @@
throw thrownEx;
}
}
+
+ void solveAny(List<Type> varsToSolve, Types types, Infer infer) {
+ boolean progress = false;
+ for (Type t : varsToSolve) {
+ UndetVar uv = (UndetVar)asFree(t, types);
+ if (uv.inst == null) {
+ infer.minimizeInst(uv, Warner.noWarnings);
+ if (uv.inst != null) {
+ progress = true;
+ }
+ }
+ }
+ if (!progress) {
+ throw infer.inferenceException.setMessage("cyclic.inference", varsToSolve);
+ }
+ }
}
final InferenceContext emptyContext = new InferenceContext(List.<Type>nil(), this);
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java Thu Oct 04 13:04:53 2012 +0100
@@ -1998,7 +1998,7 @@
// replace with <BoxedClass>.TYPE
ClassSymbol c = types.boxedClass(type);
Symbol typeSym =
- rs.access(
+ rs.accessBase(
rs.findIdentInType(attrEnv, c.type, names.TYPE, VAR),
pos, c.type, names.TYPE, true);
if (typeSym.kind == VAR)
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java Thu Oct 04 13:04:53 2012 +0100
@@ -604,6 +604,10 @@
env.dup(tree, env.info.dup(env.info.scope.dupUnshared()));
localEnv.enclMethod = tree;
localEnv.info.scope.owner = tree.sym;
+ if (tree.sym.type != null) {
+ //when this is called in the enter stage, there's no type to be set
+ localEnv.info.returnResult = attr.new ResultInfo(VAL, tree.sym.type.getReturnType());
+ }
if ((tree.mods.flags & STATIC) != 0) localEnv.info.staticLevel++;
return localEnv;
}
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Thu Oct 04 13:04:53 2012 +0100
@@ -31,6 +31,9 @@
import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.comp.Attr.ResultInfo;
import com.sun.tools.javac.comp.Check.CheckContext;
+import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
+import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext;
+import com.sun.tools.javac.comp.DeferredAttr.DeferredType;
import com.sun.tools.javac.comp.Infer.InferenceContext;
import com.sun.tools.javac.comp.Infer.InferenceContext.FreeTypeListener;
import com.sun.tools.javac.comp.Resolve.MethodResolutionContext.Candidate;
@@ -42,15 +45,12 @@
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumMap;
import java.util.EnumSet;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
-import java.util.Set;
import javax.lang.model.element.ElementVisitor;
@@ -77,6 +77,7 @@
Log log;
Symtab syms;
Attr attr;
+ DeferredAttr deferredAttr;
Check chk;
Infer infer;
ClassReader reader;
@@ -109,6 +110,7 @@
names = Names.instance(context);
log = Log.instance(context);
attr = Attr.instance(context);
+ deferredAttr = DeferredAttr.instance(context);
chk = Check.instance(context);
infer = Infer.instance(context);
reader = ClassReader.instance(context);
@@ -219,9 +221,12 @@
}
}
String key = success ? "verbose.resolve.multi" : "verbose.resolve.multi.1";
+ List<Type> argtypes2 = Type.map(argtypes,
+ deferredAttr.new RecoveryDeferredTypeMap(AttrMode.SPECULATIVE, bestSoFar, currentResolutionContext.step));
JCDiagnostic main = diags.note(log.currentSource(), dpos, key, name,
site.tsym, mostSpecificPos, currentResolutionContext.step,
- methodArguments(argtypes), methodArguments(typeargtypes));
+ methodArguments(argtypes2),
+ methodArguments(typeargtypes));
JCDiagnostic d = new JCDiagnostic.MultilineDiagnostic(main, subDiags.toList());
log.report(d);
}
@@ -501,13 +506,34 @@
argtypes,
allowBoxing,
useVarargs,
+ currentResolutionContext,
warn);
- checkRawArgumentsAcceptable(env, argtypes, mt.getParameterTypes(),
+ checkRawArgumentsAcceptable(env, m, argtypes, mt.getParameterTypes(),
allowBoxing, useVarargs, warn);
return mt;
}
+ Type checkMethod(Env<AttrContext> env,
+ Type site,
+ Symbol m,
+ ResultInfo resultInfo,
+ List<Type> argtypes,
+ List<Type> typeargtypes,
+ Warner warn) {
+ MethodResolutionContext prevContext = currentResolutionContext;
+ try {
+ currentResolutionContext = new MethodResolutionContext();
+ currentResolutionContext.attrMode = DeferredAttr.AttrMode.CHECK;
+ MethodResolutionPhase step = currentResolutionContext.step = env.info.pendingResolutionPhase;
+ return rawInstantiate(env, site, m, resultInfo, argtypes, typeargtypes,
+ step.isBoxingRequired(), step.isVarargsRequired(), warn);
+ }
+ finally {
+ currentResolutionContext = prevContext;
+ }
+ }
+
/** Same but returns null instead throwing a NoInstanceException
*/
Type instantiate(Env<AttrContext> env,
@@ -530,13 +556,14 @@
/** Check if a parameter list accepts a list of args.
*/
boolean argumentsAcceptable(Env<AttrContext> env,
+ Symbol msym,
List<Type> argtypes,
List<Type> formals,
boolean allowBoxing,
boolean useVarargs,
Warner warn) {
try {
- checkRawArgumentsAcceptable(env, argtypes, formals, allowBoxing, useVarargs, warn);
+ checkRawArgumentsAcceptable(env, msym, argtypes, formals, allowBoxing, useVarargs, warn);
return true;
} catch (InapplicableMethodException ex) {
return false;
@@ -583,12 +610,13 @@
};
void checkRawArgumentsAcceptable(Env<AttrContext> env,
+ Symbol msym,
List<Type> argtypes,
List<Type> formals,
boolean allowBoxing,
boolean useVarargs,
Warner warn) {
- checkRawArgumentsAcceptable(env, infer.emptyContext, argtypes, formals,
+ checkRawArgumentsAcceptable(env, msym, currentResolutionContext.attrMode(), infer.emptyContext, argtypes, formals,
allowBoxing, useVarargs, warn, resolveHandler);
}
@@ -598,35 +626,41 @@
* compatible (by method invocation conversion) with the types in F.
*
* Since this routine is shared between overload resolution and method
- * type-inference, it is crucial that actual types are converted to the
- * corresponding 'undet' form (i.e. where inference variables are replaced
- * with undetvars) so that constraints can be propagated and collected.
+ * type-inference, a (possibly empty) inference context is used to convert
+ * formal types to the corresponding 'undet' form ahead of a compatibility
+ * check so that constraints can be propagated and collected.
*
- * Moreover, if one or more types in A is a poly type, this routine calls
- * Infer.instantiateArg in order to complete the poly type (this might involve
- * deferred attribution).
+ * Moreover, if one or more types in A is a deferred type, this routine uses
+ * DeferredAttr in order to perform deferred attribution. If one or more actual
+ * deferred types are stuck, they are placed in a queue and revisited later
+ * after the remainder of the arguments have been seen. If this is not sufficient
+ * to 'unstuck' the argument, a cyclic inference error is called out.
*
* A method check handler (see above) is used in order to report errors.
*/
void checkRawArgumentsAcceptable(final Env<AttrContext> env,
+ Symbol msym,
+ DeferredAttr.AttrMode mode,
final Infer.InferenceContext inferenceContext,
List<Type> argtypes,
List<Type> formals,
boolean allowBoxing,
boolean useVarargs,
Warner warn,
- MethodCheckHandler handler) {
+ final MethodCheckHandler handler) {
Type varargsFormal = useVarargs ? formals.last() : null;
- ListBuffer<Type> checkedArgs = ListBuffer.lb();
if (varargsFormal == null &&
argtypes.size() != formals.size()) {
throw handler.arityMismatch(); // not enough args
}
+ DeferredAttr.DeferredAttrContext deferredAttrContext =
+ deferredAttr.new DeferredAttrContext(mode, msym, currentResolutionContext.step, inferenceContext);
+
while (argtypes.nonEmpty() && formals.head != varargsFormal) {
- ResultInfo resultInfo = methodCheckResult(formals.head, allowBoxing, false, inferenceContext, handler, warn);
- checkedArgs.append(resultInfo.check(env.tree.pos(), argtypes.head));
+ ResultInfo mresult = methodCheckResult(formals.head, allowBoxing, false, inferenceContext, deferredAttrContext, handler, warn);
+ mresult.check(null, argtypes.head);
argtypes = argtypes.tail;
formals = formals.tail;
}
@@ -638,15 +672,17 @@
if (useVarargs) {
//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);
+ final Type elt = types.elemtype(varargsFormal);
+ ResultInfo mresult = methodCheckResult(elt, allowBoxing, true, inferenceContext, deferredAttrContext, handler, warn);
while (argtypes.nonEmpty()) {
- ResultInfo resultInfo = methodCheckResult(elt, allowBoxing, true, inferenceContext, handler, warn);
- checkedArgs.append(resultInfo.check(env.tree.pos(), argtypes.head));
+ mresult.check(null, argtypes.head);
argtypes = argtypes.tail;
}
//check varargs element type accessibility
varargsAccessible(env, elt, handler, inferenceContext);
}
+
+ deferredAttrContext.complete();
}
void varargsAccessible(final Env<AttrContext> env, final Type t, final Resolve.MethodCheckHandler handler, final InferenceContext inferenceContext) {
@@ -674,12 +710,15 @@
MethodCheckHandler handler;
boolean useVarargs;
Infer.InferenceContext inferenceContext;
+ DeferredAttrContext deferredAttrContext;
Warner rsWarner;
- public MethodCheckContext(MethodCheckHandler handler, boolean useVarargs, Infer.InferenceContext inferenceContext, Warner rsWarner) {
+ public MethodCheckContext(MethodCheckHandler handler, boolean useVarargs,
+ Infer.InferenceContext inferenceContext, DeferredAttrContext deferredAttrContext, Warner rsWarner) {
this.handler = handler;
this.useVarargs = useVarargs;
this.inferenceContext = inferenceContext;
+ this.deferredAttrContext = deferredAttrContext;
this.rsWarner = rsWarner;
}
@@ -694,6 +733,10 @@
public InferenceContext inferenceContext() {
return inferenceContext;
}
+
+ public DeferredAttrContext deferredAttrContext() {
+ return deferredAttrContext;
+ }
}
/**
@@ -702,8 +745,9 @@
*/
class StrictMethodContext extends MethodCheckContext {
- public StrictMethodContext(MethodCheckHandler handler, boolean useVarargs, Infer.InferenceContext inferenceContext, Warner rsWarner) {
- super(handler, useVarargs, inferenceContext, rsWarner);
+ public StrictMethodContext(MethodCheckHandler handler, boolean useVarargs,
+ Infer.InferenceContext inferenceContext, DeferredAttrContext deferredAttrContext, Warner rsWarner) {
+ super(handler, useVarargs, inferenceContext, deferredAttrContext, rsWarner);
}
public boolean compatible(Type found, Type req, Warner warn) {
@@ -717,8 +761,9 @@
*/
class LooseMethodContext extends MethodCheckContext {
- public LooseMethodContext(MethodCheckHandler handler, boolean useVarargs, Infer.InferenceContext inferenceContext, Warner rsWarner) {
- super(handler, useVarargs, inferenceContext, rsWarner);
+ public LooseMethodContext(MethodCheckHandler handler, boolean useVarargs,
+ Infer.InferenceContext inferenceContext, DeferredAttrContext deferredAttrContext, Warner rsWarner) {
+ super(handler, useVarargs, inferenceContext, deferredAttrContext, rsWarner);
}
public boolean compatible(Type found, Type req, Warner warn) {
@@ -730,16 +775,37 @@
* Create a method check context to be used during method applicability check
*/
ResultInfo methodCheckResult(Type to, boolean allowBoxing, boolean useVarargs,
- Infer.InferenceContext inferenceContext, MethodCheckHandler methodHandler, Warner rsWarner) {
+ Infer.InferenceContext inferenceContext, DeferredAttr.DeferredAttrContext deferredAttrContext,
+ MethodCheckHandler methodHandler, Warner rsWarner) {
MethodCheckContext checkContext = allowBoxing ?
- new LooseMethodContext(methodHandler, useVarargs, inferenceContext, rsWarner) :
- new StrictMethodContext(methodHandler, useVarargs, inferenceContext, rsWarner);
- return attr.new ResultInfo(VAL, to, checkContext) {
- @Override
- protected Type check(DiagnosticPosition pos, Type found) {
+ new LooseMethodContext(methodHandler, useVarargs, inferenceContext, deferredAttrContext, rsWarner) :
+ new StrictMethodContext(methodHandler, useVarargs, inferenceContext, deferredAttrContext, rsWarner);
+ return new MethodResultInfo(to, checkContext, deferredAttrContext);
+ }
+
+ class MethodResultInfo extends ResultInfo {
+
+ DeferredAttr.DeferredAttrContext deferredAttrContext;
+
+ public MethodResultInfo(Type pt, MethodCheckContext checkContext, DeferredAttr.DeferredAttrContext deferredAttrContext) {
+ attr.super(VAL, pt, checkContext);
+ this.deferredAttrContext = deferredAttrContext;
+ }
+
+ @Override
+ protected Type check(DiagnosticPosition pos, Type found) {
+ if (found.tag == DEFERRED) {
+ DeferredType dt = (DeferredType)found;
+ return dt.check(this);
+ } else {
return super.check(pos, chk.checkNonVoid(pos, types.capture(types.upperBound(found.baseType()))));
}
- };
+ }
+
+ @Override
+ protected MethodResultInfo dup(Type newPt) {
+ return new MethodResultInfo(newPt, (MethodCheckContext)checkContext, deferredAttrContext);
+ }
}
public static class InapplicableMethodException extends RuntimeException {
@@ -1614,14 +1680,41 @@
*
* @param sym The symbol that was found, or a ResolveError.
* @param pos The position to use for error reporting.
+ * @param location The symbol the served as a context for this lookup
* @param site The original type from where the selection took place.
* @param name The symbol's name.
+ * @param qualified Did we get here through a qualified expression resolution?
* @param argtypes The invocation's value arguments,
* if we looked for a method.
* @param typeargtypes The invocation's type arguments,
* if we looked for a method.
+ * @param logResolveHelper helper class used to log resolve errors
*/
- Symbol access(Symbol sym,
+ Symbol accessInternal(Symbol sym,
+ DiagnosticPosition pos,
+ Symbol location,
+ Type site,
+ Name name,
+ boolean qualified,
+ List<Type> argtypes,
+ List<Type> typeargtypes,
+ LogResolveHelper logResolveHelper) {
+ if (sym.kind >= AMBIGUOUS) {
+ ResolveError errSym = (ResolveError)sym;
+ sym = errSym.access(name, qualified ? site.tsym : syms.noSymbol);
+ argtypes = logResolveHelper.getArgumentTypes(errSym, sym, name, argtypes);
+ if (logResolveHelper.resolveDiagnosticNeeded(site, argtypes, typeargtypes)) {
+ logResolveError(errSym, pos, location, site, name, argtypes, typeargtypes);
+ }
+ }
+ return sym;
+ }
+
+ /**
+ * Variant of the generalized access routine, to be used for generating method
+ * resolution diagnostics
+ */
+ Symbol accessMethod(Symbol sym,
DiagnosticPosition pos,
Symbol location,
Type site,
@@ -1629,53 +1722,91 @@
boolean qualified,
List<Type> argtypes,
List<Type> typeargtypes) {
- if (sym.kind >= AMBIGUOUS) {
- ResolveError errSym = (ResolveError)sym;
- if (!site.isErroneous() &&
- !Type.isErroneous(argtypes) &&
- (typeargtypes==null || !Type.isErroneous(typeargtypes)))
- logResolveError(errSym, pos, location, site, name, argtypes, typeargtypes);
- sym = errSym.access(name, qualified ? site.tsym : syms.noSymbol);
- }
- return sym;
+ return accessInternal(sym, pos, location, site, name, qualified, argtypes, typeargtypes, methodLogResolveHelper);
}
- /** Same as original access(), but without location.
+ /** Same as original accessMethod(), but without location.
*/
- Symbol access(Symbol sym,
+ Symbol accessMethod(Symbol sym,
DiagnosticPosition pos,
Type site,
Name name,
boolean qualified,
List<Type> argtypes,
List<Type> typeargtypes) {
- return access(sym, pos, site.tsym, site, name, qualified, argtypes, typeargtypes);
+ return accessMethod(sym, pos, site.tsym, site, name, qualified, argtypes, typeargtypes);
}
- /** Same as original access(), but without type arguments and arguments.
+ /**
+ * Variant of the generalized access routine, to be used for generating variable,
+ * type resolution diagnostics
*/
- Symbol access(Symbol sym,
+ Symbol accessBase(Symbol sym,
DiagnosticPosition pos,
Symbol location,
Type site,
Name name,
boolean qualified) {
- if (sym.kind >= AMBIGUOUS)
- return access(sym, pos, location, site, name, qualified, List.<Type>nil(), null);
- else
- return sym;
+ return accessInternal(sym, pos, location, site, name, qualified, List.<Type>nil(), null, basicLogResolveHelper);
}
- /** Same as original access(), but without location, type arguments and arguments.
+ /** Same as original accessBase(), but without location.
*/
- Symbol access(Symbol sym,
+ Symbol accessBase(Symbol sym,
DiagnosticPosition pos,
Type site,
Name name,
boolean qualified) {
- return access(sym, pos, site.tsym, site, name, qualified);
+ return accessBase(sym, pos, site.tsym, site, name, qualified);
+ }
+
+ interface LogResolveHelper {
+ boolean resolveDiagnosticNeeded(Type site, List<Type> argtypes, List<Type> typeargtypes);
+ List<Type> getArgumentTypes(ResolveError errSym, Symbol accessedSym, Name name, List<Type> argtypes);
}
+ LogResolveHelper basicLogResolveHelper = new LogResolveHelper() {
+ public boolean resolveDiagnosticNeeded(Type site, List<Type> argtypes, List<Type> typeargtypes) {
+ return !site.isErroneous();
+ }
+ public List<Type> getArgumentTypes(ResolveError errSym, Symbol accessedSym, Name name, List<Type> argtypes) {
+ return argtypes;
+ }
+ };
+
+ LogResolveHelper methodLogResolveHelper = new LogResolveHelper() {
+ public boolean resolveDiagnosticNeeded(Type site, List<Type> argtypes, List<Type> typeargtypes) {
+ return !site.isErroneous() &&
+ !Type.isErroneous(argtypes) &&
+ (typeargtypes == null || !Type.isErroneous(typeargtypes));
+ }
+ public List<Type> getArgumentTypes(ResolveError errSym, Symbol accessedSym, Name name, List<Type> argtypes) {
+ if (syms.operatorNames.contains(name)) {
+ return argtypes;
+ } else {
+ Symbol msym = errSym.kind == WRONG_MTH ?
+ ((InapplicableSymbolError)errSym).errCandidate().sym : accessedSym;
+
+ List<Type> argtypes2 = Type.map(argtypes,
+ deferredAttr.new RecoveryDeferredTypeMap(AttrMode.SPECULATIVE, msym, currentResolutionContext.firstErroneousResolutionPhase()));
+
+ if (msym != accessedSym) {
+ //fixup deferred type caches - this 'hack' is required because the symbol
+ //returned by InapplicableSymbolError.access() will hide the candidate
+ //method symbol that can be used for lookups in the speculative cache,
+ //causing problems in Attr.checkId()
+ for (Type t : argtypes) {
+ if (t.tag == DEFERRED) {
+ DeferredType dt = (DeferredType)t;
+ dt.speculativeCache.dupAllTo(msym, accessedSym);
+ }
+ }
+ }
+ return argtypes2;
+ }
+ }
+ };
+
/** Check that sym is not an abstract method.
*/
void checkNonAbstract(DiagnosticPosition pos, Symbol sym) {
@@ -1734,7 +1865,7 @@
*/
Symbol resolveIdent(DiagnosticPosition pos, Env<AttrContext> env,
Name name, int kind) {
- return access(
+ return accessBase(
findIdent(env, name, kind),
pos, env.enclClass.sym.type, name, false);
}
@@ -1759,19 +1890,19 @@
while (steps.nonEmpty() &&
steps.head.isApplicable(boxingEnabled, varargsEnabled) &&
sym.kind >= ERRONEOUS) {
- currentResolutionContext.step = steps.head;
+ currentResolutionContext.step = env.info.pendingResolutionPhase = steps.head;
sym = findFun(env, name, argtypes, typeargtypes,
steps.head.isBoxingRequired,
- env.info.varArgs = steps.head.isVarargsRequired);
+ steps.head.isVarargsRequired);
currentResolutionContext.resolutionCache.put(steps.head, sym);
steps = steps.tail;
}
if (sym.kind >= AMBIGUOUS) {//if nothing is found return the 'first' error
MethodResolutionPhase errPhase =
currentResolutionContext.firstErroneousResolutionPhase();
- sym = access(currentResolutionContext.resolutionCache.get(errPhase),
+ sym = accessMethod(currentResolutionContext.resolutionCache.get(errPhase),
pos, env.enclClass.sym.type, name, false, argtypes, typeargtypes);
- env.info.varArgs = errPhase.isVarargsRequired;
+ env.info.pendingResolutionPhase = errPhase;
}
return sym;
}
@@ -1811,10 +1942,10 @@
while (steps.nonEmpty() &&
steps.head.isApplicable(boxingEnabled, varargsEnabled) &&
sym.kind >= ERRONEOUS) {
- currentResolutionContext.step = steps.head;
+ currentResolutionContext.step = env.info.pendingResolutionPhase = steps.head;
sym = findMethod(env, site, name, argtypes, typeargtypes,
steps.head.isBoxingRequired(),
- env.info.varArgs = steps.head.isVarargsRequired(), false);
+ steps.head.isVarargsRequired(), false);
currentResolutionContext.resolutionCache.put(steps.head, sym);
steps = steps.tail;
}
@@ -1822,13 +1953,13 @@
//if nothing is found return the 'first' error
MethodResolutionPhase errPhase =
currentResolutionContext.firstErroneousResolutionPhase();
- sym = access(currentResolutionContext.resolutionCache.get(errPhase),
+ sym = accessMethod(currentResolutionContext.resolutionCache.get(errPhase),
pos, location, site, name, true, argtypes, typeargtypes);
- env.info.varArgs = errPhase.isVarargsRequired;
+ env.info.pendingResolutionPhase = errPhase;
} else if (allowMethodHandles) {
MethodSymbol msym = (MethodSymbol)sym;
if (msym.isSignaturePolymorphic(types)) {
- env.info.varArgs = false;
+ env.info.pendingResolutionPhase = BASIC;
return findPolymorphicSignatureInstance(env, sym, argtypes);
}
}
@@ -1850,7 +1981,7 @@
Symbol spMethod,
List<Type> argtypes) {
Type mtype = infer.instantiatePolymorphicSignatureInstance(env,
- (MethodSymbol)spMethod, argtypes);
+ (MethodSymbol)spMethod, currentResolutionContext, argtypes);
for (Symbol sym : polymorphicSignatureScope.getElementsByName(spMethod.name)) {
if (types.isSameType(mtype, sym.type)) {
return sym;
@@ -1918,18 +2049,18 @@
while (steps.nonEmpty() &&
steps.head.isApplicable(boxingEnabled, varargsEnabled) &&
sym.kind >= ERRONEOUS) {
- currentResolutionContext.step = steps.head;
+ currentResolutionContext.step = env.info.pendingResolutionPhase = steps.head;
sym = findConstructor(pos, env, site, argtypes, typeargtypes,
steps.head.isBoxingRequired(),
- env.info.varArgs = steps.head.isVarargsRequired());
+ steps.head.isVarargsRequired());
currentResolutionContext.resolutionCache.put(steps.head, sym);
steps = steps.tail;
}
if (sym.kind >= AMBIGUOUS) {//if nothing is found return the 'first' error
MethodResolutionPhase errPhase = currentResolutionContext.firstErroneousResolutionPhase();
- sym = access(currentResolutionContext.resolutionCache.get(errPhase),
+ sym = accessMethod(currentResolutionContext.resolutionCache.get(errPhase),
pos, site, names.init, true, argtypes, typeargtypes);
- env.info.varArgs = errPhase.isVarargsRequired();
+ env.info.pendingResolutionPhase = errPhase;
}
return sym;
}
@@ -1961,10 +2092,10 @@
while (steps.nonEmpty() &&
steps.head.isApplicable(boxingEnabled, varargsEnabled) &&
sym.kind >= ERRONEOUS) {
- currentResolutionContext.step = steps.head;
+ currentResolutionContext.step = env.info.pendingResolutionPhase = steps.head;
sym = findDiamond(env, site, argtypes, typeargtypes,
steps.head.isBoxingRequired(),
- env.info.varArgs = steps.head.isVarargsRequired());
+ steps.head.isVarargsRequired());
currentResolutionContext.resolutionCache.put(steps.head, sym);
steps = steps.tail;
}
@@ -1986,8 +2117,8 @@
}
};
MethodResolutionPhase errPhase = currentResolutionContext.firstErroneousResolutionPhase();
- sym = access(errSym, pos, site, names.init, true, argtypes, typeargtypes);
- env.info.varArgs = errPhase.isVarargsRequired();
+ sym = accessMethod(errSym, pos, site, names.init, true, argtypes, typeargtypes);
+ env.info.pendingResolutionPhase = errPhase;
}
return sym;
}
@@ -2115,7 +2246,7 @@
if (boxingEnabled && sym.kind >= WRONG_MTHS)
sym = findMethod(env, syms.predefClass.type, name, argtypes,
null, true, false, true);
- return access(sym, pos, env.enclClass.sym.type, name,
+ return accessMethod(sym, pos, env.enclClass.sym.type, name,
false, argtypes, null);
}
finally {
@@ -2167,7 +2298,7 @@
Symbol sym = env1.info.scope.lookup(name).sym;
if (sym != null) {
if (staticOnly) sym = new StaticError(sym);
- return access(sym, pos, env.enclClass.sym.type,
+ return accessBase(sym, pos, env.enclClass.sym.type,
name, true);
}
}
@@ -2199,7 +2330,7 @@
Symbol sym = env1.info.scope.lookup(name).sym;
if (sym != null) {
if (staticOnly) sym = new StaticError(sym);
- return access(sym, pos, env.enclClass.sym.type,
+ return accessBase(sym, pos, env.enclClass.sym.type,
name, true);
}
}
@@ -2322,17 +2453,6 @@
Name name,
List<Type> argtypes,
List<Type> typeargtypes);
-
- /**
- * A name designates an operator if it consists
- * of a non-empty sequence of operator symbols {@literal +-~!/*%&|^<>= }
- */
- boolean isOperator(Name name) {
- int i = 0;
- while (i < name.getByteLength() &&
- "+-~!*/%&|^<>=".indexOf(name.getByteAt(i)) >= 0) i++;
- return i > 0 && i == name.getByteLength();
- }
}
/**
@@ -2393,7 +2513,7 @@
if (name == names.error)
return null;
- if (isOperator(name)) {
+ if (syms.operatorNames.contains(name)) {
boolean isUnaryOp = argtypes.size() == 1;
String key = argtypes.size() == 1 ?
"operator.cant.be.applied" :
@@ -2415,8 +2535,7 @@
hasLocation = !location.name.equals(names._this) &&
!location.name.equals(names._super);
}
- boolean isConstructor = kind == ABSENT_MTH &&
- name == names.table.names.init;
+ boolean isConstructor = kind == ABSENT_MTH && name == names.init;
KindName kindname = isConstructor ? KindName.CONSTRUCTOR : absentKind(kind);
Name idname = isConstructor ? site.tsym.name : name;
String errKey = getErrorKey(kindname, typeargtypes.nonEmpty(), hasLocation);
@@ -2496,7 +2615,7 @@
if (name == names.error)
return null;
- if (isOperator(name)) {
+ if (syms.operatorNames.contains(name)) {
boolean isUnaryOp = argtypes.size() == 1;
String key = argtypes.size() == 1 ?
"operator.cant.be.applied" :
@@ -2774,9 +2893,10 @@
private Map<MethodResolutionPhase, Symbol> resolutionCache =
new EnumMap<MethodResolutionPhase, Symbol>(MethodResolutionPhase.class);
- private MethodResolutionPhase step = null;
+ MethodResolutionPhase step = null;
private boolean internalResolution = false;
+ private DeferredAttr.AttrMode attrMode = DeferredAttr.AttrMode.SPECULATIVE;
private MethodResolutionPhase firstErroneousResolutionPhase() {
MethodResolutionPhase bestSoFar = BASIC;
@@ -2842,6 +2962,14 @@
return mtype != null;
}
}
+
+ DeferredAttr.AttrMode attrMode() {
+ return attrMode;
+ }
+
+ boolean internal() {
+ return internalResolution;
+ }
}
MethodResolutionContext currentResolutionContext = null;
--- a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Thu Oct 04 13:04:53 2012 +0100
@@ -1041,7 +1041,7 @@
genEndPos = true;
if (!taskListener.isEmpty())
taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));
- log.deferDiagnostics = true;
+ log.deferAll();
} else { // free resources
procEnvImpl.close();
}
@@ -1151,7 +1151,7 @@
if (c != this)
annotationProcessingOccurred = c.annotationProcessingOccurred = true;
// doProcessing will have handled deferred diagnostics
- Assert.check(c.log.deferDiagnostics == false
+ Assert.check(c.log.deferredDiagFilter == null
&& c.log.deferredDiagnostics.size() == 0);
return c;
} finally {
--- a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Thu Oct 04 13:04:53 2012 +0100
@@ -806,7 +806,7 @@
log = Log.instance(context);
log.nerrors = priorErrors;
log.nwarnings += priorWarnings;
- log.deferDiagnostics = true;
+ log.deferAll();
// the following is for the benefit of JavacProcessingEnvironment.getContext()
JavacProcessingEnvironment.this.context = context;
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Thu Oct 04 13:04:53 2012 +0100
@@ -635,6 +635,10 @@
second operand: {0}\n\
third operand : {1}
+# 0: message segment
+compiler.misc.incompatible.type.in.conditional=\
+ bad type in conditional expression; {0}
+
compiler.err.new.not.allowed.in.annotation=\
''new'' not allowed in an annotation
@@ -1701,6 +1705,10 @@
inferred: {0}\n\
equality constraints(s): {1}
+# 0: list of type
+compiler.misc.cyclic.inference=\
+ Cannot instantiate inference variables {0} because of an inference loop
+
# 0: symbol
compiler.misc.diamond=\
{0}<>
@@ -2086,6 +2094,9 @@
compiler.misc.type.null=\
<null>
+compiler.misc.type.conditional=\
+ conditional expression
+
# X#n (where n is an int id) is disambiguated tvar name
# 0: name, 1: number
compiler.misc.type.var=\
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java Thu Oct 04 13:04:53 2012 +0100
@@ -81,6 +81,12 @@
*/
DocCommentTable docComments = null;
+ /**
+ * A string sequence to be used when Pretty output should be constrained
+ * to fit into a given size
+ */
+ private final static String trimSequence = "[...]";
+
/** Align code to be indented to left margin.
*/
void align() throws IOException {
@@ -129,6 +135,27 @@
out.write(lineSep);
}
+ public static String toSimpleString(JCTree tree, int maxLength) {
+ StringWriter s = new StringWriter();
+ try {
+ new Pretty(s, false).printExpr(tree);
+ }
+ catch (IOException e) {
+ // should never happen, because StringWriter is defined
+ // never to throw any IOExceptions
+ throw new AssertionError(e);
+ }
+ //we need to (i) replace all line terminators with a space and (ii) remove
+ //occurrences of 'missing' in the Pretty output (generated when types are missing)
+ String res = s.toString().replaceAll("\\s+", " ").replaceAll("/\\*missing\\*/", "");
+ if (res.length() < maxLength) {
+ return res;
+ } else {
+ int split = (maxLength - trimSequence.length()) * 2 / 3;
+ return res.substring(0, split) + trimSequence + res.substring(split);
+ }
+ }
+
String lineSep = System.getProperty("line.separator");
/**************************************************************************
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java Thu Oct 04 13:04:53 2012 +0100
@@ -245,6 +245,23 @@
}
}
+ /** Return true if a a tree corresponds to a poly expression. */
+ public static boolean isPoly(JCTree tree, JCTree origin) {
+ switch (tree.getTag()) {
+ case APPLY:
+ case NEWCLASS:
+ case CONDEXPR:
+ return !origin.hasTag(TYPECAST);
+ case LAMBDA:
+ case REFERENCE:
+ return true;
+ case PARENS:
+ return isPoly(((JCParens)tree).expr, origin);
+ default:
+ return false;
+ }
+ }
+
/**
* Return true if the AST corresponds to a static select of the kind A.B
*/
--- a/langtools/src/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java Thu Oct 04 13:04:53 2012 +0100
@@ -489,7 +489,8 @@
* type referred by a given captured type C contains C itself) which might
* lead to infinite loops.
*/
- protected Printer printer = new Printer() {
+ protected Printer printer = new Printer(isRaw()) {
+
@Override
protected String localize(Locale locale, String key, Object... args) {
return AbstractDiagnosticFormatter.this.localize(locale, key, args);
--- a/langtools/src/share/classes/com/sun/tools/javac/util/List.java Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/List.java Thu Oct 04 13:04:53 2012 +0100
@@ -83,6 +83,19 @@
}
};
+ /** Returns the list obtained from 'l' after removing all elements 'elem'
+ */
+ public static <A> List<A> filter(List<A> l, A elem) {
+ Assert.checkNonNull(elem);
+ List<A> res = List.nil();
+ for (A a : l) {
+ if (a != null && !a.equals(elem)) {
+ res = res.prepend(a);
+ }
+ }
+ return res.reverse();
+ }
+
/** Construct a list consisting of given element.
*/
public static <A> List<A> of(A x1) {
@@ -120,6 +133,14 @@
return xs;
}
+ public static <A> List<A> from(Iterable<? extends A> coll) {
+ List<A> xs = nil();
+ for (A a : coll) {
+ xs = new List<A>(a, xs);
+ }
+ return xs;
+ }
+
/** Construct a list consisting of a given number of identical elements.
* @param len The number of elements in the list.
* @param init The value of each element.
--- a/langtools/src/share/classes/com/sun/tools/javac/util/Log.java Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/Log.java Thu Oct 04 13:04:53 2012 +0100
@@ -130,7 +130,7 @@
/**
* Deferred diagnostics
*/
- public boolean deferDiagnostics;
+ public Filter<JCDiagnostic> deferredDiagFilter;
public Queue<JCDiagnostic> deferredDiagnostics = new ListBuffer<JCDiagnostic>();
/** Construct a log with given I/O redirections.
@@ -450,7 +450,7 @@
/** Report selected deferred diagnostics, and clear the deferDiagnostics flag. */
public void reportDeferredDiagnostics(Set<JCDiagnostic.Kind> kinds) {
- deferDiagnostics = false;
+ deferredDiagFilter = null;
JCDiagnostic d;
while ((d = deferredDiagnostics.poll()) != null) {
if (kinds.contains(d.getKind()))
@@ -464,7 +464,7 @@
* reported so far, the diagnostic may be handed off to writeDiagnostic.
*/
public void report(JCDiagnostic diagnostic) {
- if (deferDiagnostics) {
+ if (deferredDiagFilter != null && deferredDiagFilter.accepts(diagnostic)) {
deferredDiagnostics.add(diagnostic);
return;
}
@@ -551,6 +551,18 @@
}
}
+ public void deferAll() {
+ deferredDiagFilter = new Filter<JCDiagnostic>() {
+ public boolean accepts(JCDiagnostic t) {
+ return true;
+ }
+ };
+ }
+
+ public void deferNone() {
+ deferredDiagFilter = null;
+ }
+
/** Find a localized string in the resource bundle.
* Because this method is static, it ignores the locale.
* Use localize(key, args) when possible.
--- a/langtools/src/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java Thu Oct 04 13:04:53 2012 +0100
@@ -325,6 +325,10 @@
*/
protected class RichPrinter extends Printer {
+ public RichPrinter() {
+ super(formatter.isRaw());
+ }
+
@Override
public String localize(Locale locale, String key, Object... args) {
return formatter.localize(locale, key, args);
@@ -393,11 +397,6 @@
}
@Override
- protected String printMethodArgs(List<Type> args, boolean varArgs, Locale locale) {
- return super.printMethodArgs(args, varArgs, locale);
- }
-
- @Override
public String visitClassSymbol(ClassSymbol s, Locale locale) {
String name = nameSimplifier.simplify(s);
if (name.length() == 0 ||
--- a/langtools/test/tools/javac/conditional/Conditional.java Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/test/tools/javac/conditional/Conditional.java Thu Oct 04 13:04:53 2012 +0100
@@ -27,6 +27,7 @@
* @summary Conditional operator applies assignment conversion
* @author Tim Hanson, BEA
*
+ * @compile -XDallowPoly Conditional.java
* @compile/fail Conditional.java
*/
--- a/langtools/test/tools/javac/diags/examples.not-yet.txt Sat Sep 29 09:00:58 2012 -0700
+++ b/langtools/test/tools/javac/diags/examples.not-yet.txt Thu Oct 04 13:04:53 2012 +0100
@@ -58,6 +58,7 @@
compiler.misc.fatal.err.cant.close # JavaCompiler
compiler.misc.file.does.not.contain.package
compiler.misc.illegal.start.of.class.file
+compiler.misc.cyclic.inference # Cannot happen w/o lambdas
compiler.misc.kindname.annotation
compiler.misc.kindname.enum
compiler.misc.kindname.package
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/IncompatibleTypesInConditional.java Thu Oct 04 13:04:53 2012 +0100
@@ -0,0 +1,35 @@
+/*
+ * 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
+// key: compiler.misc.incompatible.type.in.conditional
+// key: compiler.misc.inconvertible.types
+// options: -XDallowPoly
+
+class IncompatibleTypesInConditional {
+
+ interface A { }
+ interface B { }
+
+ B b = true ? (A)null : (B)null;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/TypeConditional.java Thu Oct 04 13:04:53 2012 +0100
@@ -0,0 +1,38 @@
+/*
+ * 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.cant.apply.symbol.1
+// key: compiler.misc.type.conditional
+// key: compiler.misc.no.args
+// key: compiler.misc.arg.length.mismatch
+// options: -XDallowPoly
+// run: simple
+
+class TypeConditional {
+
+ void m() { }
+
+ void test() {
+ m(true ? 1 : 2);
+ }
+}