184 */
185 public Type skipTypeVars(Type site, boolean capture) {
186 while (site.hasTag(TYPEVAR)) {
187 site = site.getUpperBound();
188 }
189 return capture ? capture(site) : site;
190 }
191 // </editor-fold>
192
193 // <editor-fold defaultstate="collapsed" desc="projections">
194
195 /**
196 * A projection kind. See {@link TypeProjection}
197 */
198 enum ProjectionKind {
199 UPWARDS() {
200 @Override
201 ProjectionKind complement() {
202 return DOWNWARDS;
203 }
204 },
205 DOWNWARDS() {
206 @Override
207 ProjectionKind complement() {
208 return UPWARDS;
209 }
210 };
211
212 abstract ProjectionKind complement();
213 }
214
215 /**
216 * This visitor performs upwards and downwards projections on types.
217 *
218 * A projection is defined as a function that takes a type T, a set of type variables V and that
219 * produces another type S.
220 *
221 * An upwards projection maps a type T into a type S such that (i) T has no variables in V,
222 * and (ii) S is an upper bound of T.
223 *
224 * A downwards projection maps a type T into a type S such that (i) T has no variables in V,
225 * and (ii) S is a lower bound of T.
226 *
227 * Note that projections are only allowed to touch variables in V. Therefore, it is possible for
228 * a projection to leave its input type unchanged if it does not contain any variables in V.
229 *
230 * Moreover, note that while an upwards projection is always defined (every type as an upper bound),
231 * a downwards projection is not always defined.
232 *
233 * Examples:
234 *
235 * {@code upwards(List<#CAP1>, [#CAP1]) = List<? extends String>, where #CAP1 <: String }
236 * {@code downwards(List<#CAP2>, [#CAP2]) = List<? super String>, where #CAP2 :> String }
237 * {@code upwards(List<#CAP1>, [#CAP2]) = List<#CAP1> }
238 * {@code downwards(List<#CAP1>, [#CAP1]) = not defined }
239 */
240 class TypeProjection extends TypeMapping<ProjectionKind> {
241
242 List<Type> vars;
243 Set<Type> seen = new HashSet<>();
244
245 public TypeProjection(List<Type> vars) {
246 this.vars = vars;
247 }
248
249 @Override
250 public Type visitClassType(ClassType t, ProjectionKind pkind) {
251 if (t.isCompound()) {
252 List<Type> components = directSupertypes(t);
253 List<Type> components1 = components.map(c -> c.map(this, pkind));
254 if (components == components1) return t;
255 else return makeIntersectionType(components1);
256 } else {
257 Type outer = t.getEnclosingType();
258 Type outer1 = visit(outer, pkind);
259 List<Type> typarams = t.getTypeArguments();
260 List<Type> formals = t.tsym.type.getTypeArguments();
261 ListBuffer<Type> typarams1 = new ListBuffer<>();
262 boolean changed = false;
263 for (Type actual : typarams) {
264 Type t2 = mapTypeArgument(t, formals.head.getUpperBound(), actual, pkind);
265 if (t2.hasTag(BOT)) {
266 //not defined
267 return syms.botType;
268 }
269 typarams1.add(t2);
270 changed |= actual != t2;
271 formals = formals.tail;
272 }
273 if (outer1 == outer && !changed) return t;
274 else return new ClassType(outer1, typarams1.toList(), t.tsym, t.getMetadata()) {
275 @Override
290 //undefined
291 return syms.botType;
292 } else {
293 return new ArrayType(elemtype1, t.tsym, t.metadata) {
294 @Override
295 protected boolean needsStripping() {
296 return true;
297 }
298 };
299 }
300 }
301
302 @Override
303 public Type visitTypeVar(TypeVar t, ProjectionKind pkind) {
304 if (vars.contains(t)) {
305 if (seen.add(t)) {
306 try {
307 final Type bound;
308 switch (pkind) {
309 case UPWARDS:
310 bound = t.getUpperBound();
311 break;
312 case DOWNWARDS:
313 bound = (t.getLowerBound() == null) ?
314 syms.botType :
315 t.getLowerBound();
316 break;
317 default:
318 Assert.error();
319 return null;
320 }
321 return bound.map(this, pkind);
322 } finally {
323 seen.remove(t);
324 }
325 } else {
326 //cycle
327 return pkind == ProjectionKind.UPWARDS ?
328 syms.objectType : syms.botType;
329 }
330 } else {
331 return t;
332 }
333 }
334
335 private Type mapTypeArgument(Type site, Type declaredBound, Type t, ProjectionKind pkind) {
336 return t.containsAny(vars) ?
337 t.map(new TypeArgumentProjection(site, declaredBound), pkind) :
338 t;
339 }
340
341 class TypeArgumentProjection extends TypeMapping<ProjectionKind> {
342
343 Type site;
344 Type declaredBound;
345
346 TypeArgumentProjection(Type site, Type declaredBound) {
347 this.site = site;
348 this.declaredBound = declaredBound;
349 }
350
351 @Override
352 public Type visitType(Type t, ProjectionKind pkind) {
353 //type argument is some type containing restricted vars
354 if (pkind == ProjectionKind.DOWNWARDS) {
355 //not defined
356 return syms.botType;
357 }
358 Type upper = t.map(TypeProjection.this, ProjectionKind.UPWARDS);
359 Type lower = t.map(TypeProjection.this, ProjectionKind.DOWNWARDS);
360 List<Type> formals = site.tsym.type.getTypeArguments();
361 BoundKind bk;
362 Type bound;
363 if (!isSameType(upper, syms.objectType) &&
364 (declaredBound.containsAny(formals) ||
365 !isSubtype(declaredBound, upper))) {
366 bound = upper;
367 bk = EXTENDS;
368 } else if (!lower.hasTag(BOT)) {
369 bound = lower;
370 bk = SUPER;
371 } else {
372 bound = syms.objectType;
373 bk = UNBOUND;
374 }
375 return makeWildcard(bound, bk);
376 }
377
378 @Override
379 public Type visitWildcardType(WildcardType wt, ProjectionKind pkind) {
380 //type argument is some wildcard whose bound contains restricted vars
381 Type bound = syms.botType;
382 BoundKind bk = wt.kind;
383 switch (wt.kind) {
384 case EXTENDS:
385 bound = wt.type.map(TypeProjection.this, pkind);
386 if (bound.hasTag(BOT)) {
387 return syms.botType;
388 }
389 break;
390 case SUPER:
391 bound = wt.type.map(TypeProjection.this, pkind.complement());
392 if (bound.hasTag(BOT)) {
393 bound = syms.objectType;
394 bk = UNBOUND;
395 }
396 break;
397 }
398 return makeWildcard(bound, bk);
399 }
400
401 private Type makeWildcard(Type bound, BoundKind bk) {
402 return new WildcardType(bound, bk, syms.boundClass) {
403 @Override
404 protected boolean needsStripping() {
405 return true;
406 }
407 };
408 }
409 }
410 }
411
412 /**
413 * Computes an upward projection of given type, and vars. See {@link TypeProjection}.
414 *
415 * @param t the type to be projected
416 * @param vars the set of type variables to be mapped
417 * @return the type obtained as result of the projection
418 */
419 public Type upward(Type t, List<Type> vars) {
420 return t.map(new TypeProjection(vars), ProjectionKind.UPWARDS);
421 }
422
423 /**
424 * Computes the set of captured variables mentioned in a given type. See {@link CaptureScanner}.
425 * This routine is typically used to computed the input set of variables to be used during
426 * an upwards projection (see {@link Types#upward(Type, List)}).
427 *
428 * @param t the type where occurrences of captured variables have to be found
429 * @return the set of captured variables found in t
430 */
431 public List<Type> captures(Type t) {
432 CaptureScanner cs = new CaptureScanner();
433 Set<Type> captures = new HashSet<>();
434 cs.visit(t, captures);
435 return List.from(captures);
436 }
437
438 /**
439 * This visitor scans a type recursively looking for occurrences of captured type variables.
440 */
5319 return syms.doubleType;
5320 case ClassFile.CONSTANT_MethodHandle:
5321 return syms.methodHandleType;
5322 case ClassFile.CONSTANT_MethodType:
5323 return syms.methodTypeType;
5324 case ClassFile.CONSTANT_Dynamic:
5325 return ((DynamicVarSymbol)c).type;
5326 default:
5327 throw new AssertionError("Not a loadable constant: " + c.poolTag());
5328 }
5329 }
5330 // </editor-fold>
5331
5332 public void newRound() {
5333 descCache._map.clear();
5334 isDerivedRawCache.clear();
5335 implCache._map.clear();
5336 membersCache._map.clear();
5337 closureCache.clear();
5338 }
5339 }
|
184 */
185 public Type skipTypeVars(Type site, boolean capture) {
186 while (site.hasTag(TYPEVAR)) {
187 site = site.getUpperBound();
188 }
189 return capture ? capture(site) : site;
190 }
191 // </editor-fold>
192
193 // <editor-fold defaultstate="collapsed" desc="projections">
194
195 /**
196 * A projection kind. See {@link TypeProjection}
197 */
198 enum ProjectionKind {
199 UPWARDS() {
200 @Override
201 ProjectionKind complement() {
202 return DOWNWARDS;
203 }
204
205 @Override
206 boolean allowIntersectionTypes() {
207 return true;
208 }
209
210 @Override
211 ProjectionKind withIntersectionTypes(boolean allowIntersectionTypes) {
212 return allowIntersectionTypes ? this : UPWARDS_NO_INTERSECTION;
213 }
214 },
215 DOWNWARDS() {
216 @Override
217 ProjectionKind complement() {
218 return UPWARDS;
219 }
220
221 @Override
222 boolean allowIntersectionTypes() {
223 return true;
224 }
225
226 @Override
227 ProjectionKind withIntersectionTypes(boolean allowIntersectionTypes) {
228 return allowIntersectionTypes ? this : DOWNWARDS_NO_INTERSECTION;
229 }
230 },
231 UPWARDS_NO_INTERSECTION() {
232 @Override
233 ProjectionKind complement() {
234 return DOWNWARDS_NO_INTERSECTION;
235 }
236
237 @Override
238 boolean allowIntersectionTypes() {
239 return false;
240 }
241
242 @Override
243 ProjectionKind withIntersectionTypes(boolean allowIntersectionTypes) {
244 return allowIntersectionTypes ? UPWARDS : this;
245 }
246 },
247 DOWNWARDS_NO_INTERSECTION() {
248 @Override
249 ProjectionKind complement() {
250 return UPWARDS_NO_INTERSECTION;
251 }
252
253 @Override
254 boolean allowIntersectionTypes() {
255 return false;
256 }
257
258 @Override
259 ProjectionKind withIntersectionTypes(boolean allowIntersectionTypes) {
260 return allowIntersectionTypes ? DOWNWARDS : this;
261 }
262 };
263
264 abstract ProjectionKind complement();
265 abstract boolean allowIntersectionTypes();
266 abstract ProjectionKind withIntersectionTypes(boolean allowIntersectionTypes);
267 }
268
269 /**
270 * This visitor performs upwards and downwards projections on types.
271 *
272 * A projection is defined as a function that takes a type T, a set of type variables V and that
273 * produces another type S.
274 *
275 * An upwards projection maps a type T into a type S such that (i) T has no variables in V,
276 * and (ii) S is an upper bound of T.
277 *
278 * A downwards projection maps a type T into a type S such that (i) T has no variables in V,
279 * and (ii) S is a lower bound of T.
280 *
281 * Note that projections are only allowed to touch variables in V. Therefore, it is possible for
282 * a projection to leave its input type unchanged if it does not contain any variables in V.
283 *
284 * Moreover, note that while an upwards projection is always defined (every type as an upper bound),
285 * a downwards projection is not always defined.
286 *
287 * Examples:
288 *
289 * {@code upwards(List<#CAP1>, [#CAP1]) = List<? extends String>, where #CAP1 <: String }
290 * {@code downwards(List<#CAP2>, [#CAP2]) = List<? super String>, where #CAP2 :> String }
291 * {@code upwards(List<#CAP1>, [#CAP2]) = List<#CAP1> }
292 * {@code downwards(List<#CAP1>, [#CAP1]) = not defined }
293 */
294 class TypeProjection extends TypeMapping<ProjectionKind> {
295
296 List<Type> vars;
297 Set<Type> seen = new HashSet<>();
298
299 public TypeProjection(List<Type> vars) {
300 this.vars = vars;
301 }
302
303 @Override
304 public Type visitClassType(ClassType t, ProjectionKind pkind) {
305 if (t.isUnion() || t.isIntersection()) {
306 if (pkind.allowIntersectionTypes()) {
307 List<Type> components = directSupertypes(t);
308 List<Type> components1 = components.map(c -> c.map(this, pkind));
309 if (components == components1) return t;
310 else return makeIntersectionType(components1);
311 } else if (t.isIntersection()) {
312 return visit(((IntersectionClassType)t).getExplicitComponents().head, pkind);
313 } else {
314 Assert.check(t.isUnion());
315 return visit(((UnionClassType)t).getLub(), pkind);
316 }
317 } else {
318 Type outer = t.getEnclosingType();
319 Type outer1 = visit(outer, pkind);
320 List<Type> typarams = t.getTypeArguments();
321 List<Type> formals = t.tsym.type.getTypeArguments();
322 ListBuffer<Type> typarams1 = new ListBuffer<>();
323 boolean changed = false;
324 for (Type actual : typarams) {
325 Type t2 = mapTypeArgument(t, formals.head.getUpperBound(), actual, pkind);
326 if (t2.hasTag(BOT)) {
327 //not defined
328 return syms.botType;
329 }
330 typarams1.add(t2);
331 changed |= actual != t2;
332 formals = formals.tail;
333 }
334 if (outer1 == outer && !changed) return t;
335 else return new ClassType(outer1, typarams1.toList(), t.tsym, t.getMetadata()) {
336 @Override
351 //undefined
352 return syms.botType;
353 } else {
354 return new ArrayType(elemtype1, t.tsym, t.metadata) {
355 @Override
356 protected boolean needsStripping() {
357 return true;
358 }
359 };
360 }
361 }
362
363 @Override
364 public Type visitTypeVar(TypeVar t, ProjectionKind pkind) {
365 if (vars.contains(t)) {
366 if (seen.add(t)) {
367 try {
368 final Type bound;
369 switch (pkind) {
370 case UPWARDS:
371 case UPWARDS_NO_INTERSECTION:
372 bound = t.getUpperBound();
373 break;
374 case DOWNWARDS:
375 case DOWNWARDS_NO_INTERSECTION:
376 bound = (t.getLowerBound() == null) ?
377 syms.botType :
378 t.getLowerBound();
379 break;
380 default:
381 Assert.error();
382 return null;
383 }
384 return bound.map(this, pkind);
385 } finally {
386 seen.remove(t);
387 }
388 } else {
389 //cycle
390 return (pkind == ProjectionKind.UPWARDS || pkind == ProjectionKind.UPWARDS_NO_INTERSECTION) ?
391 syms.objectType : syms.botType;
392 }
393 } else {
394 return t;
395 }
396 }
397
398 private Type mapTypeArgument(Type site, Type declaredBound, Type t, ProjectionKind pkind) {
399 return (t.containsAny(vars) || (!pkind.allowIntersectionTypes() && !chk.checkDenotable(t))) ?
400 t.map(new TypeArgumentProjection(site, declaredBound), pkind) :
401 t;
402 }
403
404 class TypeArgumentProjection extends TypeMapping<ProjectionKind> {
405
406 Type site;
407 Type declaredBound;
408
409 TypeArgumentProjection(Type site, Type declaredBound) {
410 this.site = site;
411 this.declaredBound = declaredBound;
412 }
413
414 @Override
415 public Type visitType(Type t, ProjectionKind pkind) {
416 //type argument is some type containing restricted vars
417 if (pkind == ProjectionKind.DOWNWARDS || pkind == ProjectionKind.DOWNWARDS_NO_INTERSECTION) {
418 //not defined
419 return syms.botType;
420 }
421 Type upper = t.map(TypeProjection.this, ProjectionKind.UPWARDS.withIntersectionTypes(pkind.allowIntersectionTypes()));
422 Type lower = t.map(TypeProjection.this, ProjectionKind.DOWNWARDS);
423 List<Type> formals = site.tsym.type.getTypeArguments();
424 BoundKind bk;
425 Type bound;
426 if (!isSameType(upper, syms.objectType) &&
427 (declaredBound.containsAny(formals) ||
428 !isSubtype(declaredBound, upper))) {
429 bound = upper;
430 bk = EXTENDS;
431 } else if (!lower.hasTag(BOT) && (!lower.isIntersection() || pkind.allowIntersectionTypes())) {
432 bound = lower;
433 bk = SUPER;
434 } else {
435 bound = syms.objectType;
436 bk = UNBOUND;
437 }
438 return makeWildcard(bound, bk);
439 }
440
441 @Override
442 public Type visitWildcardType(WildcardType wt, ProjectionKind pkind) {
443 //type argument is some wildcard whose bound contains restricted vars
444 Type bound = syms.botType;
445 BoundKind bk = wt.kind;
446 switch (wt.kind) {
447 case EXTENDS:
448 bound = wt.type.map(TypeProjection.this, pkind);
449 if (bound.hasTag(BOT)) {
450 return syms.botType;
451 }
452 break;
453 case SUPER:
454 bound = wt.type.map(TypeProjection.this, pkind.withIntersectionTypes(true).complement());
455 if (bound.hasTag(BOT) || (bound.isIntersection() && !pkind.allowIntersectionTypes())) {
456 bound = syms.objectType;
457 bk = UNBOUND;
458 }
459 break;
460 }
461 return makeWildcard(bound, bk);
462 }
463
464 private Type makeWildcard(Type bound, BoundKind bk) {
465 return new WildcardType(bound, bk, syms.boundClass) {
466 @Override
467 protected boolean needsStripping() {
468 return true;
469 }
470 };
471 }
472 }
473 }
474
475 /**
476 * Computes an upward projection of given type, and vars. See {@link TypeProjection}.
477 *
478 * @param t the type to be projected
479 * @param vars the set of type variables to be mapped
480 * @return the type obtained as result of the projection
481 */
482 public Type upward(Type t, List<Type> vars) {
483 return upward(t, true, vars);
484 }
485
486 /**
487 * Computes an upward projection of given type, and vars. See {@link TypeProjection}.
488 *
489 * @param t the type to be projected
490 * @param allowIntersection whether intersection types should be allowed in the projection
491 * @param vars the set of type variables to be mapped
492 * @return the type obtained as result of the projection
493 */
494 public Type upward(Type t, boolean allowIntersection, List<Type> vars) {
495 return t.map(new TypeProjection(vars),
496 allowIntersection ? ProjectionKind.UPWARDS : ProjectionKind.UPWARDS_NO_INTERSECTION);
497 }
498
499 /**
500 * Computes the set of captured variables mentioned in a given type. See {@link CaptureScanner}.
501 * This routine is typically used to computed the input set of variables to be used during
502 * an upwards projection (see {@link Types#upward(Type, List)}).
503 *
504 * @param t the type where occurrences of captured variables have to be found
505 * @return the set of captured variables found in t
506 */
507 public List<Type> captures(Type t) {
508 CaptureScanner cs = new CaptureScanner();
509 Set<Type> captures = new HashSet<>();
510 cs.visit(t, captures);
511 return List.from(captures);
512 }
513
514 /**
515 * This visitor scans a type recursively looking for occurrences of captured type variables.
516 */
5395 return syms.doubleType;
5396 case ClassFile.CONSTANT_MethodHandle:
5397 return syms.methodHandleType;
5398 case ClassFile.CONSTANT_MethodType:
5399 return syms.methodTypeType;
5400 case ClassFile.CONSTANT_Dynamic:
5401 return ((DynamicVarSymbol)c).type;
5402 default:
5403 throw new AssertionError("Not a loadable constant: " + c.poolTag());
5404 }
5405 }
5406 // </editor-fold>
5407
5408 public void newRound() {
5409 descCache._map.clear();
5410 isDerivedRawCache.clear();
5411 implCache._map.clear();
5412 membersCache._map.clear();
5413 closureCache.clear();
5414 }
5415
5416 // code reflection
5417
5418 // The predicates below do not use a predefined symbol in Symtab.
5419 // This is deliberate, as we cannot initialize symbols in modules
5420 // other than java.base at startup.
5421
5422 public boolean isQuotable(Type type) {
5423 Symbol s = type.tsym;
5424 return s != null &&
5425 s.kind == TYP &&
5426 s.name.equals(names.quotable) &&
5427 s.packge().fullname.equals(names.jdk_incubator_code) &&
5428 s.packge().modle.name.equals(names.jdk_incubator_code);
5429 }
5430 }
|