235 * {@code upwards(List<#CAP1>, [#CAP1]) = List<? extends String>, where #CAP1 <: String } |
235 * {@code upwards(List<#CAP1>, [#CAP1]) = List<? extends String>, where #CAP1 <: String } |
236 * {@code downwards(List<#CAP2>, [#CAP2]) = List<? super String>, where #CAP2 :> String } |
236 * {@code downwards(List<#CAP2>, [#CAP2]) = List<? super String>, where #CAP2 :> String } |
237 * {@code upwards(List<#CAP1>, [#CAP2]) = List<#CAP1> } |
237 * {@code upwards(List<#CAP1>, [#CAP2]) = List<#CAP1> } |
238 * {@code downwards(List<#CAP1>, [#CAP1]) = not defined } |
238 * {@code downwards(List<#CAP1>, [#CAP1]) = not defined } |
239 */ |
239 */ |
240 class TypeProjection extends StructuralTypeMapping<ProjectionKind> { |
240 class TypeProjection extends TypeMapping<ProjectionKind> { |
241 |
241 |
242 List<Type> vars; |
242 List<Type> vars; |
243 Set<Type> seen = new HashSet<>(); |
243 Set<Type> seen = new HashSet<>(); |
244 |
244 |
245 public TypeProjection(List<Type> vars) { |
245 public TypeProjection(List<Type> vars) { |
255 else return makeIntersectionType(components1); |
255 else return makeIntersectionType(components1); |
256 } else { |
256 } else { |
257 Type outer = t.getEnclosingType(); |
257 Type outer = t.getEnclosingType(); |
258 Type outer1 = visit(outer, pkind); |
258 Type outer1 = visit(outer, pkind); |
259 List<Type> typarams = t.getTypeArguments(); |
259 List<Type> typarams = t.getTypeArguments(); |
260 List<Type> typarams1 = typarams.map(ta -> mapTypeArgument(ta, pkind)); |
260 List<Type> formals = t.tsym.type.getTypeArguments(); |
261 if (typarams1.stream().anyMatch(ta -> ta.hasTag(BOT))) { |
261 ListBuffer<Type> typarams1 = new ListBuffer<>(); |
262 //not defined |
262 boolean changed = false; |
263 return syms.botType; |
263 for (Type actual : typarams) { |
264 } |
264 Type t2 = mapTypeArgument(t, formals.head.getUpperBound(), actual, pkind); |
265 if (outer1 == outer && typarams1 == typarams) return t; |
265 if (t2.hasTag(BOT)) { |
266 else return new ClassType(outer1, typarams1, t.tsym, t.getMetadata()) { |
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()) { |
267 @Override |
275 @Override |
268 protected boolean needsStripping() { |
276 protected boolean needsStripping() { |
269 return true; |
277 return true; |
270 } |
278 } |
271 }; |
279 }; |
272 } |
280 } |
273 } |
281 } |
274 |
282 |
275 protected Type makeWildcard(Type upper, Type lower) { |
283 @Override |
276 BoundKind bk; |
284 public Type visitArrayType(ArrayType t, ProjectionKind s) { |
277 Type bound; |
285 Type elemtype = t.elemtype; |
278 if (upper.hasTag(BOT)) { |
286 Type elemtype1 = visit(elemtype, s); |
279 upper = syms.objectType; |
287 if (elemtype1 == elemtype) { |
280 } |
288 return t; |
281 boolean isUpperObject = isSameType(upper, syms.objectType); |
289 } else if (elemtype1.hasTag(BOT)) { |
282 if (!lower.hasTag(BOT) && isUpperObject) { |
290 //undefined |
283 bound = lower; |
291 return syms.botType; |
284 bk = SUPER; |
|
285 } else { |
292 } else { |
286 bound = upper; |
293 return new ArrayType(elemtype1, t.tsym, t.metadata) { |
287 bk = isUpperObject ? UNBOUND : EXTENDS; |
294 @Override |
288 } |
295 protected boolean needsStripping() { |
289 return new WildcardType(bound, bk, syms.boundClass); |
296 return true; |
|
297 } |
|
298 }; |
|
299 } |
290 } |
300 } |
291 |
301 |
292 @Override |
302 @Override |
293 public Type visitTypeVar(TypeVar t, ProjectionKind pkind) { |
303 public Type visitTypeVar(TypeVar t, ProjectionKind pkind) { |
294 if (vars.contains(t)) { |
304 if (vars.contains(t)) { |
320 } else { |
330 } else { |
321 return t; |
331 return t; |
322 } |
332 } |
323 } |
333 } |
324 |
334 |
325 @Override |
335 private Type mapTypeArgument(Type site, Type declaredBound, Type t, ProjectionKind pkind) { |
326 public Type visitWildcardType(WildcardType wt, ProjectionKind pkind) { |
336 return t.containsAny(vars) ? |
327 switch (pkind) { |
337 t.map(new TypeArgumentProjection(site, declaredBound), pkind) : |
328 case UPWARDS: |
338 t; |
329 return wt.isExtendsBound() ? |
339 } |
330 wt.type.map(this, pkind) : |
340 |
331 syms.objectType; |
341 class TypeArgumentProjection extends TypeMapping<ProjectionKind> { |
332 case DOWNWARDS: |
342 |
333 return wt.isSuperBound() ? |
343 Type site; |
334 wt.type.map(this, pkind) : |
344 Type declaredBound; |
335 syms.botType; |
345 |
336 default: |
346 TypeArgumentProjection(Type site, Type declaredBound) { |
337 Assert.error(); |
347 this.site = site; |
338 return null; |
348 this.declaredBound = declaredBound; |
339 } |
349 } |
340 } |
350 |
341 |
351 @Override |
342 private Type mapTypeArgument(Type t, ProjectionKind pkind) { |
352 public Type visitType(Type t, ProjectionKind pkind) { |
343 if (!t.containsAny(vars)) { |
353 //type argument is some type containing restricted vars |
344 return t; |
354 if (pkind == ProjectionKind.DOWNWARDS) { |
345 } else if (!t.hasTag(WILDCARD) && pkind == ProjectionKind.DOWNWARDS) { |
355 //not defined |
346 //not defined |
356 return syms.botType; |
347 return syms.botType; |
357 } |
348 } else { |
358 Type upper = t.map(TypeProjection.this, ProjectionKind.UPWARDS); |
349 Type upper = t.map(this, pkind); |
359 Type lower = t.map(TypeProjection.this, ProjectionKind.DOWNWARDS); |
350 Type lower = t.map(this, pkind.complement()); |
360 List<Type> formals = site.tsym.type.getTypeArguments(); |
351 return makeWildcard(upper, lower); |
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 }; |
352 } |
408 } |
353 } |
409 } |
354 } |
410 } |
355 |
411 |
356 /** |
412 /** |