1 /*
2 * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
181 */
182 public Type skipTypeVars(Type site, boolean capture) {
183 while (site.hasTag(TYPEVAR)) {
184 site = site.getUpperBound();
185 }
186 return capture ? capture(site) : site;
187 }
188 // </editor-fold>
189
190 // <editor-fold defaultstate="collapsed" desc="projections">
191
192 /**
193 * A projection kind. See {@link TypeProjection}
194 */
195 enum ProjectionKind {
196 UPWARDS() {
197 @Override
198 ProjectionKind complement() {
199 return DOWNWARDS;
200 }
201 },
202 DOWNWARDS() {
203 @Override
204 ProjectionKind complement() {
205 return UPWARDS;
206 }
207 };
208
209 abstract ProjectionKind complement();
210 }
211
212 /**
213 * This visitor performs upwards and downwards projections on types.
214 *
215 * A projection is defined as a function that takes a type T, a set of type variables V and that
216 * produces another type S.
217 *
218 * An upwards projection maps a type T into a type S such that (i) T has no variables in V,
219 * and (ii) S is an upper bound of T.
220 *
221 * A downwards projection maps a type T into a type S such that (i) T has no variables in V,
222 * and (ii) S is a lower bound of T.
223 *
224 * Note that projections are only allowed to touch variables in V. Therefore, it is possible for
225 * a projection to leave its input type unchanged if it does not contain any variables in V.
226 *
227 * Moreover, note that while an upwards projection is always defined (every type as an upper bound),
228 * a downwards projection is not always defined.
229 *
230 * Examples:
231 *
232 * {@code upwards(List<#CAP1>, [#CAP1]) = List<? extends String>, where #CAP1 <: String }
233 * {@code downwards(List<#CAP2>, [#CAP2]) = List<? super String>, where #CAP2 :> String }
234 * {@code upwards(List<#CAP1>, [#CAP2]) = List<#CAP1> }
235 * {@code downwards(List<#CAP1>, [#CAP1]) = not defined }
236 */
237 class TypeProjection extends TypeMapping<ProjectionKind> {
238
239 List<Type> vars;
240 Set<Type> seen = new HashSet<>();
241
242 public TypeProjection(List<Type> vars) {
243 this.vars = vars;
244 }
245
246 @Override
247 public Type visitClassType(ClassType t, ProjectionKind pkind) {
248 if (t.isCompound()) {
249 List<Type> components = directSupertypes(t);
250 List<Type> components1 = components.map(c -> c.map(this, pkind));
251 if (components == components1) return t;
252 else return makeIntersectionType(components1);
253 } else {
254 Type outer = t.getEnclosingType();
255 Type outer1 = visit(outer, pkind);
256 List<Type> typarams = t.getTypeArguments();
257 List<Type> formals = t.tsym.type.getTypeArguments();
258 ListBuffer<Type> typarams1 = new ListBuffer<>();
259 boolean changed = false;
260 for (Type actual : typarams) {
261 Type t2 = mapTypeArgument(t, formals.head.getUpperBound(), actual, pkind);
262 if (t2.hasTag(BOT)) {
263 //not defined
264 return syms.botType;
265 }
266 typarams1.add(t2);
267 changed |= actual != t2;
268 formals = formals.tail;
269 }
270 if (outer1 == outer && !changed) return t;
271 else return new ClassType(outer1, typarams1.toList(), t.tsym, t.getMetadata()) {
272 @Override
287 //undefined
288 return syms.botType;
289 } else {
290 return new ArrayType(elemtype1, t.tsym, t.metadata) {
291 @Override
292 protected boolean needsStripping() {
293 return true;
294 }
295 };
296 }
297 }
298
299 @Override
300 public Type visitTypeVar(TypeVar t, ProjectionKind pkind) {
301 if (vars.contains(t)) {
302 if (seen.add(t)) {
303 try {
304 final Type bound;
305 switch (pkind) {
306 case UPWARDS:
307 bound = t.getUpperBound();
308 break;
309 case DOWNWARDS:
310 bound = (t.getLowerBound() == null) ?
311 syms.botType :
312 t.getLowerBound();
313 break;
314 default:
315 Assert.error();
316 return null;
317 }
318 return bound.map(this, pkind);
319 } finally {
320 seen.remove(t);
321 }
322 } else {
323 //cycle
324 return pkind == ProjectionKind.UPWARDS ?
325 syms.objectType : syms.botType;
326 }
327 } else {
328 return t;
329 }
330 }
331
332 private Type mapTypeArgument(Type site, Type declaredBound, Type t, ProjectionKind pkind) {
333 return t.containsAny(vars) ?
334 t.map(new TypeArgumentProjection(site, declaredBound), pkind) :
335 t;
336 }
337
338 class TypeArgumentProjection extends TypeMapping<ProjectionKind> {
339
340 Type site;
341 Type declaredBound;
342
343 TypeArgumentProjection(Type site, Type declaredBound) {
344 this.site = site;
345 this.declaredBound = declaredBound;
346 }
347
348 @Override
349 public Type visitType(Type t, ProjectionKind pkind) {
350 //type argument is some type containing restricted vars
351 if (pkind == ProjectionKind.DOWNWARDS) {
352 //not defined
353 return syms.botType;
354 }
355 Type upper = t.map(TypeProjection.this, ProjectionKind.UPWARDS);
356 Type lower = t.map(TypeProjection.this, ProjectionKind.DOWNWARDS);
357 List<Type> formals = site.tsym.type.getTypeArguments();
358 BoundKind bk;
359 Type bound;
360 if (!isSameType(upper, syms.objectType) &&
361 (declaredBound.containsAny(formals) ||
362 !isSubtype(declaredBound, upper))) {
363 bound = upper;
364 bk = EXTENDS;
365 } else if (!lower.hasTag(BOT)) {
366 bound = lower;
367 bk = SUPER;
368 } else {
369 bound = syms.objectType;
370 bk = UNBOUND;
371 }
372 return makeWildcard(bound, bk);
373 }
374
375 @Override
376 public Type visitWildcardType(WildcardType wt, ProjectionKind pkind) {
377 //type argument is some wildcard whose bound contains restricted vars
378 Type bound = syms.botType;
379 BoundKind bk = wt.kind;
380 switch (wt.kind) {
381 case EXTENDS:
382 bound = wt.type.map(TypeProjection.this, pkind);
383 if (bound.hasTag(BOT)) {
384 return syms.botType;
385 }
386 break;
387 case SUPER:
388 bound = wt.type.map(TypeProjection.this, pkind.complement());
389 if (bound.hasTag(BOT)) {
390 bound = syms.objectType;
391 bk = UNBOUND;
392 }
393 break;
394 }
395 return makeWildcard(bound, bk);
396 }
397
398 private Type makeWildcard(Type bound, BoundKind bk) {
399 return new WildcardType(bound, bk, syms.boundClass) {
400 @Override
401 protected boolean needsStripping() {
402 return true;
403 }
404 };
405 }
406 }
407 }
408
409 /**
410 * Computes an upward projection of given type, and vars. See {@link TypeProjection}.
411 *
412 * @param t the type to be projected
413 * @param vars the set of type variables to be mapped
414 * @return the type obtained as result of the projection
415 */
416 public Type upward(Type t, List<Type> vars) {
417 return t.map(new TypeProjection(vars), ProjectionKind.UPWARDS);
418 }
419
420 /**
421 * Computes the set of captured variables mentioned in a given type. See {@link CaptureScanner}.
422 * This routine is typically used to computed the input set of variables to be used during
423 * an upwards projection (see {@link Types#upward(Type, List)}).
424 *
425 * @param t the type where occurrences of captured variables have to be found
426 * @return the set of captured variables found in t
427 */
428 public List<Type> captures(Type t) {
429 CaptureScanner cs = new CaptureScanner();
430 Set<Type> captures = new HashSet<>();
431 cs.visit(t, captures);
432 return List.from(captures);
433 }
434
435 /**
436 * This visitor scans a type recursively looking for occurrences of captured type variables.
437 */
5305 return syms.doubleType;
5306 case ClassFile.CONSTANT_MethodHandle:
5307 return syms.methodHandleType;
5308 case ClassFile.CONSTANT_MethodType:
5309 return syms.methodTypeType;
5310 case ClassFile.CONSTANT_Dynamic:
5311 return ((DynamicVarSymbol)c).type;
5312 default:
5313 throw new AssertionError("Not a loadable constant: " + c.poolTag());
5314 }
5315 }
5316 // </editor-fold>
5317
5318 public void newRound() {
5319 descCache._map.clear();
5320 isDerivedRawCache.clear();
5321 implCache._map.clear();
5322 membersCache._map.clear();
5323 closureCache.clear();
5324 }
5325 }
|
1 /*
2 * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
181 */
182 public Type skipTypeVars(Type site, boolean capture) {
183 while (site.hasTag(TYPEVAR)) {
184 site = site.getUpperBound();
185 }
186 return capture ? capture(site) : site;
187 }
188 // </editor-fold>
189
190 // <editor-fold defaultstate="collapsed" desc="projections">
191
192 /**
193 * A projection kind. See {@link TypeProjection}
194 */
195 enum ProjectionKind {
196 UPWARDS() {
197 @Override
198 ProjectionKind complement() {
199 return DOWNWARDS;
200 }
201
202 @Override
203 boolean allowIntersectionTypes() {
204 return true;
205 }
206
207 @Override
208 ProjectionKind withIntersectionTypes(boolean allowIntersectionTypes) {
209 return allowIntersectionTypes ? this : UPWARDS_NO_INTERSECTION;
210 }
211 },
212 DOWNWARDS() {
213 @Override
214 ProjectionKind complement() {
215 return UPWARDS;
216 }
217
218 @Override
219 boolean allowIntersectionTypes() {
220 return true;
221 }
222
223 @Override
224 ProjectionKind withIntersectionTypes(boolean allowIntersectionTypes) {
225 return allowIntersectionTypes ? this : DOWNWARDS_NO_INTERSECTION;
226 }
227 },
228 UPWARDS_NO_INTERSECTION() {
229 @Override
230 ProjectionKind complement() {
231 return DOWNWARDS_NO_INTERSECTION;
232 }
233
234 @Override
235 boolean allowIntersectionTypes() {
236 return false;
237 }
238
239 @Override
240 ProjectionKind withIntersectionTypes(boolean allowIntersectionTypes) {
241 return allowIntersectionTypes ? UPWARDS : this;
242 }
243 },
244 DOWNWARDS_NO_INTERSECTION() {
245 @Override
246 ProjectionKind complement() {
247 return UPWARDS_NO_INTERSECTION;
248 }
249
250 @Override
251 boolean allowIntersectionTypes() {
252 return false;
253 }
254
255 @Override
256 ProjectionKind withIntersectionTypes(boolean allowIntersectionTypes) {
257 return allowIntersectionTypes ? DOWNWARDS : this;
258 }
259 };
260
261 abstract ProjectionKind complement();
262 abstract boolean allowIntersectionTypes();
263 abstract ProjectionKind withIntersectionTypes(boolean allowIntersectionTypes);
264 }
265
266 /**
267 * This visitor performs upwards and downwards projections on types.
268 *
269 * A projection is defined as a function that takes a type T, a set of type variables V and that
270 * produces another type S.
271 *
272 * An upwards projection maps a type T into a type S such that (i) T has no variables in V,
273 * and (ii) S is an upper bound of T.
274 *
275 * A downwards projection maps a type T into a type S such that (i) T has no variables in V,
276 * and (ii) S is a lower bound of T.
277 *
278 * Note that projections are only allowed to touch variables in V. Therefore, it is possible for
279 * a projection to leave its input type unchanged if it does not contain any variables in V.
280 *
281 * Moreover, note that while an upwards projection is always defined (every type as an upper bound),
282 * a downwards projection is not always defined.
283 *
284 * Examples:
285 *
286 * {@code upwards(List<#CAP1>, [#CAP1]) = List<? extends String>, where #CAP1 <: String }
287 * {@code downwards(List<#CAP2>, [#CAP2]) = List<? super String>, where #CAP2 :> String }
288 * {@code upwards(List<#CAP1>, [#CAP2]) = List<#CAP1> }
289 * {@code downwards(List<#CAP1>, [#CAP1]) = not defined }
290 */
291 class TypeProjection extends TypeMapping<ProjectionKind> {
292
293 List<Type> vars;
294 Set<Type> seen = new HashSet<>();
295
296 public TypeProjection(List<Type> vars) {
297 this.vars = vars;
298 }
299
300 @Override
301 public Type visitClassType(ClassType t, ProjectionKind pkind) {
302 if (t.isUnion() || t.isIntersection()) {
303 if (pkind.allowIntersectionTypes()) {
304 List<Type> components = directSupertypes(t);
305 List<Type> components1 = components.map(c -> c.map(this, pkind));
306 if (components == components1) return t;
307 else return makeIntersectionType(components1);
308 } else if (t.isIntersection()) {
309 return visit(((IntersectionClassType)t).getExplicitComponents().head, pkind);
310 } else {
311 Assert.check(t.isUnion());
312 return visit(((UnionClassType)t).getLub(), pkind);
313 }
314 } else {
315 Type outer = t.getEnclosingType();
316 Type outer1 = visit(outer, pkind);
317 List<Type> typarams = t.getTypeArguments();
318 List<Type> formals = t.tsym.type.getTypeArguments();
319 ListBuffer<Type> typarams1 = new ListBuffer<>();
320 boolean changed = false;
321 for (Type actual : typarams) {
322 Type t2 = mapTypeArgument(t, formals.head.getUpperBound(), actual, pkind);
323 if (t2.hasTag(BOT)) {
324 //not defined
325 return syms.botType;
326 }
327 typarams1.add(t2);
328 changed |= actual != t2;
329 formals = formals.tail;
330 }
331 if (outer1 == outer && !changed) return t;
332 else return new ClassType(outer1, typarams1.toList(), t.tsym, t.getMetadata()) {
333 @Override
348 //undefined
349 return syms.botType;
350 } else {
351 return new ArrayType(elemtype1, t.tsym, t.metadata) {
352 @Override
353 protected boolean needsStripping() {
354 return true;
355 }
356 };
357 }
358 }
359
360 @Override
361 public Type visitTypeVar(TypeVar t, ProjectionKind pkind) {
362 if (vars.contains(t)) {
363 if (seen.add(t)) {
364 try {
365 final Type bound;
366 switch (pkind) {
367 case UPWARDS:
368 case UPWARDS_NO_INTERSECTION:
369 bound = t.getUpperBound();
370 break;
371 case DOWNWARDS:
372 case DOWNWARDS_NO_INTERSECTION:
373 bound = (t.getLowerBound() == null) ?
374 syms.botType :
375 t.getLowerBound();
376 break;
377 default:
378 Assert.error();
379 return null;
380 }
381 return bound.map(this, pkind);
382 } finally {
383 seen.remove(t);
384 }
385 } else {
386 //cycle
387 return (pkind == ProjectionKind.UPWARDS || pkind == ProjectionKind.UPWARDS_NO_INTERSECTION) ?
388 syms.objectType : syms.botType;
389 }
390 } else {
391 return t;
392 }
393 }
394
395 private Type mapTypeArgument(Type site, Type declaredBound, Type t, ProjectionKind pkind) {
396 return (t.containsAny(vars) || (!pkind.allowIntersectionTypes() && !chk.checkDenotable(t))) ?
397 t.map(new TypeArgumentProjection(site, declaredBound), pkind) :
398 t;
399 }
400
401 class TypeArgumentProjection extends TypeMapping<ProjectionKind> {
402
403 Type site;
404 Type declaredBound;
405
406 TypeArgumentProjection(Type site, Type declaredBound) {
407 this.site = site;
408 this.declaredBound = declaredBound;
409 }
410
411 @Override
412 public Type visitType(Type t, ProjectionKind pkind) {
413 //type argument is some type containing restricted vars
414 if (pkind == ProjectionKind.DOWNWARDS || pkind == ProjectionKind.DOWNWARDS_NO_INTERSECTION) {
415 //not defined
416 return syms.botType;
417 }
418 Type upper = t.map(TypeProjection.this, ProjectionKind.UPWARDS.withIntersectionTypes(pkind.allowIntersectionTypes()));
419 Type lower = t.map(TypeProjection.this, ProjectionKind.DOWNWARDS);
420 List<Type> formals = site.tsym.type.getTypeArguments();
421 BoundKind bk;
422 Type bound;
423 if (!isSameType(upper, syms.objectType) &&
424 (declaredBound.containsAny(formals) ||
425 !isSubtype(declaredBound, upper))) {
426 bound = upper;
427 bk = EXTENDS;
428 } else if (!lower.hasTag(BOT) && (!lower.isIntersection() || pkind.allowIntersectionTypes())) {
429 bound = lower;
430 bk = SUPER;
431 } else {
432 bound = syms.objectType;
433 bk = UNBOUND;
434 }
435 return makeWildcard(bound, bk);
436 }
437
438 @Override
439 public Type visitWildcardType(WildcardType wt, ProjectionKind pkind) {
440 //type argument is some wildcard whose bound contains restricted vars
441 Type bound = syms.botType;
442 BoundKind bk = wt.kind;
443 switch (wt.kind) {
444 case EXTENDS:
445 bound = wt.type.map(TypeProjection.this, pkind);
446 if (bound.hasTag(BOT)) {
447 return syms.botType;
448 }
449 break;
450 case SUPER:
451 bound = wt.type.map(TypeProjection.this, pkind.withIntersectionTypes(true).complement());
452 if (bound.hasTag(BOT) || (bound.isIntersection() && !pkind.allowIntersectionTypes())) {
453 bound = syms.objectType;
454 bk = UNBOUND;
455 }
456 break;
457 }
458 return makeWildcard(bound, bk);
459 }
460
461 private Type makeWildcard(Type bound, BoundKind bk) {
462 return new WildcardType(bound, bk, syms.boundClass) {
463 @Override
464 protected boolean needsStripping() {
465 return true;
466 }
467 };
468 }
469 }
470 }
471
472 /**
473 * Computes an upward projection of given type, and vars. See {@link TypeProjection}.
474 *
475 * @param t the type to be projected
476 * @param vars the set of type variables to be mapped
477 * @return the type obtained as result of the projection
478 */
479 public Type upward(Type t, List<Type> vars) {
480 return upward(t, true, vars);
481 }
482
483 /**
484 * Computes an upward projection of given type, and vars. See {@link TypeProjection}.
485 *
486 * @param t the type to be projected
487 * @param allowIntersection whether intersection types should be allowed in the projection
488 * @param vars the set of type variables to be mapped
489 * @return the type obtained as result of the projection
490 */
491 public Type upward(Type t, boolean allowIntersection, List<Type> vars) {
492 return t.map(new TypeProjection(vars),
493 allowIntersection ? ProjectionKind.UPWARDS : ProjectionKind.UPWARDS_NO_INTERSECTION);
494 }
495
496 /**
497 * Computes the set of captured variables mentioned in a given type. See {@link CaptureScanner}.
498 * This routine is typically used to computed the input set of variables to be used during
499 * an upwards projection (see {@link Types#upward(Type, List)}).
500 *
501 * @param t the type where occurrences of captured variables have to be found
502 * @return the set of captured variables found in t
503 */
504 public List<Type> captures(Type t) {
505 CaptureScanner cs = new CaptureScanner();
506 Set<Type> captures = new HashSet<>();
507 cs.visit(t, captures);
508 return List.from(captures);
509 }
510
511 /**
512 * This visitor scans a type recursively looking for occurrences of captured type variables.
513 */
5381 return syms.doubleType;
5382 case ClassFile.CONSTANT_MethodHandle:
5383 return syms.methodHandleType;
5384 case ClassFile.CONSTANT_MethodType:
5385 return syms.methodTypeType;
5386 case ClassFile.CONSTANT_Dynamic:
5387 return ((DynamicVarSymbol)c).type;
5388 default:
5389 throw new AssertionError("Not a loadable constant: " + c.poolTag());
5390 }
5391 }
5392 // </editor-fold>
5393
5394 public void newRound() {
5395 descCache._map.clear();
5396 isDerivedRawCache.clear();
5397 implCache._map.clear();
5398 membersCache._map.clear();
5399 closureCache.clear();
5400 }
5401
5402 // code reflection
5403
5404 public boolean isQuoted(Type type) {
5405 return type.tsym == syms.quotedType.tsym;
5406 }
5407 }
|