diff -r 3d3350aea968 -r 161230ec7c73 src/share/classes/com/sun/tools/javac/comp/Resolve.java --- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java Tue Feb 28 18:04:50 2012 -0800 +++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java Fri Mar 02 12:57:04 2012 +0000 @@ -29,6 +29,7 @@ import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.code.Symbol.*; +import com.sun.tools.javac.comp.Resolve.MethodResolutionContext.Candidate; import com.sun.tools.javac.jvm.*; import com.sun.tools.javac.tree.*; import com.sun.tools.javac.tree.JCTree.*; @@ -39,10 +40,9 @@ import java.util.Arrays; import java.util.Collection; +import java.util.EnumMap; import java.util.EnumSet; -import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; @@ -84,6 +84,58 @@ Scope polymorphicSignatureScope; + protected Resolve(Context context) { + context.put(resolveKey, this); + syms = Symtab.instance(context); + + varNotFound = new + SymbolNotFoundError(ABSENT_VAR); + wrongMethod = new + InapplicableSymbolError(); + wrongMethods = new + InapplicableSymbolsError(); + methodNotFound = new + SymbolNotFoundError(ABSENT_MTH); + typeNotFound = new + SymbolNotFoundError(ABSENT_TYP); + + names = Names.instance(context); + log = Log.instance(context); + chk = Check.instance(context); + infer = Infer.instance(context); + reader = ClassReader.instance(context); + treeinfo = TreeInfo.instance(context); + types = Types.instance(context); + diags = JCDiagnostic.Factory.instance(context); + Source source = Source.instance(context); + boxingEnabled = source.allowBoxing(); + varargsEnabled = source.allowVarargs(); + Options options = Options.instance(context); + debugResolve = options.isSet("debugresolve"); + verboseResolutionMode = VerboseResolutionMode.getVerboseResolutionMode(options); + Target target = Target.instance(context); + allowMethodHandles = target.hasMethodHandles(); + polymorphicSignatureScope = new Scope(syms.noSymbol); + + inapplicableMethodException = new InapplicableMethodException(diags); + } + + /** error symbols, which are returned when resolution fails + */ + private final SymbolNotFoundError varNotFound; + private final InapplicableSymbolError wrongMethod; + private final InapplicableSymbolsError wrongMethods; + private final SymbolNotFoundError methodNotFound; + private final SymbolNotFoundError typeNotFound; + + public static Resolve instance(Context context) { + Resolve instance = context.get(resolveKey); + if (instance == null) + instance = new Resolve(context); + return instance; + } + + // enum VerboseResolutionMode { SUCCESS("success"), FAILURE("failure"), @@ -119,56 +171,74 @@ } } - public static Resolve instance(Context context) { - Resolve instance = context.get(resolveKey); - if (instance == null) - instance = new Resolve(context); - return instance; + void reportVerboseResolutionDiagnostic(DiagnosticPosition dpos, Name name, Type site, + List argtypes, List typeargtypes, Symbol bestSoFar) { + boolean success = bestSoFar.kind < ERRONEOUS; + + if (success && !verboseResolutionMode.contains(VerboseResolutionMode.SUCCESS)) { + return; + } else if (!success && !verboseResolutionMode.contains(VerboseResolutionMode.FAILURE)) { + return; + } + + if (bestSoFar.name == names.init && + bestSoFar.owner == syms.objectType.tsym && + !verboseResolutionMode.contains(VerboseResolutionMode.OBJECT_INIT)) { + return; //skip diags for Object constructor resolution + } else if (site == syms.predefClass.type && + !verboseResolutionMode.contains(VerboseResolutionMode.PREDEF)) { + return; //skip spurious diags for predef symbols (i.e. operators) + } else if (currentResolutionContext.internalResolution && + !verboseResolutionMode.contains(VerboseResolutionMode.INTERNAL)) { + return; + } + + int pos = 0; + int mostSpecificPos = -1; + ListBuffer subDiags = ListBuffer.lb(); + for (Candidate c : currentResolutionContext.candidates) { + if (currentResolutionContext.step != c.step || + (c.isApplicable() && !verboseResolutionMode.contains(VerboseResolutionMode.APPLICABLE)) || + (!c.isApplicable() && !verboseResolutionMode.contains(VerboseResolutionMode.INAPPLICABLE))) { + continue; + } else { + subDiags.append(c.isApplicable() ? + getVerboseApplicableCandidateDiag(pos, c.sym, c.mtype) : + getVerboseInapplicableCandidateDiag(pos, c.sym, c.details)); + if (c.sym == bestSoFar) + mostSpecificPos = pos; + pos++; + } + } + String key = success ? "verbose.resolve.multi" : "verbose.resolve.multi.1"; + JCDiagnostic main = diags.note(log.currentSource(), dpos, key, name, + site.tsym, mostSpecificPos, currentResolutionContext.step, + methodArguments(argtypes), methodArguments(typeargtypes)); + JCDiagnostic d = new JCDiagnostic.MultilineDiagnostic(main, subDiags.toList()); + log.report(d); } - protected Resolve(Context context) { - context.put(resolveKey, this); - syms = Symtab.instance(context); + JCDiagnostic getVerboseApplicableCandidateDiag(int pos, Symbol sym, Type inst) { + JCDiagnostic subDiag = null; + if (inst.getReturnType().tag == FORALL) { + Type diagType = types.createMethodTypeWithReturn(inst.asMethodType(), + ((ForAll)inst.getReturnType()).qtype); + subDiag = diags.fragment("partial.inst.sig", diagType); + } else if (sym.type.tag == FORALL) { + subDiag = diags.fragment("full.inst.sig", inst.asMethodType()); + } - varNotFound = new - SymbolNotFoundError(ABSENT_VAR); - wrongMethod = new - InapplicableSymbolError(syms.errSymbol); - wrongMethods = new - InapplicableSymbolsError(syms.errSymbol); - methodNotFound = new - SymbolNotFoundError(ABSENT_MTH); - typeNotFound = new - SymbolNotFoundError(ABSENT_TYP); + String key = subDiag == null ? + "applicable.method.found" : + "applicable.method.found.1"; - names = Names.instance(context); - log = Log.instance(context); - chk = Check.instance(context); - infer = Infer.instance(context); - reader = ClassReader.instance(context); - treeinfo = TreeInfo.instance(context); - types = Types.instance(context); - diags = JCDiagnostic.Factory.instance(context); - Source source = Source.instance(context); - boxingEnabled = source.allowBoxing(); - varargsEnabled = source.allowVarargs(); - Options options = Options.instance(context); - debugResolve = options.isSet("debugresolve"); - verboseResolutionMode = VerboseResolutionMode.getVerboseResolutionMode(options); - Target target = Target.instance(context); - allowMethodHandles = target.hasMethodHandles(); - polymorphicSignatureScope = new Scope(syms.noSymbol); - - inapplicableMethodException = new InapplicableMethodException(diags); + return diags.fragment(key, pos, sym, subDiag); } - /** error symbols, which are returned when resolution fails - */ - final SymbolNotFoundError varNotFound; - final InapplicableSymbolError wrongMethod; - final InapplicableSymbolsError wrongMethods; - final SymbolNotFoundError methodNotFound; - final SymbolNotFoundError typeNotFound; + JCDiagnostic getVerboseInapplicableCandidateDiag(int pos, Symbol sym, JCDiagnostic subDiag) { + return diags.fragment("not.applicable.method.found", pos, sym, subDiag); + } + // /* ************************************************************************ * Identifier resolution @@ -804,17 +874,18 @@ try { Type mt = rawInstantiate(env, site, sym, argtypes, typeargtypes, allowBoxing, useVarargs, Warner.noWarnings); - if (!operator) addVerboseApplicableCandidateDiag(sym ,mt); + if (!operator) + currentResolutionContext.addApplicableCandidate(sym, mt); } catch (InapplicableMethodException ex) { - if (!operator) addVerboseInapplicableCandidateDiag(sym, ex.getDiagnostic()); + if (!operator) + currentResolutionContext.addInapplicableCandidate(sym, ex.getDiagnostic()); switch (bestSoFar.kind) { case ABSENT_MTH: - return wrongMethod.setWrongSym(sym, ex.getDiagnostic()); + return wrongMethod; case WRONG_MTH: if (operator) return bestSoFar; - wrongMethods.addCandidate(currentStep, wrongMethod.sym, wrongMethod.explanation); case WRONG_MTHS: - return wrongMethods.addCandidate(currentStep, sym, ex.getDiagnostic()); + return wrongMethods; default: return bestSoFar; } @@ -823,40 +894,12 @@ return (bestSoFar.kind == ABSENT_MTH) ? new AccessError(env, site, sym) : bestSoFar; - } + } return (bestSoFar.kind > AMBIGUOUS) ? sym : mostSpecific(sym, bestSoFar, env, site, allowBoxing && operator, useVarargs); } - //where - void addVerboseApplicableCandidateDiag(Symbol sym, Type inst) { - if (!verboseResolutionMode.contains(VerboseResolutionMode.APPLICABLE)) - return; - - JCDiagnostic subDiag = null; - if (inst.getReturnType().tag == FORALL) { - Type diagType = types.createMethodTypeWithReturn(inst.asMethodType(), - ((ForAll)inst.getReturnType()).qtype); - subDiag = diags.fragment("partial.inst.sig", diagType); - } else if (sym.type.tag == FORALL) { - subDiag = diags.fragment("full.inst.sig", inst.asMethodType()); - } - - String key = subDiag == null ? - "applicable.method.found" : - "applicable.method.found.1"; - - verboseResolutionCandidateDiags.put(sym, - diags.fragment(key, verboseResolutionCandidateDiags.size(), sym, subDiag)); - } - - void addVerboseInapplicableCandidateDiag(Symbol sym, JCDiagnostic subDiag) { - if (!verboseResolutionMode.contains(VerboseResolutionMode.INAPPLICABLE)) - return; - verboseResolutionCandidateDiags.put(sym, - diags.fragment("not.applicable.method.found", verboseResolutionCandidateDiags.size(), sym, subDiag)); - } /* Return the most specific of the two methods for a call, * given that both are accessible and applicable. @@ -1054,7 +1097,6 @@ boolean allowBoxing, boolean useVarargs, boolean operator) { - verboseResolutionCandidateDiags.clear(); Symbol bestSoFar = methodNotFound; bestSoFar = findMethod(env, site, @@ -1127,37 +1169,6 @@ } return bestSoFar; } - //where - void reportVerboseResolutionDiagnostic(DiagnosticPosition dpos, Name name, Type site, List argtypes, List typeargtypes, Symbol bestSoFar) { - boolean success = bestSoFar.kind < ERRONEOUS; - - if (success && !verboseResolutionMode.contains(VerboseResolutionMode.SUCCESS)) { - return; - } else if (!success && !verboseResolutionMode.contains(VerboseResolutionMode.FAILURE)) { - return; - } - - if (bestSoFar.name == names.init && - bestSoFar.owner == syms.objectType.tsym && - !verboseResolutionMode.contains(VerboseResolutionMode.OBJECT_INIT)) { - return; //skip diags for Object constructor resolution - } else if (site == syms.predefClass.type && !verboseResolutionMode.contains(VerboseResolutionMode.PREDEF)) { - return; //skip spurious diags for predef symbols (i.e. operators) - } else if (internalResolution && !verboseResolutionMode.contains(VerboseResolutionMode.INTERNAL)) { - return; - } - - int pos = 0; - for (Symbol s : verboseResolutionCandidateDiags.keySet()) { - if (s == bestSoFar) break; - pos++; - } - String key = success ? "verbose.resolve.multi" : "verbose.resolve.multi.1"; - JCDiagnostic main = diags.note(log.currentSource(), dpos, key, name, site.tsym, pos, currentStep, - methodArguments(argtypes), methodArguments(typeargtypes)); - JCDiagnostic d = new JCDiagnostic.MultilineDiagnostic(main, List.from(verboseResolutionCandidateDiags.values().toArray(new JCDiagnostic[verboseResolutionCandidateDiags.size()]))); - log.report(d); - } /** Find unqualified method matching given name, type and value arguments. * @param env The current environment. @@ -1591,32 +1602,33 @@ Name name, List argtypes, List typeargtypes) { - Symbol sym = startResolution(); - List steps = methodResolutionSteps; - while (steps.nonEmpty() && - steps.head.isApplicable(boxingEnabled, varargsEnabled) && - sym.kind >= ERRONEOUS) { - currentStep = steps.head; - sym = findFun(env, name, argtypes, typeargtypes, - steps.head.isBoxingRequired, - env.info.varArgs = steps.head.isVarargsRequired); - methodResolutionCache.put(steps.head, sym); - steps = steps.tail; + MethodResolutionContext prevResolutionContext = currentResolutionContext; + try { + currentResolutionContext = new MethodResolutionContext(); + Symbol sym = methodNotFound; + List steps = methodResolutionSteps; + while (steps.nonEmpty() && + steps.head.isApplicable(boxingEnabled, varargsEnabled) && + sym.kind >= ERRONEOUS) { + currentResolutionContext.step = steps.head; + sym = findFun(env, name, argtypes, typeargtypes, + steps.head.isBoxingRequired, + env.info.varArgs = 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), + pos, env.enclClass.sym.type, name, false, argtypes, typeargtypes); + env.info.varArgs = errPhase.isVarargsRequired; + } + return sym; } - if (sym.kind >= AMBIGUOUS) {//if nothing is found return the 'first' error - MethodResolutionPhase errPhase = - firstErroneousResolutionPhase(); - sym = access(methodResolutionCache.get(errPhase), - pos, env.enclClass.sym.type, name, false, argtypes, typeargtypes); - env.info.varArgs = errPhase.isVarargsRequired; + finally { + currentResolutionContext = prevResolutionContext; } - return sym; - } - - private Symbol startResolution() { - wrongMethod.clear(); - wrongMethods.clear(); - return methodNotFound; } /** Resolve a qualified method identifier @@ -1636,40 +1648,53 @@ Symbol resolveQualifiedMethod(DiagnosticPosition pos, Env env, Symbol location, Type site, Name name, List argtypes, List typeargtypes) { - Symbol sym = startResolution(); - List steps = methodResolutionSteps; - while (steps.nonEmpty() && - steps.head.isApplicable(boxingEnabled, varargsEnabled) && - sym.kind >= ERRONEOUS) { - currentStep = steps.head; - sym = findMethod(env, site, name, argtypes, typeargtypes, - steps.head.isBoxingRequired(), - env.info.varArgs = steps.head.isVarargsRequired(), false); - methodResolutionCache.put(steps.head, sym); - steps = steps.tail; - } - if (sym.kind >= AMBIGUOUS) { - if (site.tsym.isPolymorphicSignatureGeneric()) { - //polymorphic receiver - synthesize new method symbol + return resolveQualifiedMethod(new MethodResolutionContext(), pos, env, location, site, name, argtypes, typeargtypes); + } + private Symbol resolveQualifiedMethod(MethodResolutionContext resolveContext, + DiagnosticPosition pos, Env env, + Symbol location, Type site, Name name, List argtypes, + List typeargtypes) { + MethodResolutionContext prevResolutionContext = currentResolutionContext; + try { + currentResolutionContext = resolveContext; + Symbol sym = methodNotFound; + List steps = methodResolutionSteps; + while (steps.nonEmpty() && + steps.head.isApplicable(boxingEnabled, varargsEnabled) && + sym.kind >= ERRONEOUS) { + currentResolutionContext.step = steps.head; + sym = findMethod(env, site, name, argtypes, typeargtypes, + steps.head.isBoxingRequired(), + env.info.varArgs = steps.head.isVarargsRequired(), false); + currentResolutionContext.resolutionCache.put(steps.head, sym); + steps = steps.tail; + } + if (sym.kind >= AMBIGUOUS) { + if (site.tsym.isPolymorphicSignatureGeneric()) { + //polymorphic receiver - synthesize new method symbol + env.info.varArgs = false; + sym = findPolymorphicSignatureInstance(env, + site, name, null, argtypes); + } + else { + //if nothing is found return the 'first' error + MethodResolutionPhase errPhase = + currentResolutionContext.firstErroneousResolutionPhase(); + sym = access(currentResolutionContext.resolutionCache.get(errPhase), + pos, location, site, name, true, argtypes, typeargtypes); + env.info.varArgs = errPhase.isVarargsRequired; + } + } else if (allowMethodHandles && sym.isPolymorphicSignatureGeneric()) { + //non-instantiated polymorphic signature - synthesize new method symbol env.info.varArgs = false; sym = findPolymorphicSignatureInstance(env, - site, name, null, argtypes); + site, name, (MethodSymbol)sym, argtypes); } - else { - //if nothing is found return the 'first' error - MethodResolutionPhase errPhase = - firstErroneousResolutionPhase(); - sym = access(methodResolutionCache.get(errPhase), - pos, location, site, name, true, argtypes, typeargtypes); - env.info.varArgs = errPhase.isVarargsRequired; - } - } else if (allowMethodHandles && sym.isPolymorphicSignatureGeneric()) { - //non-instantiated polymorphic signature - synthesize new method symbol - env.info.varArgs = false; - sym = findPolymorphicSignatureInstance(env, - site, name, (MethodSymbol)sym, argtypes); + return sym; } - return sym; + finally { + currentResolutionContext = prevResolutionContext; + } } /** Find or create an implicit method of exactly the given type (after erasure). @@ -1726,19 +1751,14 @@ Type site, Name name, List argtypes, List typeargtypes) { - boolean prevInternal = internalResolution; - try { - internalResolution = true; - Symbol sym = resolveQualifiedMethod( - pos, env, site.tsym, site, name, argtypes, typeargtypes); - if (sym.kind == MTH) return (MethodSymbol)sym; - else throw new FatalError( - diags.fragment("fatal.err.cant.locate.meth", - name)); - } - finally { - internalResolution = prevInternal; - } + MethodResolutionContext resolveContext = new MethodResolutionContext(); + resolveContext.internalResolution = true; + Symbol sym = resolveQualifiedMethod(resolveContext, pos, env, site.tsym, + site, name, argtypes, typeargtypes); + if (sym.kind == MTH) return (MethodSymbol)sym; + else throw new FatalError( + diags.fragment("fatal.err.cant.locate.meth", + name)); } /** Resolve constructor. @@ -1755,25 +1775,40 @@ Type site, List argtypes, List typeargtypes) { - Symbol sym = startResolution(); - List steps = methodResolutionSteps; - while (steps.nonEmpty() && - steps.head.isApplicable(boxingEnabled, varargsEnabled) && - sym.kind >= ERRONEOUS) { - currentStep = steps.head; - sym = resolveConstructor(pos, env, site, argtypes, typeargtypes, - steps.head.isBoxingRequired(), - env.info.varArgs = steps.head.isVarargsRequired()); - methodResolutionCache.put(steps.head, sym); - steps = steps.tail; + return resolveConstructor(new MethodResolutionContext(), pos, env, site, argtypes, typeargtypes); + } + private Symbol resolveConstructor(MethodResolutionContext resolveContext, + DiagnosticPosition pos, + Env env, + Type site, + List argtypes, + List typeargtypes) { + MethodResolutionContext prevResolutionContext = currentResolutionContext; + try { + currentResolutionContext = resolveContext; + Symbol sym = methodNotFound; + List steps = methodResolutionSteps; + while (steps.nonEmpty() && + steps.head.isApplicable(boxingEnabled, varargsEnabled) && + sym.kind >= ERRONEOUS) { + currentResolutionContext.step = steps.head; + sym = findConstructor(pos, env, site, argtypes, typeargtypes, + steps.head.isBoxingRequired(), + env.info.varArgs = 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), + pos, site, names.init, true, argtypes, typeargtypes); + env.info.varArgs = errPhase.isVarargsRequired(); + } + return sym; } - if (sym.kind >= AMBIGUOUS) {//if nothing is found return the 'first' error - MethodResolutionPhase errPhase = firstErroneousResolutionPhase(); - sym = access(methodResolutionCache.get(errPhase), - pos, site, names.init, true, argtypes, typeargtypes); - env.info.varArgs = errPhase.isVarargsRequired(); + finally { + currentResolutionContext = prevResolutionContext; } - return sym; } /** Resolve constructor using diamond inference. @@ -1791,38 +1826,45 @@ Type site, List argtypes, List typeargtypes) { - Symbol sym = startResolution(); - List steps = methodResolutionSteps; - while (steps.nonEmpty() && - steps.head.isApplicable(boxingEnabled, varargsEnabled) && - sym.kind >= ERRONEOUS) { - currentStep = steps.head; - sym = resolveConstructor(pos, env, site, argtypes, typeargtypes, - steps.head.isBoxingRequired(), - env.info.varArgs = steps.head.isVarargsRequired()); - methodResolutionCache.put(steps.head, sym); - steps = steps.tail; + MethodResolutionContext prevResolutionContext = currentResolutionContext; + try { + currentResolutionContext = new MethodResolutionContext(); + Symbol sym = methodNotFound; + List steps = methodResolutionSteps; + while (steps.nonEmpty() && + steps.head.isApplicable(boxingEnabled, varargsEnabled) && + sym.kind >= ERRONEOUS) { + currentResolutionContext.step = steps.head; + sym = findConstructor(pos, env, site, argtypes, typeargtypes, + steps.head.isBoxingRequired(), + env.info.varArgs = steps.head.isVarargsRequired()); + currentResolutionContext.resolutionCache.put(steps.head, sym); + steps = steps.tail; + } + if (sym.kind >= AMBIGUOUS) { + final JCDiagnostic details = sym.kind == WRONG_MTH ? + currentResolutionContext.candidates.head.details : + null; + Symbol errSym = new ResolveError(WRONG_MTH, "diamond error") { + @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); + } + }; + MethodResolutionPhase errPhase = currentResolutionContext.firstErroneousResolutionPhase(); + sym = access(errSym, pos, site, names.init, true, argtypes, typeargtypes); + env.info.varArgs = errPhase.isVarargsRequired(); + } + return sym; } - if (sym.kind >= AMBIGUOUS) { - final JCDiagnostic details = sym.kind == WRONG_MTH ? - ((InapplicableSymbolError)sym).explanation : - null; - Symbol errSym = new ResolveError(WRONG_MTH, "diamond error") { - @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); - } - }; - MethodResolutionPhase errPhase = firstErroneousResolutionPhase(); - sym = access(errSym, pos, site, names.init, true, argtypes, typeargtypes); - env.info.varArgs = errPhase.isVarargsRequired(); + finally { + currentResolutionContext = prevResolutionContext; } - return sym; } /** Resolve constructor. @@ -1841,10 +1883,25 @@ List typeargtypes, boolean allowBoxing, boolean useVarargs) { + MethodResolutionContext prevResolutionContext = currentResolutionContext; + try { + currentResolutionContext = new MethodResolutionContext(); + return findConstructor(pos, env, site, argtypes, typeargtypes, allowBoxing, useVarargs); + } + finally { + currentResolutionContext = prevResolutionContext; + } + } + + Symbol findConstructor(DiagnosticPosition pos, Env env, + Type site, List argtypes, + List typeargtypes, + boolean allowBoxing, + boolean useVarargs) { Symbol sym = findMethod(env, site, - names.init, argtypes, - typeargtypes, allowBoxing, - useVarargs, false); + names.init, argtypes, + typeargtypes, allowBoxing, + useVarargs, false); chk.checkDeprecated(pos, env.info.scope.owner, sym); return sym; } @@ -1860,8 +1917,9 @@ Type site, List argtypes, List typeargtypes) { - Symbol sym = resolveConstructor( - pos, env, site, argtypes, typeargtypes); + MethodResolutionContext resolveContext = new MethodResolutionContext(); + resolveContext.internalResolution = true; + Symbol sym = resolveConstructor(resolveContext, pos, env, site, argtypes, typeargtypes); if (sym.kind == MTH) return (MethodSymbol)sym; else throw new FatalError( diags.fragment("fatal.err.cant.locate.ctor", site)); @@ -1875,15 +1933,21 @@ */ Symbol resolveOperator(DiagnosticPosition pos, JCTree.Tag optag, Env env, List argtypes) { - startResolution(); - Name name = treeinfo.operatorName(optag); - Symbol sym = findMethod(env, syms.predefClass.type, name, argtypes, - null, false, false, true); - 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, - false, argtypes, null); + MethodResolutionContext prevResolutionContext = currentResolutionContext; + try { + currentResolutionContext = new MethodResolutionContext(); + Name name = treeinfo.operatorName(optag); + Symbol sym = findMethod(env, syms.predefClass.type, name, argtypes, + null, false, false, true); + 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, + false, argtypes, null); + } + finally { + currentResolutionContext = prevResolutionContext; + } } /** Resolve operator. @@ -2227,34 +2291,24 @@ * (either a method, a constructor or an operand) is not applicable * given an actual arguments/type argument list. */ - class InapplicableSymbolError extends InvalidSymbolError { + class InapplicableSymbolError extends ResolveError { - /** An auxiliary explanation set in case of instantiation errors. */ - JCDiagnostic explanation; - - InapplicableSymbolError(Symbol sym) { - super(WRONG_MTH, sym, "inapplicable symbol error"); + InapplicableSymbolError() { + super(WRONG_MTH, "inapplicable symbol error"); } - /** Update sym and explanation and return this. - */ - InapplicableSymbolError setWrongSym(Symbol sym, JCDiagnostic explanation) { - this.sym = sym; - if (this.sym == sym && explanation != null) - this.explanation = explanation; //update the details - return this; - } - - /** Update sym and return this. - */ - InapplicableSymbolError setWrongSym(Symbol sym) { - this.sym = sym; - return this; + protected InapplicableSymbolError(int kind, String debugName) { + super(kind, debugName); } @Override public String toString() { - return super.toString() + " explanation=" + explanation; + return super.toString(); + } + + @Override + public boolean exists() { + return true; } @Override @@ -2279,27 +2333,40 @@ key, name, first, second); } else { - Symbol ws = sym.asMemberOf(site, types); + Candidate c = errCandidate(); + Symbol ws = c.sym.asMemberOf(site, types); return diags.create(dkind, log.currentSource(), pos, - "cant.apply.symbol" + (explanation != null ? ".1" : ""), + "cant.apply.symbol" + (c.details != null ? ".1" : ""), kindName(ws), ws.name == names.init ? ws.owner.name : ws.name, methodArguments(ws.type.getParameterTypes()), methodArguments(argtypes), kindName(ws.owner), ws.owner.type, - explanation); + c.details); } } - void clear() { - explanation = null; - } - @Override public Symbol access(Name name, TypeSymbol location) { return types.createErrorType(name, location, syms.errSymbol.type).tsym; } + + protected boolean shouldReport(Candidate c) { + return !c.isApplicable() && + (((c.sym.flags() & VARARGS) != 0 && c.step == VARARITY) || + (c.sym.flags() & VARARGS) == 0 && c.step == (boxingEnabled ? BOX : BASIC)); + } + + private Candidate errCandidate() { + for (Candidate c : currentResolutionContext.candidates) { + if (shouldReport(c)) { + return c; + } + } + Assert.error(); + return null; + } } /** @@ -2307,11 +2374,9 @@ * (either methods, constructors or operands) is not applicable * given an actual arguments/type argument list. */ - class InapplicableSymbolsError extends ResolveError { + class InapplicableSymbolsError extends InapplicableSymbolError { - private List candidates = List.nil(); - - InapplicableSymbolsError(Symbol sym) { + InapplicableSymbolsError() { super(WRONG_MTHS, "inapplicable symbols"); } @@ -2323,7 +2388,7 @@ Name name, List argtypes, List typeargtypes) { - if (candidates.nonEmpty()) { + if (currentResolutionContext.candidates.nonEmpty()) { JCDiagnostic err = diags.create(dkind, log.currentSource(), pos, @@ -2341,68 +2406,24 @@ //where List candidateDetails(Type site) { List details = List.nil(); - for (Candidate c : candidates) - details = details.prepend(c.getDiagnostic(site)); + for (Candidate c : currentResolutionContext.candidates) { + if (!shouldReport(c)) continue; + JCDiagnostic detailDiag = diags.fragment("inapplicable.method", + Kinds.kindName(c.sym), + c.sym.location(site, types), + c.sym.asMemberOf(site, types), + c.details); + details = details.prepend(detailDiag); + } return details.reverse(); } - Symbol addCandidate(MethodResolutionPhase currentStep, Symbol sym, JCDiagnostic details) { - Candidate c = new Candidate(currentStep, sym, details); - if (c.isValid() && !candidates.contains(c)) - candidates = candidates.append(c); - return this; - } - - void clear() { - candidates = List.nil(); - } - private Name getName() { - Symbol sym = candidates.head.sym; + Symbol sym = currentResolutionContext.candidates.head.sym; return sym.name == names.init ? sym.owner.name : sym.name; } - - private class Candidate { - - final MethodResolutionPhase step; - final Symbol sym; - final JCDiagnostic details; - - private Candidate(MethodResolutionPhase step, Symbol sym, JCDiagnostic details) { - this.step = step; - this.sym = sym; - this.details = details; - } - - JCDiagnostic getDiagnostic(Type site) { - return diags.fragment("inapplicable.method", - Kinds.kindName(sym), - sym.location(site, types), - sym.asMemberOf(site, types), - details); - } - - @Override - public boolean equals(Object o) { - if (o instanceof Candidate) { - Symbol s1 = this.sym; - Symbol s2 = ((Candidate)o).sym; - if ((s1 != s2 && - (s1.overrides(s2, s1.owner.type.tsym, types, false) || - (s2.overrides(s1, s2.owner.type.tsym, types, false)))) || - ((s1.isConstructor() || s2.isConstructor()) && s1.owner != s2.owner)) - return true; - } - return false; - } - - boolean isValid() { - return (((sym.flags() & VARARGS) != 0 && step == VARARITY) || - (sym.flags() & VARARGS) == 0 && step == (boxingEnabled ? BOX : BASIC)); - } - } } /** @@ -2563,29 +2584,91 @@ } } - private Map methodResolutionCache = - new HashMap(MethodResolutionPhase.values().length); - - private Map verboseResolutionCandidateDiags = - new LinkedHashMap(); - final List methodResolutionSteps = List.of(BASIC, BOX, VARARITY); - private MethodResolutionPhase currentStep = null; + /** + * A resolution context is used to keep track of intermediate results of + * overload resolution, such as list of method that are not applicable + * (used to generate more precise diagnostics) and so on. Resolution contexts + * can be nested - this means that when each overload resolution routine should + * work within the resolution context it created. + */ + class MethodResolutionContext { - private boolean internalResolution = false; + private List candidates = List.nil(); - private MethodResolutionPhase firstErroneousResolutionPhase() { - MethodResolutionPhase bestSoFar = BASIC; - Symbol sym = methodNotFound; - List steps = methodResolutionSteps; - while (steps.nonEmpty() && - steps.head.isApplicable(boxingEnabled, varargsEnabled) && - sym.kind >= WRONG_MTHS) { - sym = methodResolutionCache.get(steps.head); - bestSoFar = steps.head; - steps = steps.tail; + private Map resolutionCache = + new EnumMap(MethodResolutionPhase.class); + + private MethodResolutionPhase step = null; + + private boolean internalResolution = false; + + private MethodResolutionPhase firstErroneousResolutionPhase() { + MethodResolutionPhase bestSoFar = BASIC; + Symbol sym = methodNotFound; + List steps = methodResolutionSteps; + while (steps.nonEmpty() && + steps.head.isApplicable(boxingEnabled, varargsEnabled) && + sym.kind >= WRONG_MTHS) { + sym = resolutionCache.get(steps.head); + bestSoFar = steps.head; + steps = steps.tail; + } + return bestSoFar; } - return bestSoFar; + + void addInapplicableCandidate(Symbol sym, JCDiagnostic details) { + Candidate c = new Candidate(currentResolutionContext.step, sym, details, null); + if (!candidates.contains(c)) + candidates = candidates.append(c); + } + + void addApplicableCandidate(Symbol sym, Type mtype) { + Candidate c = new Candidate(currentResolutionContext.step, sym, null, mtype); + candidates = candidates.append(c); + } + + /** + * This class represents an overload resolution candidate. There are two + * kinds of candidates: applicable methods and inapplicable methods; + * applicable methods have a pointer to the instantiated method type, + * while inapplicable candidates contain further details about the + * reason why the method has been considered inapplicable. + */ + class Candidate { + + final MethodResolutionPhase step; + final Symbol sym; + final JCDiagnostic details; + final Type mtype; + + private Candidate(MethodResolutionPhase step, Symbol sym, JCDiagnostic details, Type mtype) { + this.step = step; + this.sym = sym; + this.details = details; + this.mtype = mtype; + } + + @Override + public boolean equals(Object o) { + if (o instanceof Candidate) { + Symbol s1 = this.sym; + Symbol s2 = ((Candidate)o).sym; + if ((s1 != s2 && + (s1.overrides(s2, s1.owner.type.tsym, types, false) || + (s2.overrides(s1, s2.owner.type.tsym, types, false)))) || + ((s1.isConstructor() || s2.isConstructor()) && s1.owner != s2.owner)) + return true; + } + return false; + } + + boolean isApplicable() { + return mtype != null; + } + } } + + MethodResolutionContext currentResolutionContext = null; }