@@ -329,17 +329,23 @@ private boolean isAssignableFrom(ResolvableType other, boolean strict,
329
329
return true ;
330
330
}
331
331
332
+ boolean exactMatch = (strict && matchedBefore != null ); // We're checking nested generic variables now...
333
+
332
334
// Deal with wildcard bounds
333
335
WildcardBounds ourBounds = WildcardBounds .get (this );
334
336
WildcardBounds typeBounds = WildcardBounds .get (other );
335
337
336
338
// In the form X is assignable to <? extends Number>
337
339
if (typeBounds != null ) {
338
340
if (ourBounds != null ) {
339
- return (ourBounds .isSameKind (typeBounds ) && ourBounds .isAssignableFrom (typeBounds .getBounds ()));
341
+ return (ourBounds .isSameKind (typeBounds ) &&
342
+ ourBounds .isAssignableFrom (typeBounds .getBounds (), matchedBefore ));
340
343
}
341
344
else if (upUntilUnresolvable ) {
342
- return typeBounds .isAssignableFrom (this );
345
+ return typeBounds .isAssignableFrom (this , matchedBefore );
346
+ }
347
+ else if (!exactMatch ) {
348
+ return typeBounds .isAssignableTo (this , matchedBefore );
343
349
}
344
350
else {
345
351
return false ;
@@ -348,11 +354,10 @@ else if (upUntilUnresolvable) {
348
354
349
355
// In the form <? extends Number> is assignable to X...
350
356
if (ourBounds != null ) {
351
- return ourBounds .isAssignableFrom (other );
357
+ return ourBounds .isAssignableFrom (other , matchedBefore );
352
358
}
353
359
354
360
// Main assignability check about to follow
355
- boolean exactMatch = (matchedBefore != null ); // We're checking nested generic variables now...
356
361
boolean checkGenerics = true ;
357
362
Class <?> ourResolved = null ;
358
363
if (this .type instanceof TypeVariable <?> variable ) {
@@ -667,9 +672,9 @@ private boolean isUnresolvableTypeVariable() {
667
672
* without specific bounds (i.e., equal to {@code ? extends Object}).
668
673
*/
669
674
private boolean isWildcardWithoutBounds () {
670
- if (this .type instanceof WildcardType wt ) {
671
- if (wt .getLowerBounds ().length == 0 ) {
672
- Type [] upperBounds = wt .getUpperBounds ();
675
+ if (this .type instanceof WildcardType wildcardType ) {
676
+ if (wildcardType .getLowerBounds ().length == 0 ) {
677
+ Type [] upperBounds = wildcardType .getUpperBounds ();
673
678
if (upperBounds .length == 0 || (upperBounds .length == 1 && Object .class == upperBounds [0 ])) {
674
679
return true ;
675
680
}
@@ -1693,30 +1698,60 @@ public WildcardBounds(Kind kind, ResolvableType[] bounds) {
1693
1698
}
1694
1699
1695
1700
/**
1696
- * Return {@code true} if this bounds is the same kind as the specified bounds.
1701
+ * Return {@code true} if these bounds are the same kind as the specified bounds.
1697
1702
*/
1698
1703
public boolean isSameKind (WildcardBounds bounds ) {
1699
1704
return this .kind == bounds .kind ;
1700
1705
}
1701
1706
1702
1707
/**
1703
- * Return {@code true} if this bounds is assignable to all the specified types.
1708
+ * Return {@code true} if these bounds are assignable from all the specified types.
1704
1709
* @param types the types to test against
1705
- * @return {@code true} if this bounds is assignable to all types
1710
+ * @return {@code true} if these bounds are assignable from all types
1711
+ */
1712
+ public boolean isAssignableFrom (ResolvableType [] types , @ Nullable Map <Type , Type > matchedBefore ) {
1713
+ for (ResolvableType type : types ) {
1714
+ if (!isAssignableFrom (type , matchedBefore )) {
1715
+ return false ;
1716
+ }
1717
+ }
1718
+ return true ;
1719
+ }
1720
+
1721
+ /**
1722
+ * Return {@code true} if these bounds are assignable from the specified type.
1723
+ * @param type the type to test against
1724
+ * @return {@code true} if these bounds are assignable from the type
1725
+ * @since 6.2
1706
1726
*/
1707
- public boolean isAssignableFrom (ResolvableType ... types ) {
1727
+ public boolean isAssignableFrom (ResolvableType type , @ Nullable Map < Type , Type > matchedBefore ) {
1708
1728
for (ResolvableType bound : this .bounds ) {
1709
- for (ResolvableType type : types ) {
1710
- if (!isAssignable (bound , type )) {
1711
- return false ;
1712
- }
1729
+ if (this .kind == Kind .UPPER ? !bound .isAssignableFrom (type , false , matchedBefore , false ) :
1730
+ !type .isAssignableFrom (bound , false , matchedBefore , false )) {
1731
+ return false ;
1713
1732
}
1714
1733
}
1715
1734
return true ;
1716
1735
}
1717
1736
1718
- private boolean isAssignable (ResolvableType source , ResolvableType from ) {
1719
- return (this .kind == Kind .UPPER ? source .isAssignableFrom (from ) : from .isAssignableFrom (source ));
1737
+ /**
1738
+ * Return {@code true} if these bounds are assignable to the specified type.
1739
+ * @param type the type to test against
1740
+ * @return {@code true} if these bounds are assignable to the type
1741
+ * @since 6.2
1742
+ */
1743
+ public boolean isAssignableTo (ResolvableType type , @ Nullable Map <Type , Type > matchedBefore ) {
1744
+ if (this .kind == Kind .UPPER ) {
1745
+ for (ResolvableType bound : this .bounds ) {
1746
+ if (type .isAssignableFrom (bound , false , matchedBefore , false )) {
1747
+ return true ;
1748
+ }
1749
+ }
1750
+ return false ;
1751
+ }
1752
+ else {
1753
+ return (type .resolve () == Object .class );
1754
+ }
1720
1755
}
1721
1756
1722
1757
/**
@@ -1728,21 +1763,30 @@ public ResolvableType[] getBounds() {
1728
1763
1729
1764
/**
1730
1765
* Get a {@link WildcardBounds} instance for the specified type, returning
1731
- * {@code null} if the specified type cannot be resolved to a {@link WildcardType}.
1766
+ * {@code null} if the specified type cannot be resolved to a {@link WildcardType}
1767
+ * or an equivalent unresolvable type variable.
1732
1768
* @param type the source type
1733
1769
* @return a {@link WildcardBounds} instance or {@code null}
1734
1770
*/
1735
1771
@ Nullable
1736
1772
public static WildcardBounds get (ResolvableType type ) {
1737
- ResolvableType resolveToWildcard = type ;
1738
- while (!(resolveToWildcard .getType () instanceof WildcardType wildcardType )) {
1739
- if (resolveToWildcard == NONE ) {
1773
+ ResolvableType candidate = type ;
1774
+ while (!(candidate .getType () instanceof WildcardType || candidate . isUnresolvableTypeVariable () )) {
1775
+ if (candidate == NONE ) {
1740
1776
return null ;
1741
1777
}
1742
- resolveToWildcard = resolveToWildcard .resolveType ();
1778
+ candidate = candidate .resolveType ();
1779
+ }
1780
+ Kind boundsType ;
1781
+ Type [] bounds ;
1782
+ if (candidate .getType () instanceof WildcardType wildcardType ) {
1783
+ boundsType = (wildcardType .getLowerBounds ().length > 0 ? Kind .LOWER : Kind .UPPER );
1784
+ bounds = (boundsType == Kind .UPPER ? wildcardType .getUpperBounds () : wildcardType .getLowerBounds ());
1785
+ }
1786
+ else {
1787
+ boundsType = Kind .UPPER ;
1788
+ bounds = ((TypeVariable <?>) candidate .getType ()).getBounds ();
1743
1789
}
1744
- Kind boundsType = (wildcardType .getLowerBounds ().length > 0 ? Kind .LOWER : Kind .UPPER );
1745
- Type [] bounds = (boundsType == Kind .UPPER ? wildcardType .getUpperBounds () : wildcardType .getLowerBounds ());
1746
1790
ResolvableType [] resolvableBounds = new ResolvableType [bounds .length ];
1747
1791
for (int i = 0 ; i < bounds .length ; i ++) {
1748
1792
resolvableBounds [i ] = ResolvableType .forType (bounds [i ], type .variableResolver );
0 commit comments