mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 11:04:34 +02:00
8005243: Restructure method check code to allow pluggable checkers
Add interface to perform a method check - to be implemented by helper classes Reviewed-by: jjg
This commit is contained in:
parent
259f5d7cc8
commit
159b251085
2 changed files with 174 additions and 212 deletions
|
@ -114,7 +114,7 @@ public class Infer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final InferenceException inferenceException;
|
final InferenceException inferenceException;
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Mini/Maximization of UndetVars
|
* Mini/Maximization of UndetVars
|
||||||
|
@ -271,15 +271,19 @@ public class Infer {
|
||||||
boolean allowBoxing,
|
boolean allowBoxing,
|
||||||
boolean useVarargs,
|
boolean useVarargs,
|
||||||
Resolve.MethodResolutionContext resolveContext,
|
Resolve.MethodResolutionContext resolveContext,
|
||||||
|
Resolve.MethodCheck methodCheck,
|
||||||
Warner warn) throws InferenceException {
|
Warner warn) throws InferenceException {
|
||||||
//-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
|
//-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
|
||||||
final InferenceContext inferenceContext = new InferenceContext(tvars, this, true);
|
final InferenceContext inferenceContext = new InferenceContext(tvars, this, true);
|
||||||
inferenceException.clear();
|
inferenceException.clear();
|
||||||
|
|
||||||
|
DeferredAttr.DeferredAttrContext deferredAttrContext =
|
||||||
|
resolveContext.deferredAttrContext(msym, inferenceContext);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
rs.checkRawArgumentsAcceptable(env, msym, resolveContext.attrMode(), inferenceContext,
|
methodCheck.argumentsAcceptable(env, deferredAttrContext, argtypes, mt.getParameterTypes(), warn);
|
||||||
argtypes, mt.getParameterTypes(), allowBoxing, useVarargs, warn,
|
|
||||||
new InferenceCheckHandler(inferenceContext));
|
deferredAttrContext.complete();
|
||||||
|
|
||||||
// minimize as yet undetermined type variables
|
// minimize as yet undetermined type variables
|
||||||
for (Type t : inferenceContext.undetvars) {
|
for (Type t : inferenceContext.undetvars) {
|
||||||
|
@ -309,32 +313,6 @@ public class Infer {
|
||||||
inferenceContext.notifyChange(types);
|
inferenceContext.notifyChange(types);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//where
|
|
||||||
|
|
||||||
/** inference check handler **/
|
|
||||||
class InferenceCheckHandler implements Resolve.MethodCheckHandler {
|
|
||||||
|
|
||||||
InferenceContext inferenceContext;
|
|
||||||
|
|
||||||
public InferenceCheckHandler(InferenceContext inferenceContext) {
|
|
||||||
this.inferenceContext = inferenceContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InapplicableMethodException arityMismatch() {
|
|
||||||
return inferenceException.setMessage("infer.arg.length.mismatch", inferenceContext.inferenceVars());
|
|
||||||
}
|
|
||||||
public InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic details) {
|
|
||||||
String key = varargs ?
|
|
||||||
"infer.varargs.argument.mismatch" :
|
|
||||||
"infer.no.conforming.assignment.exists";
|
|
||||||
return inferenceException.setMessage(key,
|
|
||||||
inferenceContext.inferenceVars(), details);
|
|
||||||
}
|
|
||||||
public InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected) {
|
|
||||||
return inferenceException.setMessage("inaccessible.varargs.type",
|
|
||||||
expected, Kinds.kindName(location), location);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** check that type parameters are within their bounds.
|
/** check that type parameters are within their bounds.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -506,6 +506,7 @@ public class Resolve {
|
||||||
List<Type> typeargtypes,
|
List<Type> typeargtypes,
|
||||||
boolean allowBoxing,
|
boolean allowBoxing,
|
||||||
boolean useVarargs,
|
boolean useVarargs,
|
||||||
|
MethodCheck methodCheck,
|
||||||
Warner warn) throws Infer.InferenceException {
|
Warner warn) throws Infer.InferenceException {
|
||||||
|
|
||||||
Type mt = types.memberType(site, m);
|
Type mt = types.memberType(site, m);
|
||||||
|
@ -558,10 +559,11 @@ public class Resolve {
|
||||||
allowBoxing,
|
allowBoxing,
|
||||||
useVarargs,
|
useVarargs,
|
||||||
currentResolutionContext,
|
currentResolutionContext,
|
||||||
|
methodCheck,
|
||||||
warn);
|
warn);
|
||||||
|
|
||||||
checkRawArgumentsAcceptable(env, m, argtypes, mt.getParameterTypes(),
|
methodCheck.argumentsAcceptable(env, currentResolutionContext.deferredAttrContext(m, infer.emptyContext),
|
||||||
allowBoxing, useVarargs, warn);
|
argtypes, mt.getParameterTypes(), warn);
|
||||||
return mt;
|
return mt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -578,7 +580,7 @@ public class Resolve {
|
||||||
currentResolutionContext.attrMode = DeferredAttr.AttrMode.CHECK;
|
currentResolutionContext.attrMode = DeferredAttr.AttrMode.CHECK;
|
||||||
MethodResolutionPhase step = currentResolutionContext.step = env.info.pendingResolutionPhase;
|
MethodResolutionPhase step = currentResolutionContext.step = env.info.pendingResolutionPhase;
|
||||||
return rawInstantiate(env, site, m, resultInfo, argtypes, typeargtypes,
|
return rawInstantiate(env, site, m, resultInfo, argtypes, typeargtypes,
|
||||||
step.isBoxingRequired(), step.isVarargsRequired(), warn);
|
step.isBoxingRequired(), step.isVarargsRequired(), resolveMethodCheck, warn);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
currentResolutionContext = prevContext;
|
currentResolutionContext = prevContext;
|
||||||
|
@ -595,81 +597,66 @@ public class Resolve {
|
||||||
List<Type> typeargtypes,
|
List<Type> typeargtypes,
|
||||||
boolean allowBoxing,
|
boolean allowBoxing,
|
||||||
boolean useVarargs,
|
boolean useVarargs,
|
||||||
|
MethodCheck methodCheck,
|
||||||
Warner warn) {
|
Warner warn) {
|
||||||
try {
|
try {
|
||||||
return rawInstantiate(env, site, m, resultInfo, argtypes, typeargtypes,
|
return rawInstantiate(env, site, m, resultInfo, argtypes, typeargtypes,
|
||||||
allowBoxing, useVarargs, warn);
|
allowBoxing, useVarargs, methodCheck, warn);
|
||||||
} catch (InapplicableMethodException ex) {
|
} catch (InapplicableMethodException ex) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check if a parameter list accepts a list of args.
|
/**
|
||||||
|
* This interface defines an entry point that should be used to perform a
|
||||||
|
* method check. A method check usually consist in determining as to whether
|
||||||
|
* a set of types (actuals) is compatible with another set of types (formals).
|
||||||
|
* Since the notion of compatibility can vary depending on the circumstances,
|
||||||
|
* this interfaces allows to easily add new pluggable method check routines.
|
||||||
*/
|
*/
|
||||||
boolean argumentsAcceptable(Env<AttrContext> env,
|
interface MethodCheck {
|
||||||
Symbol msym,
|
/**
|
||||||
|
* Main method check routine. A method check usually consist in determining
|
||||||
|
* as to whether a set of types (actuals) is compatible with another set of
|
||||||
|
* types (formals). If an incompatibility is found, an unchecked exception
|
||||||
|
* is assumed to be thrown.
|
||||||
|
*/
|
||||||
|
void argumentsAcceptable(Env<AttrContext> env,
|
||||||
|
DeferredAttrContext deferredAttrContext,
|
||||||
List<Type> argtypes,
|
List<Type> argtypes,
|
||||||
List<Type> formals,
|
List<Type> formals,
|
||||||
boolean allowBoxing,
|
Warner warn);
|
||||||
boolean useVarargs,
|
}
|
||||||
Warner warn) {
|
|
||||||
try {
|
/**
|
||||||
checkRawArgumentsAcceptable(env, msym, argtypes, formals, allowBoxing, useVarargs, warn);
|
* Helper enum defining all method check diagnostics (used by resolveMethodCheck).
|
||||||
return true;
|
*/
|
||||||
} catch (InapplicableMethodException ex) {
|
enum MethodCheckDiag {
|
||||||
return false;
|
/**
|
||||||
|
* Actuals and formals differs in length.
|
||||||
|
*/
|
||||||
|
ARITY_MISMATCH("arg.length.mismatch", "infer.arg.length.mismatch"),
|
||||||
|
/**
|
||||||
|
* An actual is incompatible with a formal.
|
||||||
|
*/
|
||||||
|
ARG_MISMATCH("no.conforming.assignment.exists", "infer.no.conforming.assignment.exists"),
|
||||||
|
/**
|
||||||
|
* An actual is incompatible with the varargs element type.
|
||||||
|
*/
|
||||||
|
VARARG_MISMATCH("varargs.argument.mismatch", "infer.varargs.argument.mismatch"),
|
||||||
|
/**
|
||||||
|
* The varargs element type is inaccessible.
|
||||||
|
*/
|
||||||
|
INACCESSIBLE_VARARGS("inaccessible.varargs.type", "inaccessible.varargs.type");
|
||||||
|
|
||||||
|
final String basicKey;
|
||||||
|
final String inferKey;
|
||||||
|
|
||||||
|
MethodCheckDiag(String basicKey, String inferKey) {
|
||||||
|
this.basicKey = basicKey;
|
||||||
|
this.inferKey = inferKey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* A check handler is used by the main method applicability routine in order
|
|
||||||
* to handle specific method applicability failures. It is assumed that a class
|
|
||||||
* implementing this interface should throw exceptions that are a subtype of
|
|
||||||
* InapplicableMethodException (see below). Such exception will terminate the
|
|
||||||
* method applicability check and propagate important info outwards (for the
|
|
||||||
* purpose of generating better diagnostics).
|
|
||||||
*/
|
|
||||||
interface MethodCheckHandler {
|
|
||||||
/* The number of actuals and formals differ */
|
|
||||||
InapplicableMethodException arityMismatch();
|
|
||||||
/* An actual argument type does not conform to the corresponding formal type */
|
|
||||||
InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic details);
|
|
||||||
/* The element type of a varargs is not accessible in the current context */
|
|
||||||
InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Basic method check handler used within Resolve - all methods end up
|
|
||||||
* throwing InapplicableMethodException; a diagnostic fragment that describes
|
|
||||||
* the cause as to why the method is not applicable is set on the exception
|
|
||||||
* before it is thrown.
|
|
||||||
*/
|
|
||||||
MethodCheckHandler resolveHandler = new MethodCheckHandler() {
|
|
||||||
public InapplicableMethodException arityMismatch() {
|
|
||||||
return inapplicableMethodException.setMessage("arg.length.mismatch");
|
|
||||||
}
|
|
||||||
public InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic details) {
|
|
||||||
String key = varargs ?
|
|
||||||
"varargs.argument.mismatch" :
|
|
||||||
"no.conforming.assignment.exists";
|
|
||||||
return inapplicableMethodException.setMessage(key,
|
|
||||||
details);
|
|
||||||
}
|
|
||||||
public InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected) {
|
|
||||||
return inapplicableMethodException.setMessage("inaccessible.varargs.type",
|
|
||||||
expected, Kinds.kindName(location), location);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void checkRawArgumentsAcceptable(Env<AttrContext> env,
|
|
||||||
Symbol msym,
|
|
||||||
List<Type> argtypes,
|
|
||||||
List<Type> formals,
|
|
||||||
boolean allowBoxing,
|
|
||||||
boolean useVarargs,
|
|
||||||
Warner warn) {
|
|
||||||
checkRawArgumentsAcceptable(env, msym, currentResolutionContext.attrMode(), infer.emptyContext, argtypes, formals,
|
|
||||||
allowBoxing, useVarargs, warn, resolveHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main method applicability routine. Given a list of actual types A,
|
* Main method applicability routine. Given a list of actual types A,
|
||||||
|
@ -689,68 +676,94 @@ public class Resolve {
|
||||||
*
|
*
|
||||||
* A method check handler (see above) is used in order to report errors.
|
* A method check handler (see above) is used in order to report errors.
|
||||||
*/
|
*/
|
||||||
void checkRawArgumentsAcceptable(final Env<AttrContext> env,
|
MethodCheck resolveMethodCheck = new MethodCheck() {
|
||||||
Symbol msym,
|
@Override
|
||||||
DeferredAttr.AttrMode mode,
|
public void argumentsAcceptable(final Env<AttrContext> env,
|
||||||
final Infer.InferenceContext inferenceContext,
|
DeferredAttrContext deferredAttrContext,
|
||||||
List<Type> argtypes,
|
List<Type> argtypes,
|
||||||
List<Type> formals,
|
List<Type> formals,
|
||||||
boolean allowBoxing,
|
Warner warn) {
|
||||||
boolean useVarargs,
|
//should we expand formals?
|
||||||
Warner warn,
|
boolean useVarargs = deferredAttrContext.phase.isVarargsRequired();
|
||||||
final MethodCheckHandler handler) {
|
|
||||||
Type varargsFormal = useVarargs ? formals.last() : null;
|
|
||||||
|
|
||||||
if (varargsFormal == null &&
|
//inference context used during this method check
|
||||||
argtypes.size() != formals.size()) {
|
InferenceContext inferenceContext = deferredAttrContext.inferenceContext;
|
||||||
throw handler.arityMismatch(); // not enough args
|
|
||||||
}
|
|
||||||
|
|
||||||
DeferredAttr.DeferredAttrContext deferredAttrContext =
|
Type varargsFormal = useVarargs ? formals.last() : null;
|
||||||
deferredAttr.new DeferredAttrContext(mode, msym, currentResolutionContext.step, inferenceContext);
|
|
||||||
|
|
||||||
while (argtypes.nonEmpty() && formals.head != varargsFormal) {
|
if (varargsFormal == null &&
|
||||||
ResultInfo mresult = methodCheckResult(formals.head, allowBoxing, false, inferenceContext, deferredAttrContext, handler, warn);
|
argtypes.size() != formals.size()) {
|
||||||
mresult.check(null, argtypes.head);
|
report(MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args
|
||||||
argtypes = argtypes.tail;
|
}
|
||||||
formals = formals.tail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (formals.head != varargsFormal) {
|
while (argtypes.nonEmpty() && formals.head != varargsFormal) {
|
||||||
throw handler.arityMismatch(); // not enough args
|
ResultInfo mresult = methodCheckResult(false, formals.head, deferredAttrContext, warn);
|
||||||
}
|
|
||||||
|
|
||||||
if (useVarargs) {
|
|
||||||
//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(elt, allowBoxing, true, inferenceContext, deferredAttrContext, handler, warn);
|
|
||||||
while (argtypes.nonEmpty()) {
|
|
||||||
mresult.check(null, argtypes.head);
|
mresult.check(null, argtypes.head);
|
||||||
argtypes = argtypes.tail;
|
argtypes = argtypes.tail;
|
||||||
|
formals = formals.tail;
|
||||||
}
|
}
|
||||||
//check varargs element type accessibility
|
|
||||||
varargsAccessible(env, elt, handler, inferenceContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
deferredAttrContext.complete();
|
if (formals.head != varargsFormal) {
|
||||||
}
|
report(MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args
|
||||||
|
}
|
||||||
|
|
||||||
void varargsAccessible(final Env<AttrContext> env, final Type t, final Resolve.MethodCheckHandler handler, final InferenceContext inferenceContext) {
|
if (useVarargs) {
|
||||||
if (inferenceContext.free(t)) {
|
//note: if applicability check is triggered by most specific test,
|
||||||
inferenceContext.addFreeTypeListener(List.of(t), new FreeTypeListener() {
|
//the last argument of a varargs is _not_ an array type (see JLS 15.12.2.5)
|
||||||
@Override
|
final Type elt = types.elemtype(varargsFormal);
|
||||||
public void typesInferred(InferenceContext inferenceContext) {
|
ResultInfo mresult = methodCheckResult(true, elt, deferredAttrContext, warn);
|
||||||
varargsAccessible(env, inferenceContext.asInstType(t, types), handler, inferenceContext);
|
while (argtypes.nonEmpty()) {
|
||||||
|
mresult.check(null, argtypes.head);
|
||||||
|
argtypes = argtypes.tail;
|
||||||
}
|
}
|
||||||
});
|
//check varargs element type accessibility
|
||||||
} else {
|
varargsAccessible(env, elt, inferenceContext);
|
||||||
if (!isAccessible(env, t)) {
|
|
||||||
Symbol location = env.enclClass.sym;
|
|
||||||
throw handler.inaccessibleVarargs(location, t);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private void report(MethodCheckDiag diag, InferenceContext inferenceContext, Object... args) {
|
||||||
|
boolean inferDiag = inferenceContext != infer.emptyContext;
|
||||||
|
InapplicableMethodException ex = inferDiag ?
|
||||||
|
infer.inferenceException : inapplicableMethodException;
|
||||||
|
if (inferDiag && (!diag.inferKey.equals(diag.basicKey))) {
|
||||||
|
Object[] args2 = new Object[args.length + 1];
|
||||||
|
System.arraycopy(args, 0, args2, 1, args.length);
|
||||||
|
args2[0] = inferenceContext.inferenceVars();
|
||||||
|
args = args2;
|
||||||
|
}
|
||||||
|
throw ex.setMessage(inferDiag ? diag.inferKey : diag.basicKey, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void varargsAccessible(final Env<AttrContext> env, final Type t, final InferenceContext inferenceContext) {
|
||||||
|
if (inferenceContext.free(t)) {
|
||||||
|
inferenceContext.addFreeTypeListener(List.of(t), new FreeTypeListener() {
|
||||||
|
@Override
|
||||||
|
public void typesInferred(InferenceContext inferenceContext) {
|
||||||
|
varargsAccessible(env, inferenceContext.asInstType(t, types), inferenceContext);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (!isAccessible(env, t)) {
|
||||||
|
Symbol location = env.enclClass.sym;
|
||||||
|
report(MethodCheckDiag.INACCESSIBLE_VARARGS, inferenceContext, t, Kinds.kindName(location), location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResultInfo methodCheckResult(final boolean varargsCheck, Type to,
|
||||||
|
final DeferredAttr.DeferredAttrContext deferredAttrContext, Warner rsWarner) {
|
||||||
|
CheckContext checkContext = new MethodCheckContext(!deferredAttrContext.phase.isBoxingRequired(), deferredAttrContext, rsWarner) {
|
||||||
|
MethodCheckDiag methodDiag = varargsCheck ?
|
||||||
|
MethodCheckDiag.VARARG_MISMATCH : MethodCheckDiag.ARG_MISMATCH;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void report(DiagnosticPosition pos, JCDiagnostic details) {
|
||||||
|
report(methodDiag, deferredAttrContext.inferenceContext, details);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return new MethodResultInfo(to, checkContext);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check context to be used during method applicability checks. A method check
|
* Check context to be used during method applicability checks. A method check
|
||||||
|
@ -758,23 +771,24 @@ public class Resolve {
|
||||||
*/
|
*/
|
||||||
abstract class MethodCheckContext implements CheckContext {
|
abstract class MethodCheckContext implements CheckContext {
|
||||||
|
|
||||||
MethodCheckHandler handler;
|
boolean strict;
|
||||||
boolean useVarargs;
|
|
||||||
Infer.InferenceContext inferenceContext;
|
|
||||||
DeferredAttrContext deferredAttrContext;
|
DeferredAttrContext deferredAttrContext;
|
||||||
Warner rsWarner;
|
Warner rsWarner;
|
||||||
|
|
||||||
public MethodCheckContext(MethodCheckHandler handler, boolean useVarargs,
|
public MethodCheckContext(boolean strict, DeferredAttrContext deferredAttrContext, Warner rsWarner) {
|
||||||
Infer.InferenceContext inferenceContext, DeferredAttrContext deferredAttrContext, Warner rsWarner) {
|
this.strict = strict;
|
||||||
this.handler = handler;
|
this.deferredAttrContext = deferredAttrContext;
|
||||||
this.useVarargs = useVarargs;
|
this.rsWarner = rsWarner;
|
||||||
this.inferenceContext = inferenceContext;
|
}
|
||||||
this.deferredAttrContext = deferredAttrContext;
|
|
||||||
this.rsWarner = rsWarner;
|
public boolean compatible(Type found, Type req, Warner warn) {
|
||||||
|
return strict ?
|
||||||
|
types.isSubtypeUnchecked(found, deferredAttrContext.inferenceContext.asFree(req, types), warn) :
|
||||||
|
types.isConvertible(found, deferredAttrContext.inferenceContext.asFree(req, types), warn);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void report(DiagnosticPosition pos, JCDiagnostic details) {
|
public void report(DiagnosticPosition pos, JCDiagnostic details) {
|
||||||
throw handler.argumentMismatch(useVarargs, details);
|
throw inapplicableMethodException.setMessage(details);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) {
|
public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) {
|
||||||
|
@ -782,7 +796,7 @@ public class Resolve {
|
||||||
}
|
}
|
||||||
|
|
||||||
public InferenceContext inferenceContext() {
|
public InferenceContext inferenceContext() {
|
||||||
return inferenceContext;
|
return deferredAttrContext.inferenceContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeferredAttrContext deferredAttrContext() {
|
public DeferredAttrContext deferredAttrContext() {
|
||||||
|
@ -791,56 +805,13 @@ public class Resolve {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subclass of method check context class that implements strict method conversion.
|
* ResultInfo class to be used during method applicability checks. Check
|
||||||
* Strict method conversion checks compatibility between types using subtyping tests.
|
* for deferred types goes through special path.
|
||||||
*/
|
*/
|
||||||
class StrictMethodContext extends MethodCheckContext {
|
|
||||||
|
|
||||||
public StrictMethodContext(MethodCheckHandler handler, boolean useVarargs,
|
|
||||||
Infer.InferenceContext inferenceContext, DeferredAttrContext deferredAttrContext, Warner rsWarner) {
|
|
||||||
super(handler, useVarargs, inferenceContext, deferredAttrContext, rsWarner);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean compatible(Type found, Type req, Warner warn) {
|
|
||||||
return types.isSubtypeUnchecked(found, inferenceContext.asFree(req, types), warn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subclass of method check context class that implements loose method conversion.
|
|
||||||
* Loose method conversion checks compatibility between types using method conversion tests.
|
|
||||||
*/
|
|
||||||
class LooseMethodContext extends MethodCheckContext {
|
|
||||||
|
|
||||||
public LooseMethodContext(MethodCheckHandler handler, boolean useVarargs,
|
|
||||||
Infer.InferenceContext inferenceContext, DeferredAttrContext deferredAttrContext, Warner rsWarner) {
|
|
||||||
super(handler, useVarargs, inferenceContext, deferredAttrContext, rsWarner);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean compatible(Type found, Type req, Warner warn) {
|
|
||||||
return types.isConvertible(found, inferenceContext.asFree(req, types), warn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a method check context to be used during method applicability check
|
|
||||||
*/
|
|
||||||
ResultInfo methodCheckResult(Type to, boolean allowBoxing, boolean useVarargs,
|
|
||||||
Infer.InferenceContext inferenceContext, DeferredAttr.DeferredAttrContext deferredAttrContext,
|
|
||||||
MethodCheckHandler methodHandler, Warner rsWarner) {
|
|
||||||
MethodCheckContext checkContext = allowBoxing ?
|
|
||||||
new LooseMethodContext(methodHandler, useVarargs, inferenceContext, deferredAttrContext, rsWarner) :
|
|
||||||
new StrictMethodContext(methodHandler, useVarargs, inferenceContext, deferredAttrContext, rsWarner);
|
|
||||||
return new MethodResultInfo(to, checkContext, deferredAttrContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
class MethodResultInfo extends ResultInfo {
|
class MethodResultInfo extends ResultInfo {
|
||||||
|
|
||||||
DeferredAttr.DeferredAttrContext deferredAttrContext;
|
public MethodResultInfo(Type pt, CheckContext checkContext) {
|
||||||
|
|
||||||
public MethodResultInfo(Type pt, CheckContext checkContext, DeferredAttr.DeferredAttrContext deferredAttrContext) {
|
|
||||||
attr.super(VAL, pt, checkContext);
|
attr.super(VAL, pt, checkContext);
|
||||||
this.deferredAttrContext = deferredAttrContext;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -855,12 +826,12 @@ public class Resolve {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected MethodResultInfo dup(Type newPt) {
|
protected MethodResultInfo dup(Type newPt) {
|
||||||
return new MethodResultInfo(newPt, checkContext, deferredAttrContext);
|
return new MethodResultInfo(newPt, checkContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ResultInfo dup(CheckContext newContext) {
|
protected ResultInfo dup(CheckContext newContext) {
|
||||||
return new MethodResultInfo(pt, newContext, deferredAttrContext);
|
return new MethodResultInfo(pt, newContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1071,7 +1042,7 @@ public class Resolve {
|
||||||
Assert.check(sym.kind < AMBIGUOUS);
|
Assert.check(sym.kind < AMBIGUOUS);
|
||||||
try {
|
try {
|
||||||
Type mt = rawInstantiate(env, site, sym, null, argtypes, typeargtypes,
|
Type mt = rawInstantiate(env, site, sym, null, argtypes, typeargtypes,
|
||||||
allowBoxing, useVarargs, types.noWarnings);
|
allowBoxing, useVarargs, resolveMethodCheck, types.noWarnings);
|
||||||
if (!operator)
|
if (!operator)
|
||||||
currentResolutionContext.addApplicableCandidate(sym, mt);
|
currentResolutionContext.addApplicableCandidate(sym, mt);
|
||||||
} catch (InapplicableMethodException ex) {
|
} catch (InapplicableMethodException ex) {
|
||||||
|
@ -1274,12 +1245,19 @@ public class Resolve {
|
||||||
}
|
}
|
||||||
//where
|
//where
|
||||||
private boolean invocationMoreSpecific(Env<AttrContext> env, Type site, Symbol m2, List<Type> argtypes1, boolean allowBoxing, boolean useVarargs) {
|
private boolean invocationMoreSpecific(Env<AttrContext> env, Type site, Symbol m2, List<Type> argtypes1, boolean allowBoxing, boolean useVarargs) {
|
||||||
noteWarner.clear();
|
MethodResolutionContext prevContext = currentResolutionContext;
|
||||||
Type mst = instantiate(env, site, m2, null,
|
try {
|
||||||
types.lowerBounds(argtypes1), null,
|
currentResolutionContext = new MethodResolutionContext();
|
||||||
allowBoxing, false, noteWarner);
|
currentResolutionContext.step = allowBoxing ? BOX : BASIC;
|
||||||
return mst != null &&
|
noteWarner.clear();
|
||||||
!noteWarner.hasLint(Lint.LintCategory.UNCHECKED);
|
Type mst = instantiate(env, site, m2, null,
|
||||||
|
types.lowerBounds(argtypes1), null,
|
||||||
|
allowBoxing, false, resolveMethodCheck, noteWarner);
|
||||||
|
return mst != null &&
|
||||||
|
!noteWarner.hasLint(Lint.LintCategory.UNCHECKED);
|
||||||
|
} finally {
|
||||||
|
currentResolutionContext = prevContext;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//where
|
//where
|
||||||
private Symbol adjustVarargs(Symbol to, Symbol from, boolean useVarargs) {
|
private Symbol adjustVarargs(Symbol to, Symbol from, boolean useVarargs) {
|
||||||
|
@ -2366,9 +2344,11 @@ public class Resolve {
|
||||||
try {
|
try {
|
||||||
currentResolutionContext = new MethodResolutionContext();
|
currentResolutionContext = new MethodResolutionContext();
|
||||||
Name name = treeinfo.operatorName(optag);
|
Name name = treeinfo.operatorName(optag);
|
||||||
|
env.info.pendingResolutionPhase = currentResolutionContext.step = BASIC;
|
||||||
Symbol sym = findMethod(env, syms.predefClass.type, name, argtypes,
|
Symbol sym = findMethod(env, syms.predefClass.type, name, argtypes,
|
||||||
null, false, false, true);
|
null, false, false, true);
|
||||||
if (boxingEnabled && sym.kind >= WRONG_MTHS)
|
if (boxingEnabled && sym.kind >= WRONG_MTHS)
|
||||||
|
env.info.pendingResolutionPhase = currentResolutionContext.step = BOX;
|
||||||
sym = findMethod(env, syms.predefClass.type, name, argtypes,
|
sym = findMethod(env, syms.predefClass.type, name, argtypes,
|
||||||
null, true, false, true);
|
null, true, false, true);
|
||||||
return accessMethod(sym, pos, env.enclClass.sym.type, name,
|
return accessMethod(sym, pos, env.enclClass.sym.type, name,
|
||||||
|
@ -3450,6 +3430,10 @@ public class Resolve {
|
||||||
candidates = candidates.append(c);
|
candidates = candidates.append(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DeferredAttrContext deferredAttrContext(Symbol sym, InferenceContext inferenceContext) {
|
||||||
|
return deferredAttr.new DeferredAttrContext(attrMode, sym, step, inferenceContext);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents an overload resolution candidate. There are two
|
* This class represents an overload resolution candidate. There are two
|
||||||
* kinds of candidates: applicable methods and inapplicable methods;
|
* kinds of candidates: applicable methods and inapplicable methods;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue