--- 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);
}