140 // <editor-fold defaultstate="collapsed" desc="Inference routines"> |
140 // <editor-fold defaultstate="collapsed" desc="Inference routines"> |
141 /** |
141 /** |
142 * Main inference entry point - instantiate a generic method type |
142 * Main inference entry point - instantiate a generic method type |
143 * using given argument types and (possibly) an expected target-type. |
143 * using given argument types and (possibly) an expected target-type. |
144 */ |
144 */ |
145 public Type instantiateMethod(Env<AttrContext> env, |
145 Type instantiateMethod( Env<AttrContext> env, |
146 List<Type> tvars, |
146 List<Type> tvars, |
147 MethodType mt, |
147 MethodType mt, |
148 Attr.ResultInfo resultInfo, |
148 Attr.ResultInfo resultInfo, |
149 Symbol msym, |
149 MethodSymbol msym, |
150 List<Type> argtypes, |
150 List<Type> argtypes, |
151 boolean allowBoxing, |
151 boolean allowBoxing, |
152 boolean useVarargs, |
152 boolean useVarargs, |
153 Resolve.MethodResolutionContext resolveContext, |
153 Resolve.MethodResolutionContext resolveContext, |
154 Warner warn) throws InferenceException { |
154 Warner warn) throws InferenceException { |
155 //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG |
155 //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG |
156 final InferenceContext inferenceContext = new InferenceContext(tvars); |
156 final InferenceContext inferenceContext = new InferenceContext(tvars); //B0 |
157 inferenceException.clear(); |
157 inferenceException.clear(); |
158 try { |
158 try { |
159 DeferredAttr.DeferredAttrContext deferredAttrContext = |
159 DeferredAttr.DeferredAttrContext deferredAttrContext = |
160 resolveContext.deferredAttrContext(msym, inferenceContext, resultInfo, warn); |
160 resolveContext.deferredAttrContext(msym, inferenceContext, resultInfo, warn); |
161 |
161 |
162 resolveContext.methodCheck.argumentsAcceptable(env, deferredAttrContext, |
162 resolveContext.methodCheck.argumentsAcceptable(env, deferredAttrContext, //B2 |
163 argtypes, mt.getParameterTypes(), warn); |
163 argtypes, mt.getParameterTypes(), warn); |
164 |
164 |
165 if (allowGraphInference && |
165 if (allowGraphInference && |
166 resultInfo != null && |
166 resultInfo != null && |
167 !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) { |
167 !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) { |
168 //inject return constraints earlier |
168 //inject return constraints earlier |
169 checkWithinBounds(inferenceContext, warn); //propagation |
169 checkWithinBounds(inferenceContext, warn); //propagation |
170 Type newRestype = generateReturnConstraints(resultInfo, mt, inferenceContext); |
170 Type newRestype = generateReturnConstraints(env.tree, resultInfo, //B3 |
|
171 mt, inferenceContext); |
171 mt = (MethodType)types.createMethodTypeWithReturn(mt, newRestype); |
172 mt = (MethodType)types.createMethodTypeWithReturn(mt, newRestype); |
172 //propagate outwards if needed |
173 //propagate outwards if needed |
173 if (resultInfo.checkContext.inferenceContext().free(resultInfo.pt)) { |
174 if (resultInfo.checkContext.inferenceContext().free(resultInfo.pt)) { |
174 //propagate inference context outwards and exit |
175 //propagate inference context outwards and exit |
175 inferenceContext.dupTo(resultInfo.checkContext.inferenceContext()); |
176 inferenceContext.dupTo(resultInfo.checkContext.inferenceContext()); |
208 if (resultInfo != null || !allowGraphInference) { |
209 if (resultInfo != null || !allowGraphInference) { |
209 inferenceContext.notifyChange(); |
210 inferenceContext.notifyChange(); |
210 } else { |
211 } else { |
211 inferenceContext.notifyChange(inferenceContext.boundedVars()); |
212 inferenceContext.notifyChange(inferenceContext.boundedVars()); |
212 } |
213 } |
|
214 if (resultInfo == null) { |
|
215 /* if the is no result info then we can clear the capture types |
|
216 * cache without affecting any result info check |
|
217 */ |
|
218 inferenceContext.captureTypeCache.clear(); |
|
219 } |
213 } |
220 } |
214 } |
221 } |
215 |
222 |
216 /** |
223 /** |
217 * Generate constraints from the generic method's return type. If the method |
224 * Generate constraints from the generic method's return type. If the method |
218 * call occurs in a context where a type T is expected, use the expected |
225 * call occurs in a context where a type T is expected, use the expected |
219 * type to derive more constraints on the generic method inference variables. |
226 * type to derive more constraints on the generic method inference variables. |
220 */ |
227 */ |
221 Type generateReturnConstraints(Attr.ResultInfo resultInfo, |
228 Type generateReturnConstraints(JCTree tree, Attr.ResultInfo resultInfo, |
222 MethodType mt, InferenceContext inferenceContext) { |
229 MethodType mt, InferenceContext inferenceContext) { |
223 InferenceContext rsInfoInfContext = resultInfo.checkContext.inferenceContext(); |
230 InferenceContext rsInfoInfContext = resultInfo.checkContext.inferenceContext(); |
224 Type from = mt.getReturnType(); |
231 Type from = mt.getReturnType(); |
225 if (mt.getReturnType().containsAny(inferenceContext.inferencevars) && |
232 if (mt.getReturnType().containsAny(inferenceContext.inferencevars) && |
226 rsInfoInfContext != emptyContext) { |
233 rsInfoInfContext != emptyContext) { |
230 if (t.hasTag(TYPEVAR) && ((TypeVar)t).isCaptured()) { |
237 if (t.hasTag(TYPEVAR) && ((TypeVar)t).isCaptured()) { |
231 inferenceContext.addVar((TypeVar)t); |
238 inferenceContext.addVar((TypeVar)t); |
232 } |
239 } |
233 } |
240 } |
234 } |
241 } |
235 Type qtype1 = inferenceContext.asUndetVar(from); |
242 Type qtype = inferenceContext.asUndetVar(from); |
236 Type to = returnConstraintTarget(qtype1, resultInfo.pt); |
243 Type to = resultInfo.pt; |
|
244 |
|
245 if (qtype.hasTag(VOID)) { |
|
246 to = syms.voidType; |
|
247 } else if (to.hasTag(NONE)) { |
|
248 to = from.isPrimitive() ? from : syms.objectType; |
|
249 } else if (qtype.hasTag(UNDETVAR)) { |
|
250 if (resultInfo.pt.isReference()) { |
|
251 to = generateReturnConstraintsUndetVarToReference( |
|
252 tree, (UndetVar)qtype, to, resultInfo, inferenceContext); |
|
253 } else { |
|
254 if (to.isPrimitive()) { |
|
255 to = generateReturnConstraintsPrimitive(tree, (UndetVar)qtype, to, |
|
256 resultInfo, inferenceContext); |
|
257 } |
|
258 } |
|
259 } |
237 Assert.check(allowGraphInference || !rsInfoInfContext.free(to), |
260 Assert.check(allowGraphInference || !rsInfoInfContext.free(to), |
238 "legacy inference engine cannot handle constraints on both sides of a subtyping assertion"); |
261 "legacy inference engine cannot handle constraints on both sides of a subtyping assertion"); |
239 //we need to skip capture? |
262 //we need to skip capture? |
240 Warner retWarn = new Warner(); |
263 Warner retWarn = new Warner(); |
241 if (!resultInfo.checkContext.compatible(qtype1, rsInfoInfContext.asUndetVar(to), retWarn) || |
264 if (!resultInfo.checkContext.compatible(qtype, rsInfoInfContext.asUndetVar(to), retWarn) || |
242 //unchecked conversion is not allowed in source 7 mode |
265 //unchecked conversion is not allowed in source 7 mode |
243 (!allowGraphInference && retWarn.hasLint(Lint.LintCategory.UNCHECKED))) { |
266 (!allowGraphInference && retWarn.hasLint(Lint.LintCategory.UNCHECKED))) { |
244 throw inferenceException |
267 throw inferenceException |
245 .setMessage("infer.no.conforming.instance.exists", |
268 .setMessage("infer.no.conforming.instance.exists", |
246 inferenceContext.restvars(), mt.getReturnType(), to); |
269 inferenceContext.restvars(), mt.getReturnType(), to); |
247 } |
270 } |
248 return from; |
271 return from; |
249 } |
272 } |
250 |
273 |
251 Type returnConstraintTarget(Type from, Type to) { |
274 private Type generateReturnConstraintsPrimitive(JCTree tree, UndetVar from, |
252 if (from.hasTag(VOID)) { |
275 Type to, Attr.ResultInfo resultInfo, InferenceContext inferenceContext) { |
253 return syms.voidType; |
276 if (!allowGraphInference) { |
254 } else if (to.hasTag(NONE)) { |
277 //if legacy, just return boxed type |
255 return from.isPrimitive() ? from : syms.objectType; |
|
256 } else if (from.hasTag(UNDETVAR) && to.isPrimitive()) { |
|
257 if (!allowGraphInference) { |
|
258 //if legacy, just return boxed type |
|
259 return types.boxedClass(to).type; |
|
260 } |
|
261 //if graph inference we need to skip conflicting boxed bounds... |
|
262 UndetVar uv = (UndetVar)from; |
|
263 for (Type t : uv.getBounds(InferenceBound.EQ, InferenceBound.LOWER)) { |
|
264 Type boundAsPrimitive = types.unboxedType(t); |
|
265 if (boundAsPrimitive == null) continue; |
|
266 if (types.isConvertible(boundAsPrimitive, to)) { |
|
267 //effectively skip return-type constraint generation (compatibility) |
|
268 return syms.objectType; |
|
269 } |
|
270 } |
|
271 return types.boxedClass(to).type; |
278 return types.boxedClass(to).type; |
272 } else { |
279 } |
273 return to; |
280 //if graph inference we need to skip conflicting boxed bounds... |
274 } |
281 for (Type t : from.getBounds(InferenceBound.EQ, InferenceBound.UPPER, |
|
282 InferenceBound.LOWER)) { |
|
283 Type boundAsPrimitive = types.unboxedType(t); |
|
284 if (boundAsPrimitive == null || boundAsPrimitive.hasTag(NONE)) { |
|
285 continue; |
|
286 } |
|
287 return generateReferenceToTargetConstraint(tree, from, to, |
|
288 resultInfo, inferenceContext); |
|
289 } |
|
290 return types.boxedClass(to).type; |
|
291 } |
|
292 |
|
293 private Type generateReturnConstraintsUndetVarToReference(JCTree tree, |
|
294 UndetVar from, Type to, Attr.ResultInfo resultInfo, |
|
295 InferenceContext inferenceContext) { |
|
296 Type captureOfTo = types.capture(to); |
|
297 /* T is a reference type, but is not a wildcard-parameterized type, and either |
|
298 */ |
|
299 if (captureOfTo == to) { //not a wildcard parameterized type |
|
300 /* i) B2 contains a bound of one of the forms alpha = S or S <: alpha, |
|
301 * where S is a wildcard-parameterized type, or |
|
302 */ |
|
303 for (Type t : from.getBounds(InferenceBound.EQ, InferenceBound.LOWER)) { |
|
304 Type captureOfBound = types.capture(t); |
|
305 if (captureOfBound != t) { |
|
306 return generateReferenceToTargetConstraint(tree, from, to, |
|
307 resultInfo, inferenceContext); |
|
308 } |
|
309 } |
|
310 |
|
311 /* ii) B2 contains two bounds of the forms S1 <: alpha and S2 <: alpha, |
|
312 * where S1 and S2 have supertypes that are two different |
|
313 * parameterizations of the same generic class or interface. |
|
314 */ |
|
315 for (Type aLowerBound : from.getBounds(InferenceBound.LOWER)) { |
|
316 for (Type anotherLowerBound : from.getBounds(InferenceBound.LOWER)) { |
|
317 if (aLowerBound != anotherLowerBound && |
|
318 commonSuperWithDiffParameterization(aLowerBound, anotherLowerBound)) { |
|
319 /* self comment check if any lower bound may be and undetVar, |
|
320 * in that case the result of this call may be a false positive. |
|
321 * Should this be restricted to non free types? |
|
322 */ |
|
323 return generateReferenceToTargetConstraint(tree, from, to, |
|
324 resultInfo, inferenceContext); |
|
325 } |
|
326 } |
|
327 } |
|
328 } |
|
329 |
|
330 /* T is a parameterization of a generic class or interface, G, |
|
331 * and B2 contains a bound of one of the forms alpha = S or S <: alpha, |
|
332 * where there exists no type of the form G<...> that is a |
|
333 * supertype of S, but the raw type G is a supertype of S |
|
334 */ |
|
335 if (to.isParameterized()) { |
|
336 for (Type t : from.getBounds(InferenceBound.EQ, InferenceBound.LOWER)) { |
|
337 Type sup = types.asSuper(t, to.tsym); |
|
338 if (sup != null && sup.isRaw()) { |
|
339 return generateReferenceToTargetConstraint(tree, from, to, |
|
340 resultInfo, inferenceContext); |
|
341 } |
|
342 } |
|
343 } |
|
344 return to; |
|
345 } |
|
346 |
|
347 private boolean commonSuperWithDiffParameterization(Type t, Type s) { |
|
348 Pair<Type, Type> supers = getParameterizedSupers(t, s); |
|
349 return (supers != null && !types.isSameType(supers.fst, supers.snd)); |
|
350 } |
|
351 |
|
352 private Type generateReferenceToTargetConstraint(JCTree tree, UndetVar from, |
|
353 Type to, Attr.ResultInfo resultInfo, |
|
354 InferenceContext inferenceContext) { |
|
355 inferenceContext.solve(List.of(from.qtype), new Warner()); |
|
356 Type capturedType = resultInfo.checkContext.inferenceContext() |
|
357 .cachedCapture(tree, from.inst, false); |
|
358 if (types.isConvertible(capturedType, |
|
359 resultInfo.checkContext.inferenceContext().asUndetVar(to))) { |
|
360 //effectively skip additional return-type constraint generation (compatibility) |
|
361 return syms.objectType; |
|
362 } |
|
363 return to; |
275 } |
364 } |
276 |
365 |
277 /** |
366 /** |
278 * Infer cyclic inference variables as described in 15.12.2.8. |
367 * Infer cyclic inference variables as described in 15.12.2.8. |
279 */ |
368 */ |