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