diff -r c2315af9cc28 -r 950e8ac120f0 src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java --- a/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Mon Apr 15 14:17:30 2013 +0100 +++ b/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Mon Apr 15 14:18:30 2013 +0100 @@ -800,4 +800,219 @@ } } } + + /** + * Does the argument expression {@code expr} need speculative type-checking? + */ + boolean isDeferred(Env env, JCExpression expr) { + DeferredChecker dc = new DeferredChecker(env); + dc.scan(expr); + return dc.result.isPoly(); + } + + /** + * The kind of an argument expression. This is used by the analysis that + * determines as to whether speculative attribution is necessary. + */ + enum ArgumentExpressionKind { + + /** kind that denotes poly argument expression */ + POLY, + /** kind that denotes a standalone expression */ + NO_POLY, + /** kind that denotes a primitive/boxed standalone expression */ + PRIMITIVE; + + /** + * Does this kind denote a poly argument expression + */ + public final boolean isPoly() { + return this == POLY; + } + + /** + * Does this kind denote a primitive standalone expression + */ + public final boolean isPrimitive() { + return this == PRIMITIVE; + } + + /** + * Compute the kind of a standalone expression of a given type + */ + static ArgumentExpressionKind standaloneKind(Type type, Types types) { + return types.unboxedTypeOrType(type).isPrimitive() ? + ArgumentExpressionKind.PRIMITIVE : + ArgumentExpressionKind.NO_POLY; + } + + /** + * Compute the kind of a method argument expression given its symbol + */ + static ArgumentExpressionKind methodKind(Symbol sym, Types types) { + Type restype = sym.type.getReturnType(); + if (sym.type.hasTag(FORALL) && + restype.containsAny(((ForAll)sym.type).tvars)) { + return ArgumentExpressionKind.POLY; + } else { + return ArgumentExpressionKind.standaloneKind(restype, types); + } + } + } + + /** + * Tree scanner used for checking as to whether an argument expression + * requires speculative attribution + */ + final class DeferredChecker extends FilterScanner { + + Env env; + ArgumentExpressionKind result; + + public DeferredChecker(Env env) { + super(deferredCheckerTags); + this.env = env; + } + + @Override + public void visitLambda(JCLambda tree) { + //a lambda is always a poly expression + result = ArgumentExpressionKind.POLY; + } + + @Override + public void visitReference(JCMemberReference tree) { + //a method reference is always a poly expression + result = ArgumentExpressionKind.POLY; + } + + @Override + public void visitTypeCast(JCTypeCast tree) { + //a cast is always a standalone expression + result = ArgumentExpressionKind.NO_POLY; + } + + @Override + public void visitConditional(JCConditional tree) { + scan(tree.truepart); + if (!result.isPrimitive()) { + result = ArgumentExpressionKind.POLY; + return; + } + scan(tree.falsepart); + result = reduce(ArgumentExpressionKind.PRIMITIVE); + } + + @Override + public void visitNewClass(JCNewClass tree) { + result = (TreeInfo.isDiamond(tree) || attr.findDiamonds) ? + ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY; + } + + @Override + public void visitApply(JCMethodInvocation tree) { + Name name = TreeInfo.name(tree.meth); + + //fast path + if (tree.typeargs.nonEmpty() || + name == name.table.names._this || + name == name.table.names._super) { + result = ArgumentExpressionKind.NO_POLY; + return; + } + + //slow path + final JCExpression rec = tree.meth.hasTag(SELECT) ? + ((JCFieldAccess)tree.meth).selected : + null; + + if (rec != null && !isSimpleReceiver(rec)) { + //give up if receiver is too complex (to cut down analysis time) + result = ArgumentExpressionKind.POLY; + return; + } + + Type site = rec != null ? + attribSpeculative(rec, env, attr.unknownTypeExprInfo).type : + env.enclClass.sym.type; + + ListBuffer args = ListBuffer.lb(); + for (int i = 0; i < tree.args.length(); i ++) { + args.append(Type.noType); + } + + Resolve.LookupHelper lh = rs.new LookupHelper(name, site, args.toList(), List.nil(), MethodResolutionPhase.VARARITY) { + @Override + Symbol lookup(Env env, MethodResolutionPhase phase) { + return rec == null ? + rs.findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) : + rs.findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired(), false); + } + @Override + Symbol access(Env env, DiagnosticPosition pos, Symbol location, Symbol sym) { + return sym; + } + }; + + Symbol sym = rs.lookupMethod(env, tree, site.tsym, rs.arityMethodCheck, lh); + + if (sym.kind == Kinds.AMBIGUOUS) { + Resolve.AmbiguityError err = (Resolve.AmbiguityError)sym.baseSymbol(); + result = ArgumentExpressionKind.PRIMITIVE; + for (List ambigousSyms = err.ambiguousSyms ; + ambigousSyms.nonEmpty() && !result.isPoly() ; + ambigousSyms = ambigousSyms.tail) { + Symbol s = ambigousSyms.head; + if (s.kind == Kinds.MTH) { + result = reduce(ArgumentExpressionKind.methodKind(s, types)); + } + } + } else { + result = (sym.kind == Kinds.MTH) ? + ArgumentExpressionKind.methodKind(sym, types) : + ArgumentExpressionKind.NO_POLY; + } + } + //where + private boolean isSimpleReceiver(JCTree rec) { + switch (rec.getTag()) { + case IDENT: + return true; + case SELECT: + return isSimpleReceiver(((JCFieldAccess)rec).selected); + case TYPEAPPLY: + case TYPEARRAY: + return true; + case ANNOTATED_TYPE: + return isSimpleReceiver(((JCAnnotatedType)rec).underlyingType); + default: + return false; + } + } + private ArgumentExpressionKind reduce(ArgumentExpressionKind kind) { + switch (result) { + case PRIMITIVE: return kind; + case NO_POLY: return kind.isPoly() ? kind : result; + case POLY: return result; + default: + Assert.error(); + return null; + } + } + + @Override + public void visitLiteral(JCLiteral tree) { + Type litType = attr.litType(tree.typetag); + result = ArgumentExpressionKind.standaloneKind(litType, types); + } + + @Override + void skip(JCTree tree) { + result = ArgumentExpressionKind.NO_POLY; + } + } + //where + private EnumSet deferredCheckerTags = + EnumSet.of(LAMBDA, REFERENCE, PARENS, TYPECAST, + CONDEXPR, NEWCLASS, APPLY, LITERAL); }