src/share/classes/com/sun/tools/javac/comp/Infer.java

changeset 2382
14979dd5e034
parent 2369
77352397867a
child 2384
327122b01a9e
equal deleted inserted replaced
2381:d02e9b7444fe 2382:14979dd5e034
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());
191 192
192 if (!allowGraphInference && 193 if (!allowGraphInference &&
193 inferenceContext.restvars().nonEmpty() && 194 inferenceContext.restvars().nonEmpty() &&
194 resultInfo != null && 195 resultInfo != null &&
195 !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) { 196 !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) {
196 generateReturnConstraints(resultInfo, mt, inferenceContext); 197 generateReturnConstraints(env.tree, resultInfo, mt, inferenceContext);
197 inferenceContext.solveLegacy(false, warn, LegacyInferenceSteps.EQ_UPPER.steps); //maximizeInst 198 inferenceContext.solveLegacy(false, warn, LegacyInferenceSteps.EQ_UPPER.steps); //maximizeInst
198 mt = (MethodType)inferenceContext.asInstType(mt); 199 mt = (MethodType)inferenceContext.asInstType(mt);
199 } 200 }
200 201
201 if (resultInfo != null && rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) { 202 if (resultInfo != null && rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) {
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 */
2080 2169
2081 /** 2170 /**
2082 * Copy variable in this inference context to the given context 2171 * Copy variable in this inference context to the given context
2083 */ 2172 */
2084 void dupTo(final InferenceContext that) { 2173 void dupTo(final InferenceContext that) {
2085 that.inferencevars = that.inferencevars.appendList(inferencevars); 2174 that.inferencevars = that.inferencevars.appendList(
2086 that.undetvars = that.undetvars.appendList(undetvars); 2175 inferencevars.diff(that.inferencevars));
2176 that.undetvars = that.undetvars.appendList(
2177 undetvars.diff(that.undetvars));
2087 //set up listeners to notify original inference contexts as 2178 //set up listeners to notify original inference contexts as
2088 //propagated vars are inferred in new context 2179 //propagated vars are inferred in new context
2089 for (Type t : inferencevars) { 2180 for (Type t : inferencevars) {
2090 that.freeTypeListeners.put(new FreeTypeListener() { 2181 that.freeTypeListeners.put(new FreeTypeListener() {
2091 public void typesInferred(InferenceContext inferenceContext) { 2182 public void typesInferred(InferenceContext inferenceContext) {
2200 @Override 2291 @Override
2201 public String toString() { 2292 public String toString() {
2202 return "Inference vars: " + inferencevars + '\n' + 2293 return "Inference vars: " + inferencevars + '\n' +
2203 "Undet vars: " + undetvars; 2294 "Undet vars: " + undetvars;
2204 } 2295 }
2296
2297 /* Method Types.capture() generates a new type every time it's applied
2298 * to a wildcard parameterized type. This is intended functionality but
2299 * there are some cases when what you need is not to generate a new
2300 * captured type but to check that a previously generated captured type
2301 * is correct. There are cases when caching a captured type for later
2302 * reuse is sound. In general two captures from the same AST are equal.
2303 * This is why the tree is used as the key of the map below. This map
2304 * stores a Type per AST.
2305 */
2306 Map<JCTree, Type> captureTypeCache = new HashMap<>();
2307
2308 Type cachedCapture(JCTree tree, Type t, boolean readOnly) {
2309 Type captured = captureTypeCache.get(tree);
2310 if (captured != null) {
2311 return captured;
2312 }
2313
2314 Type result = types.capture(t);
2315 if (result != t && !readOnly) { // then t is a wildcard parameterized type
2316 captureTypeCache.put(tree, result);
2317 }
2318 return result;
2319 }
2205 } 2320 }
2206 2321
2207 final InferenceContext emptyContext = new InferenceContext(List.<Type>nil()); 2322 final InferenceContext emptyContext = new InferenceContext(List.<Type>nil());
2208 // </editor-fold> 2323 // </editor-fold>
2209 } 2324 }

mercurial