7132880: Resolve should support nested resolution contexts

Overload resolution routine should be updated so that it can be called recursively

Reviewed-by: jjg, dlsmith
This commit is contained in:
Maurizio Cimadamore 2012-03-02 12:57:04 +00:00
parent 45a7449ceb
commit f01bc46dfe
3 changed files with 493 additions and 346 deletions

View File

@ -29,6 +29,7 @@ import com.sun.tools.javac.api.Formattable.LocalizedString;
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 com.sun.tools.javac.util.JCDiagnostic.DiagnosticType;
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 @@ public class Resolve {
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;
}
// <editor-fold defaultstate="collapsed" desc="Verbose resolution diagnostics support">
enum VerboseResolutionMode {
SUCCESS("success"),
FAILURE("failure"),
@ -119,56 +171,74 @@ public class Resolve {
}
}
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<Type> argtypes, List<Type> 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<JCDiagnostic> 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);
}
// </editor-fold>
/* ************************************************************************
* Identifier resolution
@ -804,17 +874,18 @@ public class Resolve {
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 @@ public class Resolve {
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 @@ public class Resolve {
boolean allowBoxing,
boolean useVarargs,
boolean operator) {
verboseResolutionCandidateDiags.clear();
Symbol bestSoFar = methodNotFound;
bestSoFar = findMethod(env,
site,
@ -1127,37 +1169,6 @@ public class Resolve {
}
return bestSoFar;
}
//where
void reportVerboseResolutionDiagnostic(DiagnosticPosition dpos, Name name, Type site, List<Type> argtypes, List<Type> 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 @@ public class Resolve {
Name name,
List<Type> argtypes,
List<Type> typeargtypes) {
Symbol sym = startResolution();
List<MethodResolutionPhase> 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<MethodResolutionPhase> 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 @@ public class Resolve {
Symbol resolveQualifiedMethod(DiagnosticPosition pos, Env<AttrContext> env,
Symbol location, Type site, Name name, List<Type> argtypes,
List<Type> typeargtypes) {
Symbol sym = startResolution();
List<MethodResolutionPhase> 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<AttrContext> env,
Symbol location, Type site, Name name, List<Type> argtypes,
List<Type> typeargtypes) {
MethodResolutionContext prevResolutionContext = currentResolutionContext;
try {
currentResolutionContext = resolveContext;
Symbol sym = methodNotFound;
List<MethodResolutionPhase> 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;
}
finally {
currentResolutionContext = prevResolutionContext;
}
return sym;
}
/** Find or create an implicit method of exactly the given type (after erasure).
@ -1726,19 +1751,14 @@ public class Resolve {
Type site, Name name,
List<Type> argtypes,
List<Type> 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 @@ public class Resolve {
Type site,
List<Type> argtypes,
List<Type> typeargtypes) {
Symbol sym = startResolution();
List<MethodResolutionPhase> 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<AttrContext> env,
Type site,
List<Type> argtypes,
List<Type> typeargtypes) {
MethodResolutionContext prevResolutionContext = currentResolutionContext;
try {
currentResolutionContext = resolveContext;
Symbol sym = methodNotFound;
List<MethodResolutionPhase> 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 @@ public class Resolve {
Type site,
List<Type> argtypes,
List<Type> typeargtypes) {
Symbol sym = startResolution();
List<MethodResolutionPhase> 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<MethodResolutionPhase> 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<Type> argtypes, List<Type> 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<Type> argtypes, List<Type> 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 @@ public class Resolve {
List<Type> 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<AttrContext> env,
Type site, List<Type> argtypes,
List<Type> 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 @@ public class Resolve {
Type site,
List<Type> argtypes,
List<Type> 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 @@ public class Resolve {
*/
Symbol resolveOperator(DiagnosticPosition pos, JCTree.Tag optag,
Env<AttrContext> env, List<Type> 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 @@ public class Resolve {
* (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 @@ public class Resolve {
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 @@ public class Resolve {
* (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<Candidate> candidates = List.nil();
InapplicableSymbolsError(Symbol sym) {
InapplicableSymbolsError() {
super(WRONG_MTHS, "inapplicable symbols");
}
@ -2323,7 +2388,7 @@ public class Resolve {
Name name,
List<Type> argtypes,
List<Type> typeargtypes) {
if (candidates.nonEmpty()) {
if (currentResolutionContext.candidates.nonEmpty()) {
JCDiagnostic err = diags.create(dkind,
log.currentSource(),
pos,
@ -2341,68 +2406,24 @@ public class Resolve {
//where
List<JCDiagnostic> candidateDetails(Type site) {
List<JCDiagnostic> 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 @@ public class Resolve {
}
}
private Map<MethodResolutionPhase, Symbol> methodResolutionCache =
new HashMap<MethodResolutionPhase, Symbol>(MethodResolutionPhase.values().length);
private Map<Symbol, JCDiagnostic> verboseResolutionCandidateDiags =
new LinkedHashMap<Symbol, JCDiagnostic>();
final List<MethodResolutionPhase> 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<Candidate> candidates = List.nil();
private MethodResolutionPhase firstErroneousResolutionPhase() {
MethodResolutionPhase bestSoFar = BASIC;
Symbol sym = methodNotFound;
List<MethodResolutionPhase> 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<MethodResolutionPhase, Symbol> resolutionCache =
new EnumMap<MethodResolutionPhase, Symbol>(MethodResolutionPhase.class);
private MethodResolutionPhase step = null;
private boolean internalResolution = false;
private MethodResolutionPhase firstErroneousResolutionPhase() {
MethodResolutionPhase bestSoFar = BASIC;
Symbol sym = methodNotFound;
List<MethodResolutionPhase> 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;
}
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;
}
}
return bestSoFar;
}
MethodResolutionContext currentResolutionContext = null;
}

View File

@ -0,0 +1,60 @@
/*
* @test /nodynamiccopyright/
* @bug 7132880
* @summary Resolve should support nested resolution contexts
* @compile/fail/ref=T7132880.out -XDrawDiagnostics T7132880.java
*/
class Outer {
void m1(String s) { }
void m2(int i1, int i2) { }
class Inner {
void test() {
//ok - no method named 'm' in Inner - hence, class to search is Outer
m1("");
}
}
class Inner1 {
void m1(Integer i) { }
void test() {
//error - Inner1 defines an incompatible method - hence, class to search is Inner1
m1("");
}
}
class Inner2 {
private void m1(Integer i) { }
private void m1(Double d) { }
void test() {
//error - Inner2 defines multiple incompatible methods - hence, class to search is Inner2
m1("");
}
}
class Inner3 {
private void m2(Object o, int i) { }
private void m2(int i, Object o) { }
void test() {
//error - Inner3 defines multiple ambiguous methods - hence, class to search is Inner3
m2(1, 1);
}
}
class Inner4 extends Inner2 {
void test() {
//ok - Inner2 defines multiple incompatible inaccessible methods - hence, class to search is Outer
m1("");
}
}
class Inner5 extends Inner3 {
void test() {
//ok - Inner3 defines multiple inaccessible ambiguous methods - hence, class to search is Outer
m2(1, 1);
}
}
}

View File

@ -0,0 +1,4 @@
T7132880.java:23:12: compiler.err.cant.apply.symbol.1: kindname.method, m1, java.lang.Integer, java.lang.String, kindname.class, Outer.Inner1, (compiler.misc.no.conforming.assignment.exists: java.lang.String, java.lang.Integer)
T7132880.java:33:12: compiler.err.cant.apply.symbols: kindname.method, m1, java.lang.String,{(compiler.misc.inapplicable.method: kindname.method, Outer.Inner2, m1(java.lang.Double), (compiler.misc.no.conforming.assignment.exists: java.lang.String, java.lang.Double)),(compiler.misc.inapplicable.method: kindname.method, Outer.Inner2, m1(java.lang.Integer), (compiler.misc.no.conforming.assignment.exists: java.lang.String, java.lang.Integer))}
T7132880.java:43:12: compiler.err.ref.ambiguous: m2, kindname.method, m2(java.lang.Object,int), Outer.Inner3, kindname.method, m2(int,java.lang.Object), Outer.Inner3
3 errors