diff -r fc843e3ea772 -r b419336382fd langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Fri Apr 05 14:51:55 2013 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Apr 08 15:51:41 2013 +0100 @@ -508,7 +508,6 @@ List typeargtypes, boolean allowBoxing, boolean useVarargs, - MethodCheck methodCheck, Warner warn) throws Infer.InferenceException { Type mt = types.memberType(site, m); @@ -561,10 +560,9 @@ allowBoxing, useVarargs, currentResolutionContext, - methodCheck, warn); - methodCheck.argumentsAcceptable(env, currentResolutionContext.deferredAttrContext(m, infer.emptyContext, resultInfo, warn), + currentResolutionContext.methodCheck.argumentsAcceptable(env, currentResolutionContext.deferredAttrContext(m, infer.emptyContext, resultInfo, warn), argtypes, mt.getParameterTypes(), warn); return mt; } @@ -582,7 +580,7 @@ currentResolutionContext.attrMode = DeferredAttr.AttrMode.CHECK; MethodResolutionPhase step = currentResolutionContext.step = env.info.pendingResolutionPhase; return rawInstantiate(env, site, m, resultInfo, argtypes, typeargtypes, - step.isBoxingRequired(), step.isVarargsRequired(), resolveMethodCheck, warn); + step.isBoxingRequired(), step.isVarargsRequired(), warn); } finally { currentResolutionContext = prevContext; @@ -599,11 +597,10 @@ List typeargtypes, boolean allowBoxing, boolean useVarargs, - MethodCheck methodCheck, Warner warn) { try { return rawInstantiate(env, site, m, resultInfo, argtypes, typeargtypes, - allowBoxing, useVarargs, methodCheck, warn); + allowBoxing, useVarargs, warn); } catch (InapplicableMethodException ex) { return null; } @@ -628,6 +625,12 @@ List argtypes, List formals, Warner warn); + + /** + * Retrieve the method check object that will be used during a + * most specific check. + */ + MethodCheck mostSpecificCheck(List actuals, boolean strict); } /** @@ -661,24 +664,25 @@ } /** - * Main method applicability routine. Given a list of actual types A, - * a list of formal types F, determines whether the types in A are - * compatible (by method invocation conversion) with the types in F. - * - * Since this routine is shared between overload resolution and method - * 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 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. + * Dummy method check object. All methods are deemed applicable, regardless + * of their formal parameter types. */ - MethodCheck resolveMethodCheck = new MethodCheck() { + MethodCheck nilMethodCheck = new MethodCheck() { + public void argumentsAcceptable(Env env, DeferredAttrContext deferredAttrContext, List argtypes, List formals, Warner warn) { + //do nothing - method always applicable regardless of actuals + } + + public MethodCheck mostSpecificCheck(List actuals, boolean strict) { + return this; + } + }; + + /** + * Base class for 'real' method checks. The class defines the logic for + * iterating through formals and actuals and provides and entry point + * that can be used by subclasses in order to define the actual check logic. + */ + abstract class AbstractMethodCheck implements MethodCheck { @Override public void argumentsAcceptable(final Env env, DeferredAttrContext deferredAttrContext, @@ -699,8 +703,7 @@ } while (argtypes.nonEmpty() && formals.head != varargsFormal) { - ResultInfo mresult = methodCheckResult(false, formals.head, deferredAttrContext, warn); - mresult.check(null, argtypes.head); + checkArg(false, argtypes.head, formals.head, deferredAttrContext, warn); argtypes = argtypes.tail; formals = formals.tail; } @@ -713,17 +716,19 @@ //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) final Type elt = types.elemtype(varargsFormal); - ResultInfo mresult = methodCheckResult(true, elt, deferredAttrContext, warn); while (argtypes.nonEmpty()) { - mresult.check(null, argtypes.head); + checkArg(true, argtypes.head, elt, deferredAttrContext, warn); argtypes = argtypes.tail; } - //check varargs element type accessibility - varargsAccessible(env, elt, inferenceContext); } } - private void reportMC(MethodCheckDiag diag, InferenceContext inferenceContext, Object... args) { + /** + * Does the actual argument conforms to the corresponding formal? + */ + abstract void checkArg(boolean varargs, Type actual, Type formal, DeferredAttrContext deferredAttrContext, Warner warn); + + protected void reportMC(MethodCheckDiag diag, InferenceContext inferenceContext, Object... args) { boolean inferDiag = inferenceContext != infer.emptyContext; InapplicableMethodException ex = inferDiag ? infer.inferenceException : inapplicableMethodException; @@ -736,6 +741,63 @@ throw ex.setMessage(inferDiag ? diag.inferKey : diag.basicKey, args); } + public MethodCheck mostSpecificCheck(List actuals, boolean strict) { + return nilMethodCheck; + } + } + + /** + * Arity-based method check. A method is applicable if the number of actuals + * supplied conforms to the method signature. + */ + MethodCheck arityMethodCheck = new AbstractMethodCheck() { + @Override + void checkArg(boolean varargs, Type actual, Type formal, DeferredAttrContext deferredAttrContext, Warner warn) { + //do nothing - actual always compatible to formals + } + }; + + /** + * Main method applicability routine. Given a list of actual types A, + * a list of formal types F, determines whether the types in A are + * compatible (by method invocation conversion) with the types in F. + * + * Since this routine is shared between overload resolution and method + * 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 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. + */ + MethodCheck resolveMethodCheck = new AbstractMethodCheck() { + + @Override + void checkArg(boolean varargs, Type actual, Type formal, DeferredAttrContext deferredAttrContext, Warner warn) { + ResultInfo mresult = methodCheckResult(varargs, formal, deferredAttrContext, warn); + mresult.check(null, actual); + } + + @Override + public void argumentsAcceptable(final Env env, + DeferredAttrContext deferredAttrContext, + List argtypes, + List formals, + Warner warn) { + super.argumentsAcceptable(env, deferredAttrContext, argtypes, formals, warn); + //should we expand formals? + if (deferredAttrContext.phase.isVarargsRequired()) { + //check varargs element type accessibility + varargsAccessible(env, types.elemtype(formals.last()), + deferredAttrContext.inferenceContext); + } + } + private void varargsAccessible(final Env env, final Type t, final InferenceContext inferenceContext) { if (inferenceContext.free(t)) { inferenceContext.addFreeTypeListener(List.of(t), new FreeTypeListener() { @@ -765,6 +827,11 @@ }; return new MethodResultInfo(to, checkContext); } + + @Override + public MethodCheck mostSpecificCheck(List actuals, boolean strict) { + return new MostSpecificCheck(strict, actuals); + } }; /** @@ -1042,6 +1109,11 @@ } } } + + public MethodCheck mostSpecificCheck(List actuals, boolean strict) { + Assert.error("Cannot get here!"); + return null; + } } public static class InapplicableMethodException extends RuntimeException { @@ -1254,7 +1326,7 @@ Assert.check(sym.kind < AMBIGUOUS); try { Type mt = rawInstantiate(env, site, sym, null, argtypes, typeargtypes, - allowBoxing, useVarargs, resolveMethodCheck, types.noWarnings); + allowBoxing, useVarargs, types.noWarnings); if (!operator) currentResolutionContext.addApplicableCandidate(sym, mt); } catch (InapplicableMethodException ex) { @@ -1358,11 +1430,20 @@ int maxLength = Math.max( Math.max(m1.type.getParameterTypes().length(), actuals.length()), m2.type.getParameterTypes().length()); - Type mst = instantiate(env, site, m2, null, - adjustArgs(types.lowerBounds(types.memberType(site, m1).getParameterTypes()), m1, maxLength, useVarargs), null, - allowBoxing, useVarargs, new MostSpecificCheck(!allowBoxing, actuals), noteWarner); - return mst != null && - !noteWarner.hasLint(Lint.LintCategory.UNCHECKED); + MethodResolutionContext prevResolutionContext = currentResolutionContext; + try { + currentResolutionContext = new MethodResolutionContext(); + currentResolutionContext.step = prevResolutionContext.step; + currentResolutionContext.methodCheck = + prevResolutionContext.methodCheck.mostSpecificCheck(actuals, !allowBoxing); + Type mst = instantiate(env, site, m2, null, + adjustArgs(types.lowerBounds(types.memberType(site, m1).getParameterTypes()), m1, maxLength, useVarargs), null, + allowBoxing, useVarargs, noteWarner); + return mst != null && + !noteWarner.hasLint(Lint.LintCategory.UNCHECKED); + } finally { + currentResolutionContext = prevResolutionContext; + } } private List adjustArgs(List args, Symbol msym, int length, boolean allowVarargs) { if ((msym.flags() & VARARGS) != 0 && allowVarargs) { @@ -2124,14 +2205,14 @@ Name name, List argtypes, List typeargtypes) { - return lookupMethod(env, pos, env.enclClass.sym, new BasicLookupHelper(name, env.enclClass.sym.type, argtypes, typeargtypes) { - @Override - Symbol lookup(Env env, MethodResolutionPhase phase) { - return findFun(env, name, argtypes, typeargtypes, - phase.isBoxingRequired(), - phase.isVarargsRequired()); - } - }); + return lookupMethod(env, pos, env.enclClass.sym, resolveMethodCheck, + new BasicLookupHelper(name, env.enclClass.sym.type, argtypes, typeargtypes) { + @Override + Symbol lookup(Env env, MethodResolutionPhase phase) { + return findFun(env, name, argtypes, typeargtypes, + phase.isBoxingRequired(), + phase.isVarargsRequired()); + }}); } /** Resolve a qualified method identifier @@ -2313,36 +2394,36 @@ Type site, List argtypes, List typeargtypes) { - return lookupMethod(env, pos, site.tsym, new BasicLookupHelper(names.init, site, argtypes, typeargtypes) { - @Override - Symbol lookup(Env env, MethodResolutionPhase phase) { - return findDiamond(env, site, argtypes, typeargtypes, - phase.isBoxingRequired(), - phase.isVarargsRequired()); - } - @Override - Symbol access(Env env, DiagnosticPosition pos, Symbol location, Symbol sym) { - if (sym.kind >= AMBIGUOUS) { - final JCDiagnostic details = sym.kind == WRONG_MTH ? - ((InapplicableSymbolError)sym).errCandidate().details : - null; - sym = new InapplicableSymbolError(sym.kind, "diamondError", currentResolutionContext) { - @Override - JCDiagnostic getDiagnostic(DiagnosticType dkind, DiagnosticPosition pos, - Symbol location, Type site, Name name, List argtypes, List typeargtypes) { - String key = details == null ? - "cant.apply.diamond" : - "cant.apply.diamond.1"; - return diags.create(dkind, log.currentSource(), pos, key, - diags.fragment("diamond", site.tsym), details); + return lookupMethod(env, pos, site.tsym, resolveMethodCheck, + new BasicLookupHelper(names.init, site, argtypes, typeargtypes) { + @Override + Symbol lookup(Env env, MethodResolutionPhase phase) { + return findDiamond(env, site, argtypes, typeargtypes, + phase.isBoxingRequired(), + phase.isVarargsRequired()); + } + @Override + Symbol access(Env env, DiagnosticPosition pos, Symbol location, Symbol sym) { + if (sym.kind >= AMBIGUOUS) { + final JCDiagnostic details = sym.kind == WRONG_MTH ? + ((InapplicableSymbolError)sym).errCandidate().details : + null; + sym = new InapplicableSymbolError(sym.kind, "diamondError", currentResolutionContext) { + @Override + JCDiagnostic getDiagnostic(DiagnosticType dkind, DiagnosticPosition pos, + Symbol location, Type site, Name name, List argtypes, List typeargtypes) { + String key = details == null ? + "cant.apply.diamond" : + "cant.apply.diamond.1"; + return diags.create(dkind, log.currentSource(), pos, key, + diags.fragment("diamond", site.tsym), details); + } + }; + sym = accessMethod(sym, pos, site, names.init, true, argtypes, typeargtypes); + env.info.pendingResolutionPhase = currentResolutionContext.step; } - }; - sym = accessMethod(sym, pos, site, names.init, true, argtypes, typeargtypes); - env.info.pendingResolutionPhase = currentResolutionContext.step; - } - return sym; - } - }); + return sym; + }}); } /** This method scans all the constructor symbol in a given class scope - @@ -2475,7 +2556,8 @@ Type site, Name name, List argtypes, List typeargtypes, - boolean boxingAllowed) { + boolean boxingAllowed, + MethodCheck methodCheck) { MethodResolutionPhase maxPhase = boxingAllowed ? VARARITY : BASIC; ReferenceLookupHelper boundLookupHelper; @@ -2495,12 +2577,12 @@ //step 1 - bound lookup Env boundEnv = env.dup(env.tree, env.info.dup()); - Symbol boundSym = lookupMethod(boundEnv, env.tree.pos(), site.tsym, boundLookupHelper); + Symbol boundSym = lookupMethod(boundEnv, env.tree.pos(), site.tsym, methodCheck, boundLookupHelper); //step 2 - unbound lookup ReferenceLookupHelper unboundLookupHelper = boundLookupHelper.unboundLookup(); Env unboundEnv = env.dup(env.tree, env.info.dup()); - Symbol unboundSym = lookupMethod(unboundEnv, env.tree.pos(), site.tsym, unboundLookupHelper); + Symbol unboundSym = lookupMethod(unboundEnv, env.tree.pos(), site.tsym, methodCheck, unboundLookupHelper); //merge results Pair res; @@ -2671,7 +2753,7 @@ ReferenceLookupHelper unboundLookup() { if (TreeInfo.isStaticSelector(referenceTree.expr, names) && argtypes.nonEmpty() && - types.isSubtypeUnchecked(argtypes.head, site)) { + (argtypes.head.hasTag(NONE) || types.isSubtypeUnchecked(argtypes.head, site))) { return new UnboundMethodReferenceLookupHelper(referenceTree, name, site, argtypes, typeargtypes, maxPhase); } else { @@ -2704,8 +2786,8 @@ UnboundMethodReferenceLookupHelper(JCMemberReference referenceTree, Name name, Type site, List argtypes, List typeargtypes, MethodResolutionPhase maxPhase) { super(referenceTree, name, site, argtypes.tail, typeargtypes, maxPhase); - Type asSuperSite = types.asSuper(argtypes.head, site.tsym); - if (site.isRaw() && !asSuperSite.isErroneous()) { + if (site.isRaw() && !argtypes.head.hasTag(NONE)) { + Type asSuperSite = types.asSuper(argtypes.head, site.tsym); this.site = asSuperSite; } } @@ -2800,8 +2882,10 @@ * at the end of the lookup, the helper is used to validate the results * (this last step might trigger overload resolution diagnostics). */ - Symbol lookupMethod(Env env, DiagnosticPosition pos, Symbol location, LookupHelper lookupHelper) { - return lookupMethod(env, pos, location, new MethodResolutionContext(), lookupHelper); + Symbol lookupMethod(Env env, DiagnosticPosition pos, Symbol location, MethodCheck methodCheck, LookupHelper lookupHelper) { + MethodResolutionContext resolveContext = new MethodResolutionContext(); + resolveContext.methodCheck = methodCheck; + return lookupMethod(env, pos, location, resolveContext, lookupHelper); } Symbol lookupMethod(Env env, DiagnosticPosition pos, Symbol location, @@ -3595,6 +3679,8 @@ MethodResolutionPhase step = null; + MethodCheck methodCheck = resolveMethodCheck; + private boolean internalResolution = false; private DeferredAttr.AttrMode attrMode = DeferredAttr.AttrMode.SPECULATIVE;