1.1 --- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Jan 07 17:51:05 2013 +0000 1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java Tue Jan 08 10:15:30 2013 +0100 1.3 @@ -506,6 +506,7 @@ 1.4 List<Type> typeargtypes, 1.5 boolean allowBoxing, 1.6 boolean useVarargs, 1.7 + MethodCheck methodCheck, 1.8 Warner warn) throws Infer.InferenceException { 1.9 1.10 Type mt = types.memberType(site, m); 1.11 @@ -558,10 +559,11 @@ 1.12 allowBoxing, 1.13 useVarargs, 1.14 currentResolutionContext, 1.15 + methodCheck, 1.16 warn); 1.17 1.18 - checkRawArgumentsAcceptable(env, m, argtypes, mt.getParameterTypes(), 1.19 - allowBoxing, useVarargs, warn); 1.20 + methodCheck.argumentsAcceptable(env, currentResolutionContext.deferredAttrContext(m, infer.emptyContext), 1.21 + argtypes, mt.getParameterTypes(), warn); 1.22 return mt; 1.23 } 1.24 1.25 @@ -578,7 +580,7 @@ 1.26 currentResolutionContext.attrMode = DeferredAttr.AttrMode.CHECK; 1.27 MethodResolutionPhase step = currentResolutionContext.step = env.info.pendingResolutionPhase; 1.28 return rawInstantiate(env, site, m, resultInfo, argtypes, typeargtypes, 1.29 - step.isBoxingRequired(), step.isVarargsRequired(), warn); 1.30 + step.isBoxingRequired(), step.isVarargsRequired(), resolveMethodCheck, warn); 1.31 } 1.32 finally { 1.33 currentResolutionContext = prevContext; 1.34 @@ -595,81 +597,66 @@ 1.35 List<Type> typeargtypes, 1.36 boolean allowBoxing, 1.37 boolean useVarargs, 1.38 + MethodCheck methodCheck, 1.39 Warner warn) { 1.40 try { 1.41 return rawInstantiate(env, site, m, resultInfo, argtypes, typeargtypes, 1.42 - allowBoxing, useVarargs, warn); 1.43 + allowBoxing, useVarargs, methodCheck, warn); 1.44 } catch (InapplicableMethodException ex) { 1.45 return null; 1.46 } 1.47 } 1.48 1.49 - /** Check if a parameter list accepts a list of args. 1.50 + /** 1.51 + * This interface defines an entry point that should be used to perform a 1.52 + * method check. A method check usually consist in determining as to whether 1.53 + * a set of types (actuals) is compatible with another set of types (formals). 1.54 + * Since the notion of compatibility can vary depending on the circumstances, 1.55 + * this interfaces allows to easily add new pluggable method check routines. 1.56 */ 1.57 - boolean argumentsAcceptable(Env<AttrContext> env, 1.58 - Symbol msym, 1.59 + interface MethodCheck { 1.60 + /** 1.61 + * Main method check routine. A method check usually consist in determining 1.62 + * as to whether a set of types (actuals) is compatible with another set of 1.63 + * types (formals). If an incompatibility is found, an unchecked exception 1.64 + * is assumed to be thrown. 1.65 + */ 1.66 + void argumentsAcceptable(Env<AttrContext> env, 1.67 + DeferredAttrContext deferredAttrContext, 1.68 List<Type> argtypes, 1.69 List<Type> formals, 1.70 - boolean allowBoxing, 1.71 - boolean useVarargs, 1.72 - Warner warn) { 1.73 - try { 1.74 - checkRawArgumentsAcceptable(env, msym, argtypes, formals, allowBoxing, useVarargs, warn); 1.75 - return true; 1.76 - } catch (InapplicableMethodException ex) { 1.77 - return false; 1.78 + Warner warn); 1.79 + } 1.80 + 1.81 + /** 1.82 + * Helper enum defining all method check diagnostics (used by resolveMethodCheck). 1.83 + */ 1.84 + enum MethodCheckDiag { 1.85 + /** 1.86 + * Actuals and formals differs in length. 1.87 + */ 1.88 + ARITY_MISMATCH("arg.length.mismatch", "infer.arg.length.mismatch"), 1.89 + /** 1.90 + * An actual is incompatible with a formal. 1.91 + */ 1.92 + ARG_MISMATCH("no.conforming.assignment.exists", "infer.no.conforming.assignment.exists"), 1.93 + /** 1.94 + * An actual is incompatible with the varargs element type. 1.95 + */ 1.96 + VARARG_MISMATCH("varargs.argument.mismatch", "infer.varargs.argument.mismatch"), 1.97 + /** 1.98 + * The varargs element type is inaccessible. 1.99 + */ 1.100 + INACCESSIBLE_VARARGS("inaccessible.varargs.type", "inaccessible.varargs.type"); 1.101 + 1.102 + final String basicKey; 1.103 + final String inferKey; 1.104 + 1.105 + MethodCheckDiag(String basicKey, String inferKey) { 1.106 + this.basicKey = basicKey; 1.107 + this.inferKey = inferKey; 1.108 } 1.109 } 1.110 - /** 1.111 - * A check handler is used by the main method applicability routine in order 1.112 - * to handle specific method applicability failures. It is assumed that a class 1.113 - * implementing this interface should throw exceptions that are a subtype of 1.114 - * InapplicableMethodException (see below). Such exception will terminate the 1.115 - * method applicability check and propagate important info outwards (for the 1.116 - * purpose of generating better diagnostics). 1.117 - */ 1.118 - interface MethodCheckHandler { 1.119 - /* The number of actuals and formals differ */ 1.120 - InapplicableMethodException arityMismatch(); 1.121 - /* An actual argument type does not conform to the corresponding formal type */ 1.122 - InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic details); 1.123 - /* The element type of a varargs is not accessible in the current context */ 1.124 - InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected); 1.125 - } 1.126 - 1.127 - /** 1.128 - * Basic method check handler used within Resolve - all methods end up 1.129 - * throwing InapplicableMethodException; a diagnostic fragment that describes 1.130 - * the cause as to why the method is not applicable is set on the exception 1.131 - * before it is thrown. 1.132 - */ 1.133 - MethodCheckHandler resolveHandler = new MethodCheckHandler() { 1.134 - public InapplicableMethodException arityMismatch() { 1.135 - return inapplicableMethodException.setMessage("arg.length.mismatch"); 1.136 - } 1.137 - public InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic details) { 1.138 - String key = varargs ? 1.139 - "varargs.argument.mismatch" : 1.140 - "no.conforming.assignment.exists"; 1.141 - return inapplicableMethodException.setMessage(key, 1.142 - details); 1.143 - } 1.144 - public InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected) { 1.145 - return inapplicableMethodException.setMessage("inaccessible.varargs.type", 1.146 - expected, Kinds.kindName(location), location); 1.147 - } 1.148 - }; 1.149 - 1.150 - void checkRawArgumentsAcceptable(Env<AttrContext> env, 1.151 - Symbol msym, 1.152 - List<Type> argtypes, 1.153 - List<Type> formals, 1.154 - boolean allowBoxing, 1.155 - boolean useVarargs, 1.156 - Warner warn) { 1.157 - checkRawArgumentsAcceptable(env, msym, currentResolutionContext.attrMode(), infer.emptyContext, argtypes, formals, 1.158 - allowBoxing, useVarargs, warn, resolveHandler); 1.159 - } 1.160 1.161 /** 1.162 * Main method applicability routine. Given a list of actual types A, 1.163 @@ -689,68 +676,94 @@ 1.164 * 1.165 * A method check handler (see above) is used in order to report errors. 1.166 */ 1.167 - void checkRawArgumentsAcceptable(final Env<AttrContext> env, 1.168 - Symbol msym, 1.169 - DeferredAttr.AttrMode mode, 1.170 - final Infer.InferenceContext inferenceContext, 1.171 - List<Type> argtypes, 1.172 - List<Type> formals, 1.173 - boolean allowBoxing, 1.174 - boolean useVarargs, 1.175 - Warner warn, 1.176 - final MethodCheckHandler handler) { 1.177 - Type varargsFormal = useVarargs ? formals.last() : null; 1.178 - 1.179 - if (varargsFormal == null && 1.180 - argtypes.size() != formals.size()) { 1.181 - throw handler.arityMismatch(); // not enough args 1.182 - } 1.183 - 1.184 - DeferredAttr.DeferredAttrContext deferredAttrContext = 1.185 - deferredAttr.new DeferredAttrContext(mode, msym, currentResolutionContext.step, inferenceContext); 1.186 - 1.187 - while (argtypes.nonEmpty() && formals.head != varargsFormal) { 1.188 - ResultInfo mresult = methodCheckResult(formals.head, allowBoxing, false, inferenceContext, deferredAttrContext, handler, warn); 1.189 - mresult.check(null, argtypes.head); 1.190 - argtypes = argtypes.tail; 1.191 - formals = formals.tail; 1.192 - } 1.193 - 1.194 - if (formals.head != varargsFormal) { 1.195 - throw handler.arityMismatch(); // not enough args 1.196 - } 1.197 - 1.198 - if (useVarargs) { 1.199 - //note: if applicability check is triggered by most specific test, 1.200 - //the last argument of a varargs is _not_ an array type (see JLS 15.12.2.5) 1.201 - final Type elt = types.elemtype(varargsFormal); 1.202 - ResultInfo mresult = methodCheckResult(elt, allowBoxing, true, inferenceContext, deferredAttrContext, handler, warn); 1.203 - while (argtypes.nonEmpty()) { 1.204 + MethodCheck resolveMethodCheck = new MethodCheck() { 1.205 + @Override 1.206 + public void argumentsAcceptable(final Env<AttrContext> env, 1.207 + DeferredAttrContext deferredAttrContext, 1.208 + List<Type> argtypes, 1.209 + List<Type> formals, 1.210 + Warner warn) { 1.211 + //should we expand formals? 1.212 + boolean useVarargs = deferredAttrContext.phase.isVarargsRequired(); 1.213 + 1.214 + //inference context used during this method check 1.215 + InferenceContext inferenceContext = deferredAttrContext.inferenceContext; 1.216 + 1.217 + Type varargsFormal = useVarargs ? formals.last() : null; 1.218 + 1.219 + if (varargsFormal == null && 1.220 + argtypes.size() != formals.size()) { 1.221 + report(MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args 1.222 + } 1.223 + 1.224 + while (argtypes.nonEmpty() && formals.head != varargsFormal) { 1.225 + ResultInfo mresult = methodCheckResult(false, formals.head, deferredAttrContext, warn); 1.226 mresult.check(null, argtypes.head); 1.227 argtypes = argtypes.tail; 1.228 + formals = formals.tail; 1.229 } 1.230 - //check varargs element type accessibility 1.231 - varargsAccessible(env, elt, handler, inferenceContext); 1.232 - } 1.233 - 1.234 - deferredAttrContext.complete(); 1.235 - } 1.236 - 1.237 - void varargsAccessible(final Env<AttrContext> env, final Type t, final Resolve.MethodCheckHandler handler, final InferenceContext inferenceContext) { 1.238 - if (inferenceContext.free(t)) { 1.239 - inferenceContext.addFreeTypeListener(List.of(t), new FreeTypeListener() { 1.240 - @Override 1.241 - public void typesInferred(InferenceContext inferenceContext) { 1.242 - varargsAccessible(env, inferenceContext.asInstType(t, types), handler, inferenceContext); 1.243 + 1.244 + if (formals.head != varargsFormal) { 1.245 + report(MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args 1.246 + } 1.247 + 1.248 + if (useVarargs) { 1.249 + //note: if applicability check is triggered by most specific test, 1.250 + //the last argument of a varargs is _not_ an array type (see JLS 15.12.2.5) 1.251 + final Type elt = types.elemtype(varargsFormal); 1.252 + ResultInfo mresult = methodCheckResult(true, elt, deferredAttrContext, warn); 1.253 + while (argtypes.nonEmpty()) { 1.254 + mresult.check(null, argtypes.head); 1.255 + argtypes = argtypes.tail; 1.256 } 1.257 - }); 1.258 - } else { 1.259 - if (!isAccessible(env, t)) { 1.260 - Symbol location = env.enclClass.sym; 1.261 - throw handler.inaccessibleVarargs(location, t); 1.262 + //check varargs element type accessibility 1.263 + varargsAccessible(env, elt, inferenceContext); 1.264 } 1.265 } 1.266 - } 1.267 + 1.268 + private void report(MethodCheckDiag diag, InferenceContext inferenceContext, Object... args) { 1.269 + boolean inferDiag = inferenceContext != infer.emptyContext; 1.270 + InapplicableMethodException ex = inferDiag ? 1.271 + infer.inferenceException : inapplicableMethodException; 1.272 + if (inferDiag && (!diag.inferKey.equals(diag.basicKey))) { 1.273 + Object[] args2 = new Object[args.length + 1]; 1.274 + System.arraycopy(args, 0, args2, 1, args.length); 1.275 + args2[0] = inferenceContext.inferenceVars(); 1.276 + args = args2; 1.277 + } 1.278 + throw ex.setMessage(inferDiag ? diag.inferKey : diag.basicKey, args); 1.279 + } 1.280 + 1.281 + private void varargsAccessible(final Env<AttrContext> env, final Type t, final InferenceContext inferenceContext) { 1.282 + if (inferenceContext.free(t)) { 1.283 + inferenceContext.addFreeTypeListener(List.of(t), new FreeTypeListener() { 1.284 + @Override 1.285 + public void typesInferred(InferenceContext inferenceContext) { 1.286 + varargsAccessible(env, inferenceContext.asInstType(t, types), inferenceContext); 1.287 + } 1.288 + }); 1.289 + } else { 1.290 + if (!isAccessible(env, t)) { 1.291 + Symbol location = env.enclClass.sym; 1.292 + report(MethodCheckDiag.INACCESSIBLE_VARARGS, inferenceContext, t, Kinds.kindName(location), location); 1.293 + } 1.294 + } 1.295 + } 1.296 + 1.297 + private ResultInfo methodCheckResult(final boolean varargsCheck, Type to, 1.298 + final DeferredAttr.DeferredAttrContext deferredAttrContext, Warner rsWarner) { 1.299 + CheckContext checkContext = new MethodCheckContext(!deferredAttrContext.phase.isBoxingRequired(), deferredAttrContext, rsWarner) { 1.300 + MethodCheckDiag methodDiag = varargsCheck ? 1.301 + MethodCheckDiag.VARARG_MISMATCH : MethodCheckDiag.ARG_MISMATCH; 1.302 + 1.303 + @Override 1.304 + public void report(DiagnosticPosition pos, JCDiagnostic details) { 1.305 + report(methodDiag, deferredAttrContext.inferenceContext, details); 1.306 + } 1.307 + }; 1.308 + return new MethodResultInfo(to, checkContext); 1.309 + } 1.310 + }; 1.311 1.312 /** 1.313 * Check context to be used during method applicability checks. A method check 1.314 @@ -758,23 +771,24 @@ 1.315 */ 1.316 abstract class MethodCheckContext implements CheckContext { 1.317 1.318 - MethodCheckHandler handler; 1.319 - boolean useVarargs; 1.320 - Infer.InferenceContext inferenceContext; 1.321 + boolean strict; 1.322 DeferredAttrContext deferredAttrContext; 1.323 Warner rsWarner; 1.324 1.325 - public MethodCheckContext(MethodCheckHandler handler, boolean useVarargs, 1.326 - Infer.InferenceContext inferenceContext, DeferredAttrContext deferredAttrContext, Warner rsWarner) { 1.327 - this.handler = handler; 1.328 - this.useVarargs = useVarargs; 1.329 - this.inferenceContext = inferenceContext; 1.330 - this.deferredAttrContext = deferredAttrContext; 1.331 - this.rsWarner = rsWarner; 1.332 + public MethodCheckContext(boolean strict, DeferredAttrContext deferredAttrContext, Warner rsWarner) { 1.333 + this.strict = strict; 1.334 + this.deferredAttrContext = deferredAttrContext; 1.335 + this.rsWarner = rsWarner; 1.336 } 1.337 1.338 + public boolean compatible(Type found, Type req, Warner warn) { 1.339 + return strict ? 1.340 + types.isSubtypeUnchecked(found, deferredAttrContext.inferenceContext.asFree(req, types), warn) : 1.341 + types.isConvertible(found, deferredAttrContext.inferenceContext.asFree(req, types), warn); 1.342 + } 1.343 + 1.344 public void report(DiagnosticPosition pos, JCDiagnostic details) { 1.345 - throw handler.argumentMismatch(useVarargs, details); 1.346 + throw inapplicableMethodException.setMessage(details); 1.347 } 1.348 1.349 public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) { 1.350 @@ -782,7 +796,7 @@ 1.351 } 1.352 1.353 public InferenceContext inferenceContext() { 1.354 - return inferenceContext; 1.355 + return deferredAttrContext.inferenceContext; 1.356 } 1.357 1.358 public DeferredAttrContext deferredAttrContext() { 1.359 @@ -791,56 +805,13 @@ 1.360 } 1.361 1.362 /** 1.363 - * Subclass of method check context class that implements strict method conversion. 1.364 - * Strict method conversion checks compatibility between types using subtyping tests. 1.365 + * ResultInfo class to be used during method applicability checks. Check 1.366 + * for deferred types goes through special path. 1.367 */ 1.368 - class StrictMethodContext extends MethodCheckContext { 1.369 - 1.370 - public StrictMethodContext(MethodCheckHandler handler, boolean useVarargs, 1.371 - Infer.InferenceContext inferenceContext, DeferredAttrContext deferredAttrContext, Warner rsWarner) { 1.372 - super(handler, useVarargs, inferenceContext, deferredAttrContext, rsWarner); 1.373 - } 1.374 - 1.375 - public boolean compatible(Type found, Type req, Warner warn) { 1.376 - return types.isSubtypeUnchecked(found, inferenceContext.asFree(req, types), warn); 1.377 - } 1.378 - } 1.379 - 1.380 - /** 1.381 - * Subclass of method check context class that implements loose method conversion. 1.382 - * Loose method conversion checks compatibility between types using method conversion tests. 1.383 - */ 1.384 - class LooseMethodContext extends MethodCheckContext { 1.385 - 1.386 - public LooseMethodContext(MethodCheckHandler handler, boolean useVarargs, 1.387 - Infer.InferenceContext inferenceContext, DeferredAttrContext deferredAttrContext, Warner rsWarner) { 1.388 - super(handler, useVarargs, inferenceContext, deferredAttrContext, rsWarner); 1.389 - } 1.390 - 1.391 - public boolean compatible(Type found, Type req, Warner warn) { 1.392 - return types.isConvertible(found, inferenceContext.asFree(req, types), warn); 1.393 - } 1.394 - } 1.395 - 1.396 - /** 1.397 - * Create a method check context to be used during method applicability check 1.398 - */ 1.399 - ResultInfo methodCheckResult(Type to, boolean allowBoxing, boolean useVarargs, 1.400 - Infer.InferenceContext inferenceContext, DeferredAttr.DeferredAttrContext deferredAttrContext, 1.401 - MethodCheckHandler methodHandler, Warner rsWarner) { 1.402 - MethodCheckContext checkContext = allowBoxing ? 1.403 - new LooseMethodContext(methodHandler, useVarargs, inferenceContext, deferredAttrContext, rsWarner) : 1.404 - new StrictMethodContext(methodHandler, useVarargs, inferenceContext, deferredAttrContext, rsWarner); 1.405 - return new MethodResultInfo(to, checkContext, deferredAttrContext); 1.406 - } 1.407 - 1.408 class MethodResultInfo extends ResultInfo { 1.409 1.410 - DeferredAttr.DeferredAttrContext deferredAttrContext; 1.411 - 1.412 - public MethodResultInfo(Type pt, CheckContext checkContext, DeferredAttr.DeferredAttrContext deferredAttrContext) { 1.413 + public MethodResultInfo(Type pt, CheckContext checkContext) { 1.414 attr.super(VAL, pt, checkContext); 1.415 - this.deferredAttrContext = deferredAttrContext; 1.416 } 1.417 1.418 @Override 1.419 @@ -855,12 +826,12 @@ 1.420 1.421 @Override 1.422 protected MethodResultInfo dup(Type newPt) { 1.423 - return new MethodResultInfo(newPt, checkContext, deferredAttrContext); 1.424 + return new MethodResultInfo(newPt, checkContext); 1.425 } 1.426 1.427 @Override 1.428 protected ResultInfo dup(CheckContext newContext) { 1.429 - return new MethodResultInfo(pt, newContext, deferredAttrContext); 1.430 + return new MethodResultInfo(pt, newContext); 1.431 } 1.432 } 1.433 1.434 @@ -1071,7 +1042,7 @@ 1.435 Assert.check(sym.kind < AMBIGUOUS); 1.436 try { 1.437 Type mt = rawInstantiate(env, site, sym, null, argtypes, typeargtypes, 1.438 - allowBoxing, useVarargs, types.noWarnings); 1.439 + allowBoxing, useVarargs, resolveMethodCheck, types.noWarnings); 1.440 if (!operator) 1.441 currentResolutionContext.addApplicableCandidate(sym, mt); 1.442 } catch (InapplicableMethodException ex) { 1.443 @@ -1274,12 +1245,19 @@ 1.444 } 1.445 //where 1.446 private boolean invocationMoreSpecific(Env<AttrContext> env, Type site, Symbol m2, List<Type> argtypes1, boolean allowBoxing, boolean useVarargs) { 1.447 - noteWarner.clear(); 1.448 - Type mst = instantiate(env, site, m2, null, 1.449 - types.lowerBounds(argtypes1), null, 1.450 - allowBoxing, false, noteWarner); 1.451 - return mst != null && 1.452 - !noteWarner.hasLint(Lint.LintCategory.UNCHECKED); 1.453 + MethodResolutionContext prevContext = currentResolutionContext; 1.454 + try { 1.455 + currentResolutionContext = new MethodResolutionContext(); 1.456 + currentResolutionContext.step = allowBoxing ? BOX : BASIC; 1.457 + noteWarner.clear(); 1.458 + Type mst = instantiate(env, site, m2, null, 1.459 + types.lowerBounds(argtypes1), null, 1.460 + allowBoxing, false, resolveMethodCheck, noteWarner); 1.461 + return mst != null && 1.462 + !noteWarner.hasLint(Lint.LintCategory.UNCHECKED); 1.463 + } finally { 1.464 + currentResolutionContext = prevContext; 1.465 + } 1.466 } 1.467 //where 1.468 private Symbol adjustVarargs(Symbol to, Symbol from, boolean useVarargs) { 1.469 @@ -2366,9 +2344,11 @@ 1.470 try { 1.471 currentResolutionContext = new MethodResolutionContext(); 1.472 Name name = treeinfo.operatorName(optag); 1.473 + env.info.pendingResolutionPhase = currentResolutionContext.step = BASIC; 1.474 Symbol sym = findMethod(env, syms.predefClass.type, name, argtypes, 1.475 null, false, false, true); 1.476 if (boxingEnabled && sym.kind >= WRONG_MTHS) 1.477 + env.info.pendingResolutionPhase = currentResolutionContext.step = BOX; 1.478 sym = findMethod(env, syms.predefClass.type, name, argtypes, 1.479 null, true, false, true); 1.480 return accessMethod(sym, pos, env.enclClass.sym.type, name, 1.481 @@ -3450,6 +3430,10 @@ 1.482 candidates = candidates.append(c); 1.483 } 1.484 1.485 + DeferredAttrContext deferredAttrContext(Symbol sym, InferenceContext inferenceContext) { 1.486 + return deferredAttr.new DeferredAttrContext(attrMode, sym, step, inferenceContext); 1.487 + } 1.488 + 1.489 /** 1.490 * This class represents an overload resolution candidate. There are two 1.491 * kinds of candidates: applicable methods and inapplicable methods;