74 rs = Resolve.instance(context); |
77 rs = Resolve.instance(context); |
75 log = Log.instance(context); |
78 log = Log.instance(context); |
76 chk = Check.instance(context); |
79 chk = Check.instance(context); |
77 diags = JCDiagnostic.Factory.instance(context); |
80 diags = JCDiagnostic.Factory.instance(context); |
78 inferenceException = new InferenceException(diags); |
81 inferenceException = new InferenceException(diags); |
79 |
82 } |
80 } |
83 |
81 |
84 /** |
|
85 * This exception class is design to store a list of diagnostics corresponding |
|
86 * to inference errors that can arise during a method applicability check. |
|
87 */ |
82 public static class InferenceException extends InapplicableMethodException { |
88 public static class InferenceException extends InapplicableMethodException { |
83 private static final long serialVersionUID = 0; |
89 private static final long serialVersionUID = 0; |
84 |
90 |
|
91 List<JCDiagnostic> messages = List.nil(); |
|
92 |
85 InferenceException(JCDiagnostic.Factory diags) { |
93 InferenceException(JCDiagnostic.Factory diags) { |
86 super(diags); |
94 super(diags); |
87 } |
95 } |
|
96 |
|
97 @Override |
|
98 InapplicableMethodException setMessage(JCDiagnostic diag) { |
|
99 messages = messages.append(diag); |
|
100 return this; |
|
101 } |
|
102 |
|
103 @Override |
|
104 public JCDiagnostic getDiagnostic() { |
|
105 return messages.head; |
|
106 } |
|
107 |
|
108 void clear() { |
|
109 messages = List.nil(); |
|
110 } |
88 } |
111 } |
89 |
112 |
90 private final InferenceException inferenceException; |
113 private final InferenceException inferenceException; |
91 |
|
92 /*************************************************************************** |
|
93 * Auxiliary type values and classes |
|
94 ***************************************************************************/ |
|
95 |
|
96 /** A mapping that turns type variables into undetermined type variables. |
|
97 */ |
|
98 List<Type> makeUndetvars(List<Type> tvars) { |
|
99 List<Type> undetvars = Type.map(tvars, fromTypeVarFun); |
|
100 for (Type t : undetvars) { |
|
101 UndetVar uv = (UndetVar)t; |
|
102 uv.hibounds = types.getBounds((TypeVar)uv.qtype); |
|
103 } |
|
104 return undetvars; |
|
105 } |
|
106 //where |
|
107 Mapping fromTypeVarFun = new Mapping("fromTypeVarFun") { |
|
108 public Type apply(Type t) { |
|
109 if (t.tag == TYPEVAR) return new UndetVar(t); |
|
110 else return t.map(this); |
|
111 } |
|
112 }; |
|
113 |
114 |
114 /*************************************************************************** |
115 /*************************************************************************** |
115 * Mini/Maximization of UndetVars |
116 * Mini/Maximization of UndetVars |
116 ***************************************************************************/ |
117 ***************************************************************************/ |
117 |
118 |
118 /** Instantiate undetermined type variable to its minimal upper bound. |
119 /** Instantiate undetermined type variable to its minimal upper bound. |
119 * Throw a NoInstanceException if this not possible. |
120 * Throw a NoInstanceException if this not possible. |
120 */ |
121 */ |
121 void maximizeInst(UndetVar that, Warner warn) throws InferenceException { |
122 void maximizeInst(UndetVar that, Warner warn) throws InferenceException { |
122 List<Type> hibounds = Type.filter(that.hibounds, errorFilter); |
123 List<Type> hibounds = Type.filter(that.hibounds, boundFilter); |
123 if (that.eq.isEmpty()) { |
124 if (that.eq.isEmpty()) { |
124 if (hibounds.isEmpty()) |
125 if (hibounds.isEmpty()) |
125 that.inst = syms.objectType; |
126 that.inst = syms.objectType; |
126 else if (hibounds.tail.isEmpty()) |
127 else if (hibounds.tail.isEmpty()) |
127 that.inst = hibounds.head; |
128 that.inst = hibounds.head; |
164 } else { |
166 } else { |
165 that.inst = that.eq.head; |
167 that.inst = that.eq.head; |
166 } |
168 } |
167 } |
169 } |
168 |
170 |
169 Type asUndetType(Type t, List<Type> undetvars) { |
|
170 return types.subst(t, inferenceVars(undetvars), undetvars); |
|
171 } |
|
172 |
|
173 List<Type> inferenceVars(List<Type> undetvars) { |
|
174 ListBuffer<Type> tvars = ListBuffer.lb(); |
|
175 for (Type uv : undetvars) { |
|
176 tvars.append(((UndetVar)uv).qtype); |
|
177 } |
|
178 return tvars.toList(); |
|
179 } |
|
180 |
|
181 /*************************************************************************** |
171 /*************************************************************************** |
182 * Exported Methods |
172 * Exported Methods |
183 ***************************************************************************/ |
173 ***************************************************************************/ |
184 |
174 |
185 /** Try to instantiate expression type `that' to given type `to'. |
175 /** |
186 * If a maximal instantiation exists which makes this type |
176 * Instantiate uninferred inference variables (JLS 15.12.2.8). First |
187 * a subtype of type `to', return the instantiated type. |
177 * if the method return type is non-void, we derive constraints from the |
188 * If no instantiation exists, or if several incomparable |
178 * expected type - then we use declared bound well-formedness to derive additional |
189 * best instantiations exist throw a NoInstanceException. |
179 * constraints. If no instantiation exists, or if several incomparable |
190 */ |
180 * best instantiations exist throw a NoInstanceException. |
191 public List<Type> instantiateUninferred(DiagnosticPosition pos, |
181 */ |
192 List<Type> undetvars, |
182 public void instantiateUninferred(DiagnosticPosition pos, |
193 List<Type> tvars, |
183 InferenceContext inferenceContext, |
194 MethodType mtype, |
184 MethodType mtype, |
195 Attr.ResultInfo resultInfo, |
185 Attr.ResultInfo resultInfo, |
196 Warner warn) throws InferenceException { |
186 Warner warn) throws InferenceException { |
197 Type to = resultInfo.pt; |
187 Type to = resultInfo.pt; |
198 if (to.tag == NONE) { |
188 if (to.tag == NONE) { |
199 to = mtype.getReturnType().tag <= VOID ? |
189 to = mtype.getReturnType().tag <= VOID ? |
200 mtype.getReturnType() : syms.objectType; |
190 mtype.getReturnType() : syms.objectType; |
201 } |
191 } |
202 Type qtype1 = types.subst(mtype.getReturnType(), tvars, undetvars); |
192 Type qtype1 = inferenceContext.asFree(mtype.getReturnType(), types); |
203 if (!types.isSubtype(qtype1, |
193 if (!types.isSubtype(qtype1, |
204 qtype1.tag == UNDETVAR ? types.boxedTypeOrType(to) : to)) { |
194 qtype1.tag == UNDETVAR ? types.boxedTypeOrType(to) : to)) { |
205 throw inferenceException |
195 throw inferenceException |
206 .setMessage("infer.no.conforming.instance.exists", |
196 .setMessage("infer.no.conforming.instance.exists", |
207 tvars, mtype.getReturnType(), to); |
197 inferenceContext.restvars(), mtype.getReturnType(), to); |
208 } |
198 } |
209 |
199 |
210 List<Type> insttypes; |
|
211 while (true) { |
200 while (true) { |
212 boolean stuck = true; |
201 boolean stuck = true; |
213 insttypes = List.nil(); |
202 for (Type t : inferenceContext.undetvars) { |
214 for (Type t : undetvars) { |
|
215 UndetVar uv = (UndetVar)t; |
203 UndetVar uv = (UndetVar)t; |
216 if (uv.inst == null && (uv.eq.nonEmpty() || !Type.containsAny(uv.hibounds, tvars))) { |
204 if (uv.inst == null && (uv.eq.nonEmpty() || !inferenceContext.free(uv.hibounds))) { |
217 maximizeInst((UndetVar)t, warn); |
205 maximizeInst((UndetVar)t, warn); |
218 stuck = false; |
206 stuck = false; |
219 } |
207 } |
220 insttypes = insttypes.append(uv.inst == null ? uv.qtype : uv.inst); |
208 } |
221 } |
209 if (inferenceContext.restvars().isEmpty()) { |
222 if (!Type.containsAny(insttypes, tvars)) { |
|
223 //all variables have been instantiated - exit |
210 //all variables have been instantiated - exit |
224 break; |
211 break; |
225 } else if (stuck) { |
212 } else if (stuck) { |
226 //some variables could not be instantiated because of cycles in |
213 //some variables could not be instantiated because of cycles in |
227 //upper bounds - provide a (possibly recursive) default instantiation |
214 //upper bounds - provide a (possibly recursive) default instantiation |
228 insttypes = types.subst(insttypes, |
215 instantiateAsUninferredVars(inferenceContext); |
229 tvars, |
|
230 instantiateAsUninferredVars(undetvars, tvars)); |
|
231 break; |
216 break; |
232 } else { |
217 } else { |
233 //some variables have been instantiated - replace newly instantiated |
218 //some variables have been instantiated - replace newly instantiated |
234 //variables in remaining upper bounds and continue |
219 //variables in remaining upper bounds and continue |
235 for (Type t : undetvars) { |
220 for (Type t : inferenceContext.undetvars) { |
236 UndetVar uv = (UndetVar)t; |
221 UndetVar uv = (UndetVar)t; |
237 uv.hibounds = types.subst(uv.hibounds, tvars, insttypes); |
222 uv.hibounds = inferenceContext.asInstTypes(uv.hibounds, types); |
238 } |
223 } |
239 } |
224 } |
240 } |
225 } |
241 return insttypes; |
|
242 } |
226 } |
243 |
227 |
244 /** |
228 /** |
245 * Infer cyclic inference variables as described in 15.12.2.8. |
229 * Infer cyclic inference variables as described in 15.12.2.8. |
246 */ |
230 */ |
247 private List<Type> instantiateAsUninferredVars(List<Type> undetvars, List<Type> tvars) { |
231 private void instantiateAsUninferredVars(InferenceContext inferenceContext) { |
248 Assert.check(undetvars.length() == tvars.length()); |
|
249 ListBuffer<Type> insttypes = ListBuffer.lb(); |
|
250 ListBuffer<Type> todo = ListBuffer.lb(); |
232 ListBuffer<Type> todo = ListBuffer.lb(); |
251 //step 1 - create fresh tvars |
233 //step 1 - create fresh tvars |
252 for (Type t : undetvars) { |
234 for (Type t : inferenceContext.undetvars) { |
253 UndetVar uv = (UndetVar)t; |
235 UndetVar uv = (UndetVar)t; |
254 if (uv.inst == null) { |
236 if (uv.inst == null) { |
255 TypeSymbol fresh_tvar = new TypeSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner); |
237 TypeSymbol fresh_tvar = new TypeSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner); |
256 fresh_tvar.type = new TypeVar(fresh_tvar, types.makeCompoundType(uv.hibounds), null); |
238 fresh_tvar.type = new TypeVar(fresh_tvar, types.makeCompoundType(uv.hibounds), null); |
257 todo.append(uv); |
239 todo.append(uv); |
258 uv.inst = fresh_tvar.type; |
240 uv.inst = fresh_tvar.type; |
259 } |
241 } |
260 insttypes.append(uv.inst); |
|
261 } |
242 } |
262 //step 2 - replace fresh tvars in their bounds |
243 //step 2 - replace fresh tvars in their bounds |
263 List<Type> formals = tvars; |
244 List<Type> formals = inferenceContext.inferenceVars(); |
264 for (Type t : todo) { |
245 for (Type t : todo) { |
265 UndetVar uv = (UndetVar)t; |
246 UndetVar uv = (UndetVar)t; |
266 TypeVar ct = (TypeVar)uv.inst; |
247 TypeVar ct = (TypeVar)uv.inst; |
267 ct.bound = types.glb(types.subst(types.getBounds(ct), tvars, insttypes.toList())); |
248 ct.bound = types.glb(inferenceContext.asInstTypes(types.getBounds(ct), types)); |
268 if (ct.bound.isErroneous()) { |
249 if (ct.bound.isErroneous()) { |
269 //report inference error if glb fails |
250 //report inference error if glb fails |
270 reportBoundError(uv, BoundErrorKind.BAD_UPPER); |
251 reportBoundError(uv, BoundErrorKind.BAD_UPPER); |
271 } |
252 } |
272 formals = formals.tail; |
253 formals = formals.tail; |
273 } |
254 } |
274 return insttypes.toList(); |
255 } |
275 } |
256 |
276 |
257 /** Instantiate a generic method type by finding instantiations for all its |
277 /** Instantiate method type `mt' by finding instantiations of |
258 * inference variables so that it can be applied to a given argument type list. |
278 * `tvars' so that method can be applied to `argtypes'. |
|
279 */ |
259 */ |
280 public Type instantiateMethod(Env<AttrContext> env, |
260 public Type instantiateMethod(Env<AttrContext> env, |
281 List<Type> tvars, |
261 List<Type> tvars, |
282 MethodType mt, |
262 MethodType mt, |
283 Attr.ResultInfo resultInfo, |
263 Attr.ResultInfo resultInfo, |
285 List<Type> argtypes, |
265 List<Type> argtypes, |
286 boolean allowBoxing, |
266 boolean allowBoxing, |
287 boolean useVarargs, |
267 boolean useVarargs, |
288 Warner warn) throws InferenceException { |
268 Warner warn) throws InferenceException { |
289 //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG |
269 //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG |
290 List<Type> undetvars = makeUndetvars(tvars); |
270 final InferenceContext inferenceContext = new InferenceContext(tvars, types); |
291 |
271 inferenceException.clear(); |
292 List<Type> capturedArgs = |
272 |
293 rs.checkRawArgumentsAcceptable(env, undetvars, argtypes, mt.getParameterTypes(), |
273 try { |
294 allowBoxing, useVarargs, warn, new InferenceCheckHandler(undetvars)); |
274 rs.checkRawArgumentsAcceptable(env, inferenceContext, argtypes, mt.getParameterTypes(), |
295 |
275 allowBoxing, useVarargs, warn, new InferenceCheckHandler(inferenceContext)); |
296 // minimize as yet undetermined type variables |
276 |
297 for (Type t : undetvars) |
277 // minimize as yet undetermined type variables |
298 minimizeInst((UndetVar) t, warn); |
278 for (Type t : inferenceContext.undetvars) { |
299 |
279 minimizeInst((UndetVar)t, warn); |
300 /** Type variables instantiated to bottom */ |
280 } |
301 ListBuffer<Type> restvars = new ListBuffer<Type>(); |
281 |
302 |
282 checkWithinBounds(inferenceContext, warn); |
303 /** Undet vars instantiated to bottom */ |
283 |
304 final ListBuffer<Type> restundet = new ListBuffer<Type>(); |
284 mt = (MethodType)inferenceContext.asInstType(mt, types); |
305 |
285 |
306 /** Instantiated types or TypeVars if under-constrained */ |
286 List<Type> restvars = inferenceContext.restvars(); |
307 ListBuffer<Type> insttypes = new ListBuffer<Type>(); |
287 |
308 |
288 if (!restvars.isEmpty()) { |
309 /** Instantiated types or UndetVars if under-constrained */ |
289 if (resultInfo != null) { |
310 ListBuffer<Type> undettypes = new ListBuffer<Type>(); |
290 instantiateUninferred(env.tree.pos(), inferenceContext, mt, resultInfo, warn); |
311 |
291 checkWithinBounds(inferenceContext, warn); |
312 for (Type t : undetvars) { |
292 mt = (MethodType)inferenceContext.asInstType(mt, types); |
313 UndetVar uv = (UndetVar)t; |
293 if (rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) { |
314 if (uv.inst.tag == BOT) { |
294 log.note(env.tree.pos, "deferred.method.inst", msym, mt, resultInfo.pt); |
315 restvars.append(uv.qtype); |
295 } |
316 restundet.append(uv); |
296 } |
317 insttypes.append(uv.qtype); |
297 } |
318 undettypes.append(uv); |
298 |
319 uv.inst = null; |
299 // return instantiated version of method type |
320 } else { |
300 return mt; |
321 insttypes.append(uv.inst); |
301 } finally { |
322 undettypes.append(uv.inst); |
302 inferenceContext.notifyChange(types); |
323 } |
303 } |
324 } |
|
325 checkWithinBounds(tvars, undetvars, insttypes.toList(), warn); |
|
326 |
|
327 mt = (MethodType)types.subst(mt, tvars, insttypes.toList()); |
|
328 |
|
329 if (!restvars.isEmpty() && resultInfo != null) { |
|
330 List<Type> restInferred = |
|
331 instantiateUninferred(env.tree.pos(), restundet.toList(), restvars.toList(), mt, resultInfo, warn); |
|
332 checkWithinBounds(tvars, undetvars, |
|
333 types.subst(insttypes.toList(), restvars.toList(), restInferred), warn); |
|
334 mt = (MethodType)types.subst(mt, restvars.toList(), restInferred); |
|
335 if (rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) { |
|
336 log.note(env.tree.pos, "deferred.method.inst", msym, mt, resultInfo.pt); |
|
337 } |
|
338 } |
|
339 |
|
340 if (restvars.isEmpty() || resultInfo != null) { |
|
341 // check that actuals conform to inferred formals |
|
342 checkArgumentsAcceptable(env, capturedArgs, mt.getParameterTypes(), allowBoxing, useVarargs, warn); |
|
343 } |
|
344 // return instantiated version of method type |
|
345 return mt; |
|
346 } |
304 } |
347 //where |
305 //where |
348 |
306 |
349 /** inference check handler **/ |
307 /** inference check handler **/ |
350 class InferenceCheckHandler implements Resolve.MethodCheckHandler { |
308 class InferenceCheckHandler implements Resolve.MethodCheckHandler { |
351 |
309 |
352 List<Type> undetvars; |
310 InferenceContext inferenceContext; |
353 |
311 |
354 public InferenceCheckHandler(List<Type> undetvars) { |
312 public InferenceCheckHandler(InferenceContext inferenceContext) { |
355 this.undetvars = undetvars; |
313 this.inferenceContext = inferenceContext; |
356 } |
314 } |
357 |
315 |
358 public InapplicableMethodException arityMismatch() { |
316 public InapplicableMethodException arityMismatch() { |
359 return inferenceException.setMessage("infer.arg.length.mismatch", inferenceVars(undetvars)); |
317 return inferenceException.setMessage("infer.arg.length.mismatch", inferenceContext.inferenceVars()); |
360 } |
318 } |
361 public InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic details) { |
319 public InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic details) { |
362 String key = varargs ? |
320 String key = varargs ? |
363 "infer.varargs.argument.mismatch" : |
321 "infer.varargs.argument.mismatch" : |
364 "infer.no.conforming.assignment.exists"; |
322 "infer.no.conforming.assignment.exists"; |
365 return inferenceException.setMessage(key, |
323 return inferenceException.setMessage(key, |
366 inferenceVars(undetvars), details); |
324 inferenceContext.inferenceVars(), details); |
367 } |
325 } |
368 public InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected) { |
326 public InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected) { |
369 return inferenceException.setMessage("inaccessible.varargs.type", |
327 return inferenceException.setMessage("inaccessible.varargs.type", |
370 expected, Kinds.kindName(location), location); |
328 expected, Kinds.kindName(location), location); |
371 } |
329 } |
372 } |
330 } |
373 |
331 |
374 private void checkArgumentsAcceptable(Env<AttrContext> env, List<Type> actuals, List<Type> formals, |
|
375 boolean allowBoxing, boolean useVarargs, Warner warn) { |
|
376 try { |
|
377 rs.checkRawArgumentsAcceptable(env, actuals, formals, |
|
378 allowBoxing, useVarargs, warn); |
|
379 } |
|
380 catch (InapplicableMethodException ex) { |
|
381 // inferred method is not applicable |
|
382 throw inferenceException.setMessage(ex.getDiagnostic()); |
|
383 } |
|
384 } |
|
385 |
|
386 /** check that type parameters are within their bounds. |
332 /** check that type parameters are within their bounds. |
387 */ |
333 */ |
388 void checkWithinBounds(List<Type> tvars, |
334 void checkWithinBounds(InferenceContext inferenceContext, |
389 List<Type> undetvars, |
|
390 List<Type> arguments, |
|
391 Warner warn) |
335 Warner warn) |
392 throws InferenceException { |
336 throws InferenceException { |
393 List<Type> args = arguments; |
337 List<Type> tvars = inferenceContext.inferenceVars(); |
394 for (Type t : undetvars) { |
338 for (Type t : inferenceContext.undetvars) { |
395 UndetVar uv = (UndetVar)t; |
339 UndetVar uv = (UndetVar)t; |
396 uv.hibounds = types.subst(uv.hibounds, tvars, arguments); |
340 uv.hibounds = inferenceContext.asInstTypes(uv.hibounds, types); |
397 uv.lobounds = types.subst(uv.lobounds, tvars, arguments); |
341 uv.lobounds = inferenceContext.asInstTypes(uv.lobounds, types); |
398 uv.eq = types.subst(uv.eq, tvars, arguments); |
342 uv.eq = inferenceContext.asInstTypes(uv.eq, types); |
399 checkCompatibleUpperBounds(uv, tvars); |
343 checkCompatibleUpperBounds(uv, inferenceContext.inferenceVars()); |
400 if (args.head.tag != TYPEVAR || !args.head.containsAny(tvars)) { |
344 if (!inferenceContext.restvars().contains(tvars.head)) { |
401 Type inst = args.head; |
345 Type inst = inferenceContext.asInstType(t, types); |
402 for (Type u : uv.hibounds) { |
346 for (Type u : uv.hibounds) { |
403 if (!types.isSubtypeUnchecked(inst, types.subst(u, tvars, undetvars), warn)) { |
347 if (!types.isSubtypeUnchecked(inst, inferenceContext.asFree(u, types), warn)) { |
404 reportBoundError(uv, BoundErrorKind.UPPER); |
348 reportBoundError(uv, BoundErrorKind.UPPER); |
405 } |
349 } |
406 } |
350 } |
407 for (Type l : uv.lobounds) { |
351 for (Type l : uv.lobounds) { |
408 if (!types.isSubtypeUnchecked(types.subst(l, tvars, undetvars), inst, warn)) { |
352 if (!types.isSubtypeUnchecked(inferenceContext.asFree(l, types), inst, warn)) { |
409 reportBoundError(uv, BoundErrorKind.LOWER); |
353 reportBoundError(uv, BoundErrorKind.LOWER); |
410 } |
354 } |
411 } |
355 } |
412 for (Type e : uv.eq) { |
356 for (Type e : uv.eq) { |
413 if (!types.isSameType(inst, types.subst(e, tvars, undetvars))) { |
357 if (!types.isSameType(inst, inferenceContext.asFree(e, types))) { |
414 reportBoundError(uv, BoundErrorKind.EQ); |
358 reportBoundError(uv, BoundErrorKind.EQ); |
415 } |
359 } |
416 } |
360 } |
417 } |
361 } |
418 args = args.tail; |
362 tvars = tvars.tail; |
419 } |
363 } |
420 } |
364 } |
421 |
365 |
422 void checkCompatibleUpperBounds(UndetVar uv, List<Type> tvars) { |
366 void checkCompatibleUpperBounds(UndetVar uv, List<Type> tvars) { |
423 // VGJ: sort of inlined maximizeInst() below. Adding |
367 // VGJ: sort of inlined maximizeInst() below. Adding |
424 // bounds can cause lobounds that are above hibounds. |
368 // bounds can cause lobounds that are above hibounds. |
425 ListBuffer<Type> hiboundsNoVars = ListBuffer.lb(); |
369 ListBuffer<Type> hiboundsNoVars = ListBuffer.lb(); |
426 for (Type t : Type.filter(uv.hibounds, errorFilter)) { |
370 for (Type t : Type.filter(uv.hibounds, boundFilter)) { |
427 if (!t.containsAny(tvars)) { |
371 if (!t.containsAny(tvars)) { |
428 hiboundsNoVars.append(t); |
372 hiboundsNoVars.append(t); |
429 } |
373 } |
430 } |
374 } |
431 List<Type> hibounds = hiboundsNoVars.toList(); |
375 List<Type> hibounds = hiboundsNoVars.toList(); |
529 // infer as java.lang.Void for now |
473 // infer as java.lang.Void for now |
530 t = types.boxedClass(syms.voidType).type; |
474 t = types.boxedClass(syms.voidType).type; |
531 return t; |
475 return t; |
532 } |
476 } |
533 }; |
477 }; |
534 } |
478 |
|
479 /** |
|
480 * Mapping that turns inference variables into undet vars |
|
481 * (used by inference context) |
|
482 */ |
|
483 static Mapping fromTypeVarFun = new Mapping("fromTypeVarFun") { |
|
484 public Type apply(Type t) { |
|
485 if (t.tag == TYPEVAR) return new UndetVar(t); |
|
486 else return t.map(this); |
|
487 } |
|
488 }; |
|
489 |
|
490 /** |
|
491 * An inference context keeps track of the set of variables that are free |
|
492 * in the current context. It provides utility methods for opening/closing |
|
493 * types to their corresponding free/closed forms. It also provide hooks for |
|
494 * attaching deferred post-inference action (see PendingCheck). Finally, |
|
495 * it can be used as an entry point for performing upper/lower bound inference |
|
496 * (see InferenceKind). |
|
497 */ |
|
498 static class InferenceContext { |
|
499 |
|
500 /** |
|
501 * Single-method-interface for defining inference callbacks. Certain actions |
|
502 * (i.e. subtyping checks) might need to be redone after all inference variables |
|
503 * have been fixed. |
|
504 */ |
|
505 interface FreeTypeListener { |
|
506 void typesInferred(InferenceContext inferenceContext); |
|
507 } |
|
508 |
|
509 /** list of inference vars as undet vars */ |
|
510 List<Type> undetvars; |
|
511 |
|
512 /** list of inference vars in this context */ |
|
513 List<Type> inferencevars; |
|
514 |
|
515 java.util.Map<FreeTypeListener, List<Type>> freeTypeListeners = |
|
516 new java.util.HashMap<FreeTypeListener, List<Type>>(); |
|
517 |
|
518 List<FreeTypeListener> freetypeListeners = List.nil(); |
|
519 |
|
520 public InferenceContext(List<Type> inferencevars, Types types) { |
|
521 this.undetvars = Type.map(inferencevars, fromTypeVarFun); |
|
522 this.inferencevars = inferencevars; |
|
523 for (Type t : this.undetvars) { |
|
524 UndetVar uv = (UndetVar)t; |
|
525 uv.hibounds = types.getBounds((TypeVar)uv.qtype); |
|
526 } |
|
527 } |
|
528 |
|
529 /** |
|
530 * returns the list of free variables (as type-variables) in this |
|
531 * inference context |
|
532 */ |
|
533 List<Type> inferenceVars() { |
|
534 return inferencevars; |
|
535 } |
|
536 |
|
537 /** |
|
538 * returns the list of uninstantiated variables (as type-variables) in this |
|
539 * inference context (usually called after instantiate()) |
|
540 */ |
|
541 List<Type> restvars() { |
|
542 List<Type> undetvars = this.undetvars; |
|
543 ListBuffer<Type> restvars = ListBuffer.lb(); |
|
544 for (Type t : instTypes()) { |
|
545 UndetVar uv = (UndetVar)undetvars.head; |
|
546 if (uv.qtype == t) { |
|
547 restvars.append(t); |
|
548 } |
|
549 undetvars = undetvars.tail; |
|
550 } |
|
551 return restvars.toList(); |
|
552 } |
|
553 |
|
554 /** |
|
555 * is this type free? |
|
556 */ |
|
557 final boolean free(Type t) { |
|
558 return t.containsAny(inferencevars); |
|
559 } |
|
560 |
|
561 final boolean free(List<Type> ts) { |
|
562 for (Type t : ts) { |
|
563 if (free(t)) return true; |
|
564 } |
|
565 return false; |
|
566 } |
|
567 |
|
568 /** |
|
569 * Returns a list of free variables in a given type |
|
570 */ |
|
571 final List<Type> freeVarsIn(Type t) { |
|
572 ListBuffer<Type> buf = ListBuffer.lb(); |
|
573 for (Type iv : inferenceVars()) { |
|
574 if (t.contains(iv)) { |
|
575 buf.add(iv); |
|
576 } |
|
577 } |
|
578 return buf.toList(); |
|
579 } |
|
580 |
|
581 final List<Type> freeVarsIn(List<Type> ts) { |
|
582 ListBuffer<Type> buf = ListBuffer.lb(); |
|
583 for (Type t : ts) { |
|
584 buf.appendList(freeVarsIn(t)); |
|
585 } |
|
586 ListBuffer<Type> buf2 = ListBuffer.lb(); |
|
587 for (Type t : buf) { |
|
588 if (!buf2.contains(t)) { |
|
589 buf2.add(t); |
|
590 } |
|
591 } |
|
592 return buf2.toList(); |
|
593 } |
|
594 |
|
595 /** |
|
596 * Replace all free variables in a given type with corresponding |
|
597 * undet vars (used ahead of subtyping/compatibility checks to allow propagation |
|
598 * of inference constraints). |
|
599 */ |
|
600 final Type asFree(Type t, Types types) { |
|
601 return types.subst(t, inferencevars, undetvars); |
|
602 } |
|
603 |
|
604 final List<Type> asFree(List<Type> ts, Types types) { |
|
605 ListBuffer<Type> buf = ListBuffer.lb(); |
|
606 for (Type t : ts) { |
|
607 buf.append(asFree(t, types)); |
|
608 } |
|
609 return buf.toList(); |
|
610 } |
|
611 |
|
612 List<Type> instTypes() { |
|
613 ListBuffer<Type> buf = ListBuffer.lb(); |
|
614 for (Type t : undetvars) { |
|
615 UndetVar uv = (UndetVar)t; |
|
616 buf.append(uv.inst != null ? uv.inst : uv.qtype); |
|
617 } |
|
618 return buf.toList(); |
|
619 } |
|
620 |
|
621 /** |
|
622 * Replace all free variables in a given type with corresponding |
|
623 * instantiated types - if one or more free variable has not been |
|
624 * fully instantiated, it will still be available in the resulting type. |
|
625 */ |
|
626 Type asInstType(Type t, Types types) { |
|
627 return types.subst(t, inferencevars, instTypes()); |
|
628 } |
|
629 |
|
630 List<Type> asInstTypes(List<Type> ts, Types types) { |
|
631 ListBuffer<Type> buf = ListBuffer.lb(); |
|
632 for (Type t : ts) { |
|
633 buf.append(asInstType(t, types)); |
|
634 } |
|
635 return buf.toList(); |
|
636 } |
|
637 |
|
638 /** |
|
639 * Add custom hook for performing post-inference action |
|
640 */ |
|
641 void addFreeTypeListener(List<Type> types, FreeTypeListener ftl) { |
|
642 freeTypeListeners.put(ftl, freeVarsIn(types)); |
|
643 } |
|
644 |
|
645 /** |
|
646 * Mark the inference context as complete and trigger evaluation |
|
647 * of all deferred checks. |
|
648 */ |
|
649 void notifyChange(Types types) { |
|
650 InferenceException thrownEx = null; |
|
651 for (Map.Entry<FreeTypeListener, List<Type>> entry : |
|
652 new HashMap<FreeTypeListener, List<Type>>(freeTypeListeners).entrySet()) { |
|
653 if (!Type.containsAny(entry.getValue(), restvars())) { |
|
654 try { |
|
655 entry.getKey().typesInferred(this); |
|
656 freeTypeListeners.remove(entry.getKey()); |
|
657 } catch (InferenceException ex) { |
|
658 if (thrownEx == null) { |
|
659 thrownEx = ex; |
|
660 } |
|
661 } |
|
662 } |
|
663 } |
|
664 //inference exception multiplexing - present any inference exception |
|
665 //thrown when processing listeners as a single one |
|
666 if (thrownEx != null) { |
|
667 throw thrownEx; |
|
668 } |
|
669 } |
|
670 } |
|
671 |
|
672 final InferenceContext emptyContext = new InferenceContext(List.<Type>nil(), types); |
|
673 } |