60 |
62 |
61 protected Infer(Context context) { |
63 protected Infer(Context context) { |
62 context.put(inferKey, this); |
64 context.put(inferKey, this); |
63 syms = Symtab.instance(context); |
65 syms = Symtab.instance(context); |
64 types = Types.instance(context); |
66 types = Types.instance(context); |
|
67 rs = Resolve.instance(context); |
65 diags = JCDiagnostic.Factory.instance(context); |
68 diags = JCDiagnostic.Factory.instance(context); |
66 ambiguousNoInstanceException = |
69 ambiguousNoInstanceException = |
67 new NoInstanceException(true, diags); |
70 new NoInstanceException(true, diags); |
68 unambiguousNoInstanceException = |
71 unambiguousNoInstanceException = |
69 new NoInstanceException(false, diags); |
72 new NoInstanceException(false, diags); |
70 } |
73 invalidInstanceException = |
71 |
74 new InvalidInstanceException(diags); |
72 public static class NoInstanceException extends RuntimeException { |
75 |
|
76 } |
|
77 |
|
78 public static class InferenceException extends RuntimeException { |
73 private static final long serialVersionUID = 0; |
79 private static final long serialVersionUID = 0; |
74 |
|
75 boolean isAmbiguous; // exist several incomparable best instances? |
|
76 |
80 |
77 JCDiagnostic diagnostic; |
81 JCDiagnostic diagnostic; |
78 JCDiagnostic.Factory diags; |
82 JCDiagnostic.Factory diags; |
79 |
83 |
|
84 InferenceException(JCDiagnostic.Factory diags) { |
|
85 this.diagnostic = null; |
|
86 this.diags = diags; |
|
87 } |
|
88 |
|
89 InferenceException setMessage(String key, Object... args) { |
|
90 this.diagnostic = diags.fragment(key, args); |
|
91 return this; |
|
92 } |
|
93 |
|
94 public JCDiagnostic getDiagnostic() { |
|
95 return diagnostic; |
|
96 } |
|
97 } |
|
98 |
|
99 public static class NoInstanceException extends InferenceException { |
|
100 private static final long serialVersionUID = 1; |
|
101 |
|
102 boolean isAmbiguous; // exist several incomparable best instances? |
|
103 |
80 NoInstanceException(boolean isAmbiguous, JCDiagnostic.Factory diags) { |
104 NoInstanceException(boolean isAmbiguous, JCDiagnostic.Factory diags) { |
81 this.diagnostic = null; |
105 super(diags); |
82 this.isAmbiguous = isAmbiguous; |
106 this.isAmbiguous = isAmbiguous; |
83 this.diags = diags; |
107 } |
84 } |
108 } |
85 NoInstanceException setMessage(String key) { |
109 |
86 this.diagnostic = diags.fragment(key); |
110 public static class InvalidInstanceException extends InferenceException { |
87 return this; |
111 private static final long serialVersionUID = 2; |
88 } |
112 |
89 NoInstanceException setMessage(String key, Object arg1) { |
113 InvalidInstanceException(JCDiagnostic.Factory diags) { |
90 this.diagnostic = diags.fragment(key, arg1); |
114 super(diags); |
91 return this; |
115 } |
92 } |
116 } |
93 NoInstanceException setMessage(String key, Object arg1, Object arg2) { |
117 |
94 this.diagnostic = diags.fragment(key, arg1, arg2); |
|
95 return this; |
|
96 } |
|
97 NoInstanceException setMessage(String key, Object arg1, Object arg2, Object arg3) { |
|
98 this.diagnostic = diags.fragment(key, arg1, arg2, arg3); |
|
99 return this; |
|
100 } |
|
101 public JCDiagnostic getDiagnostic() { |
|
102 return diagnostic; |
|
103 } |
|
104 } |
|
105 private final NoInstanceException ambiguousNoInstanceException; |
118 private final NoInstanceException ambiguousNoInstanceException; |
106 private final NoInstanceException unambiguousNoInstanceException; |
119 private final NoInstanceException unambiguousNoInstanceException; |
|
120 private final InvalidInstanceException invalidInstanceException; |
107 |
121 |
108 /*************************************************************************** |
122 /*************************************************************************** |
109 * Auxiliary type values and classes |
123 * Auxiliary type values and classes |
110 ***************************************************************************/ |
124 ***************************************************************************/ |
111 |
125 |
257 |
271 |
258 // check bounds |
272 // check bounds |
259 List<Type> targs = Type.map(undetvars, getInstFun); |
273 List<Type> targs = Type.map(undetvars, getInstFun); |
260 targs = types.subst(targs, that.tvars, targs); |
274 targs = types.subst(targs, that.tvars, targs); |
261 checkWithinBounds(that.tvars, targs, warn); |
275 checkWithinBounds(that.tvars, targs, warn); |
262 |
276 return that.inst(targs, types); |
263 return getInstFun.apply(qtype1); |
|
264 } |
277 } |
265 |
278 |
266 /** Instantiate method type `mt' by finding instantiations of |
279 /** Instantiate method type `mt' by finding instantiations of |
267 * `tvars' so that method can be applied to `argtypes'. |
280 * `tvars' so that method can be applied to `argtypes'. |
268 */ |
281 */ |
269 public Type instantiateMethod(List<Type> tvars, |
282 public Type instantiateMethod(List<Type> tvars, |
270 MethodType mt, |
283 MethodType mt, |
271 List<Type> argtypes, |
284 final List<Type> argtypes, |
272 boolean allowBoxing, |
285 final boolean allowBoxing, |
273 boolean useVarargs, |
286 final boolean useVarargs, |
274 Warner warn) throws NoInstanceException { |
287 final Warner warn) throws InferenceException { |
275 //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG |
288 //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG |
276 List<Type> undetvars = Type.map(tvars, fromTypeVarFun); |
289 List<Type> undetvars = Type.map(tvars, fromTypeVarFun); |
277 List<Type> formals = mt.argtypes; |
290 List<Type> formals = mt.argtypes; |
278 |
291 //need to capture exactly once - otherwise subsequent |
|
292 //applicability checks might fail |
|
293 final List<Type> capturedArgs = types.capture(argtypes); |
|
294 List<Type> actuals = capturedArgs; |
|
295 List<Type> actualsNoCapture = argtypes; |
279 // instantiate all polymorphic argument types and |
296 // instantiate all polymorphic argument types and |
280 // set up lower bounds constraints for undetvars |
297 // set up lower bounds constraints for undetvars |
281 Type varargsFormal = useVarargs ? formals.last() : null; |
298 Type varargsFormal = useVarargs ? formals.last() : null; |
282 while (argtypes.nonEmpty() && formals.head != varargsFormal) { |
299 while (actuals.nonEmpty() && formals.head != varargsFormal) { |
283 Type ft = formals.head; |
300 Type formal = formals.head; |
284 Type at = argtypes.head.baseType(); |
301 Type actual = actuals.head.baseType(); |
285 if (at.tag == FORALL) |
302 Type actualNoCapture = actualsNoCapture.head.baseType(); |
286 at = instantiateArg((ForAll) at, ft, tvars, warn); |
303 if (actual.tag == FORALL) |
287 Type sft = types.subst(ft, tvars, undetvars); |
304 actual = instantiateArg((ForAll)actual, formal, tvars, warn); |
|
305 Type undetFormal = types.subst(formal, tvars, undetvars); |
288 boolean works = allowBoxing |
306 boolean works = allowBoxing |
289 ? types.isConvertible(at, sft, warn) |
307 ? types.isConvertible(actual, undetFormal, warn) |
290 : types.isSubtypeUnchecked(at, sft, warn); |
308 : types.isSubtypeUnchecked(actual, undetFormal, warn); |
291 if (!works) { |
309 if (!works) { |
292 throw unambiguousNoInstanceException |
310 throw unambiguousNoInstanceException |
293 .setMessage("no.conforming.assignment.exists", |
311 .setMessage("no.conforming.assignment.exists", |
294 tvars, at, ft); |
312 tvars, actualNoCapture, formal); |
295 } |
313 } |
296 formals = formals.tail; |
314 formals = formals.tail; |
297 argtypes = argtypes.tail; |
315 actuals = actuals.tail; |
|
316 actualsNoCapture = actualsNoCapture.tail; |
298 } |
317 } |
299 if (formals.head != varargsFormal || // not enough args |
318 if (formals.head != varargsFormal || // not enough args |
300 !useVarargs && argtypes.nonEmpty()) { // too many args |
319 !useVarargs && actuals.nonEmpty()) { // too many args |
301 // argument lists differ in length |
320 // argument lists differ in length |
302 throw unambiguousNoInstanceException |
321 throw unambiguousNoInstanceException |
303 .setMessage("arg.length.mismatch"); |
322 .setMessage("arg.length.mismatch"); |
304 } |
323 } |
305 |
324 |
306 // for varargs arguments as well |
325 // for varargs arguments as well |
307 if (useVarargs) { |
326 if (useVarargs) { |
308 Type elt = types.elemtype(varargsFormal); |
327 Type elemType = types.elemtype(varargsFormal); |
309 Type sft = types.subst(elt, tvars, undetvars); |
328 Type elemUndet = types.subst(elemType, tvars, undetvars); |
310 while (argtypes.nonEmpty()) { |
329 while (actuals.nonEmpty()) { |
311 Type ft = sft; |
330 Type actual = actuals.head.baseType(); |
312 Type at = argtypes.head.baseType(); |
331 Type actualNoCapture = actualsNoCapture.head.baseType(); |
313 if (at.tag == FORALL) |
332 if (actual.tag == FORALL) |
314 at = instantiateArg((ForAll) at, ft, tvars, warn); |
333 actual = instantiateArg((ForAll)actual, elemType, tvars, warn); |
315 boolean works = types.isConvertible(at, sft, warn); |
334 boolean works = types.isConvertible(actual, elemUndet, warn); |
316 if (!works) { |
335 if (!works) { |
317 throw unambiguousNoInstanceException |
336 throw unambiguousNoInstanceException |
318 .setMessage("no.conforming.assignment.exists", |
337 .setMessage("no.conforming.assignment.exists", |
319 tvars, at, ft); |
338 tvars, actualNoCapture, elemType); |
320 } |
339 } |
321 argtypes = argtypes.tail; |
340 actuals = actuals.tail; |
|
341 actualsNoCapture = actualsNoCapture.tail; |
322 } |
342 } |
323 } |
343 } |
324 |
344 |
325 // minimize as yet undetermined type variables |
345 // minimize as yet undetermined type variables |
326 for (Type t : undetvars) |
346 for (Type t : undetvars) |
347 undettypes.append(uv.inst); |
367 undettypes.append(uv.inst); |
348 } |
368 } |
349 } |
369 } |
350 checkWithinBounds(tvars, undettypes.toList(), warn); |
370 checkWithinBounds(tvars, undettypes.toList(), warn); |
351 |
371 |
|
372 mt = (MethodType)types.subst(mt, tvars, insttypes.toList()); |
|
373 |
352 if (!restvars.isEmpty()) { |
374 if (!restvars.isEmpty()) { |
353 // if there are uninstantiated variables, |
375 // if there are uninstantiated variables, |
354 // quantify result type with them |
376 // quantify result type with them |
355 mt = new MethodType(mt.argtypes, |
377 final List<Type> inferredTypes = insttypes.toList(); |
356 new ForAll(restvars.toList(), mt.restype), |
378 final List<Type> all_tvars = tvars; //this is the wrong tvars |
357 mt.thrown, syms.methodClass); |
379 final MethodType mt2 = new MethodType(mt.argtypes, null, mt.thrown, syms.methodClass); |
358 } |
380 mt2.restype = new ForAll(restvars.toList(), mt.restype) { |
359 |
381 @Override |
360 // return instantiated version of method type |
382 public Type inst(List<Type> inferred, Types types) throws NoInstanceException { |
361 return types.subst(mt, tvars, insttypes.toList()); |
383 List<Type> formals = types.subst(mt2.argtypes, tvars, inferred); |
|
384 if (!rs.argumentsAcceptable(capturedArgs, formals, |
|
385 allowBoxing, useVarargs, warn)) { |
|
386 // inferred method is not applicable |
|
387 throw invalidInstanceException.setMessage("inferred.do.not.conform.to.params", formals, argtypes); |
|
388 } |
|
389 // check that inferred bounds conform to their bounds |
|
390 checkWithinBounds(all_tvars, |
|
391 types.subst(inferredTypes, tvars, inferred), warn); |
|
392 return super.inst(inferred, types); |
|
393 }}; |
|
394 return mt2; |
|
395 } |
|
396 else if (!rs.argumentsAcceptable(capturedArgs, mt.getParameterTypes(), allowBoxing, useVarargs, warn)) { |
|
397 // inferred method is not applicable |
|
398 throw invalidInstanceException.setMessage("inferred.do.not.conform.to.params", mt.getParameterTypes(), argtypes); |
|
399 } |
|
400 else { |
|
401 // return instantiated version of method type |
|
402 return mt; |
|
403 } |
362 } |
404 } |
363 //where |
405 //where |
364 |
406 |
365 /** Try to instantiate argument type `that' to given type `to'. |
407 /** Try to instantiate argument type `that' to given type `to'. |
366 * If this fails, try to insantiate `that' to `to' where |
408 * If this fails, try to insantiate `that' to `to' where |
385 /** check that type parameters are within their bounds. |
427 /** check that type parameters are within their bounds. |
386 */ |
428 */ |
387 private void checkWithinBounds(List<Type> tvars, |
429 private void checkWithinBounds(List<Type> tvars, |
388 List<Type> arguments, |
430 List<Type> arguments, |
389 Warner warn) |
431 Warner warn) |
390 throws NoInstanceException { |
432 throws InvalidInstanceException { |
391 for (List<Type> tvs = tvars, args = arguments; |
433 for (List<Type> tvs = tvars, args = arguments; |
392 tvs.nonEmpty(); |
434 tvs.nonEmpty(); |
393 tvs = tvs.tail, args = args.tail) { |
435 tvs = tvs.tail, args = args.tail) { |
394 if (args.head instanceof UndetVar) continue; |
436 if (args.head instanceof UndetVar) continue; |
395 List<Type> bounds = types.subst(types.getBounds((TypeVar)tvs.head), tvars, arguments); |
437 List<Type> bounds = types.subst(types.getBounds((TypeVar)tvs.head), tvars, arguments); |
396 if (!types.isSubtypeUnchecked(args.head, bounds, warn)) |
438 if (!types.isSubtypeUnchecked(args.head, bounds, warn)) |
397 throw unambiguousNoInstanceException |
439 throw invalidInstanceException |
398 .setMessage("inferred.do.not.conform.to.bounds", |
440 .setMessage("inferred.do.not.conform.to.bounds", |
399 arguments, tvars); |
441 args.head, bounds); |
400 } |
442 } |
401 } |
443 } |
402 } |
444 } |