mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 11:50:54 +07:00
recursive types capture: avoid capture comparison during glb computation (IDEA-57379; IDEA-139167; IDEA-139157)
This commit is contained in:
@@ -55,7 +55,11 @@ public class PsiCapturedWildcardType extends PsiType.Stub {
|
||||
myUpperBound = PsiType.getJavaLangObject(myContext.getManager(), getResolveScope());
|
||||
}
|
||||
|
||||
private static RecursionGuard guard = RecursionManager.createGuard("captureGuard");
|
||||
public static RecursionGuard guard = RecursionManager.createGuard("captureGuard");
|
||||
|
||||
public static boolean isNoCapture() {
|
||||
return !guard.currentStack().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
@@ -86,7 +90,7 @@ public class PsiCapturedWildcardType extends PsiType.Stub {
|
||||
}
|
||||
});
|
||||
|
||||
if (sameUpperBounds != null && sameUpperBounds) {
|
||||
if (sameUpperBounds == null || sameUpperBounds) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.psi;
|
||||
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
@@ -58,10 +59,18 @@ public class PsiIntersectionType extends PsiType.Stub {
|
||||
return new PsiIntersectionType(conjuncts);
|
||||
}
|
||||
|
||||
private static PsiType[] flattenAndRemoveDuplicates(PsiType[] conjuncts) {
|
||||
private static PsiType[] flattenAndRemoveDuplicates(final PsiType[] conjuncts) {
|
||||
try {
|
||||
Set<PsiType> flattened = flatten(conjuncts, ContainerUtil.<PsiType>newLinkedHashSet());
|
||||
return flattened.toArray(createArray(flattened.size()));
|
||||
final Set<PsiType> flattenConjuncts = PsiCapturedWildcardType.guard.doPreventingRecursion(conjuncts, true, new Computable<Set<PsiType>>() {
|
||||
@Override
|
||||
public Set<PsiType> compute() {
|
||||
return flatten(conjuncts, ContainerUtil.<PsiType>newLinkedHashSet());
|
||||
}
|
||||
});
|
||||
if (flattenConjuncts == null) {
|
||||
return conjuncts;
|
||||
}
|
||||
return flattenConjuncts.toArray(createArray(flattenConjuncts.size()));
|
||||
}
|
||||
catch (NoSuchElementException e) {
|
||||
throw new RuntimeException(Arrays.toString(conjuncts), e);
|
||||
|
||||
@@ -609,8 +609,8 @@ public final class PsiUtil extends PsiUtilCore {
|
||||
* would be equivalent
|
||||
*/
|
||||
public static boolean equalOnEquivalentClasses(PsiClassType thisClassType, @NotNull PsiClass aClass, PsiClassType otherClassType, @NotNull PsiClass bClass) {
|
||||
final PsiClassType capture1 = (PsiClassType)captureToplevelWildcards(thisClassType, aClass);
|
||||
final PsiClassType capture2 = (PsiClassType)captureToplevelWildcards(otherClassType, bClass);
|
||||
final PsiClassType capture1 = PsiCapturedWildcardType.isNoCapture() ? thisClassType : (PsiClassType)captureToplevelWildcards(thisClassType, aClass);
|
||||
final PsiClassType capture2 = PsiCapturedWildcardType.isNoCapture() ? otherClassType : (PsiClassType)captureToplevelWildcards(otherClassType, bClass);
|
||||
|
||||
final PsiClassType.ClassResolveResult result1 = capture1.resolveGenerics();
|
||||
final PsiClassType.ClassResolveResult result2 = capture2.resolveGenerics();
|
||||
@@ -806,7 +806,7 @@ public final class PsiUtil extends PsiUtilCore {
|
||||
PsiType originalBound = !((PsiWildcardType)substituted).isSuper() ? ((PsiWildcardType)substituted).getBound() : null;
|
||||
glb = originalBound;
|
||||
for (PsiType boundType : boundTypes) {
|
||||
PsiType substitutedBoundType = captureSubstitutor.substitute(boundType);
|
||||
final PsiType substitutedBoundType = captureSubstitutor.substitute(boundType);
|
||||
if (substitutedBoundType != null && !(substitutedBoundType instanceof PsiWildcardType) &&
|
||||
!substitutedBoundType.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) {
|
||||
if (originalBound instanceof PsiArrayType &&
|
||||
@@ -816,16 +816,11 @@ public final class PsiUtil extends PsiUtilCore {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (originalBound == null ||
|
||||
!TypeConversionUtil.erasure(substitutedBoundType).isAssignableFrom(TypeConversionUtil.erasure(originalBound)) &&
|
||||
!TypeConversionUtil.erasure(substitutedBoundType).isAssignableFrom(originalBound)) { //erasure is essential to avoid infinite recursion
|
||||
|
||||
if (glb == null) {
|
||||
glb = substitutedBoundType;
|
||||
}
|
||||
else {
|
||||
glb = GenericsUtil.getGreatestLowerBound(glb, substitutedBoundType);
|
||||
}
|
||||
if (glb == null) {
|
||||
glb = substitutedBoundType;
|
||||
}
|
||||
else {
|
||||
glb = GenericsUtil.getGreatestLowerBound(glb, substitutedBoundType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -958,7 +958,8 @@ public class TypeConversionUtil {
|
||||
PsiTypeParameter rp = ri.next();
|
||||
final PsiType typeLeft = leftSubstitutor.substitute(lp);
|
||||
if (typeLeft == null) continue;
|
||||
final PsiType typeRight = rightSubstitutor.substituteWithBoundsPromotion(rp);
|
||||
final PsiType typeRight = PsiCapturedWildcardType.isNoCapture() ? rightSubstitutor.substitute(rp)
|
||||
: rightSubstitutor.substituteWithBoundsPromotion(rp);
|
||||
if (typeRight == null) {
|
||||
// compatibility feature: allow to assign raw types to generic ones
|
||||
return allowUncheckedConversion;
|
||||
|
||||
@@ -52,9 +52,9 @@ class Test {
|
||||
}*/
|
||||
|
||||
abstract class D<T extends Throwable & Runnable> {
|
||||
<error descr="'foo(T, D<? extends Runnable>)' clashes with 'foo(T, D<? extends Throwable>)'; both methods have same erasure">abstract <T extends Serializable & Comparable<?>> void foo(T x, D<? extends Runnable> y)</error>;
|
||||
<error descr="'foo(T, D<? extends Runnable>)' is already defined in 'Test.D'">abstract <T extends Serializable & Comparable<?>> void foo(T x, D<? extends Runnable> y)</error>;
|
||||
|
||||
abstract <T extends Serializable & Comparable<?>> void foo(T x, D<? extends Throwable> y);
|
||||
<error descr="'foo(T, D<? extends Throwable>)' is already defined in 'Test.D'">abstract <T extends Serializable & Comparable<?>> void foo(T x, D<? extends Throwable> y)</error>;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,8 +62,8 @@ class Test {
|
||||
interface IB {}
|
||||
void testExtendsOrder() {
|
||||
class E<T extends IA & IB> {
|
||||
<error descr="'foo(E<? extends IA>)' clashes with 'foo(E<? extends IB>)'; both methods have same erasure">void foo(E<? extends IA> x)</error> {}
|
||||
void foo(E<? extends IB> x) {}
|
||||
<error descr="'foo(E<? extends IA>)' is already defined in 'E'">void foo(E<? extends IA> x)</error> {}
|
||||
<error descr="'foo(E<? extends IB>)' is already defined in 'E'">void foo(E<? extends IB> x)</error> {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,9 +52,9 @@ class Test {
|
||||
}*/
|
||||
|
||||
abstract class D<T extends Throwable & Runnable> {
|
||||
<error descr="'foo(T, D<? extends Runnable>)' clashes with 'foo(T, D<? extends Throwable>)'; both methods have same erasure">abstract <T extends Serializable & Comparable<?>> void foo(T x, D<? extends Runnable> y)</error>;
|
||||
<error descr="'foo(T, D<? extends Runnable>)' is already defined in 'Test.D'">abstract <T extends Serializable & Comparable<?>> void foo(T x, D<? extends Runnable> y)</error>;
|
||||
|
||||
abstract <T extends Serializable & Comparable<?>> void foo(T x, D<? extends Throwable> y);
|
||||
<error descr="'foo(T, D<? extends Throwable>)' is already defined in 'Test.D'">abstract <T extends Serializable & Comparable<?>> void foo(T x, D<? extends Throwable> y)</error>;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,8 +62,8 @@ class Test {
|
||||
interface IB {}
|
||||
void testExtendsOrder() {
|
||||
class E<T extends IA & IB> {
|
||||
<error descr="'foo(E<? extends IA>)' clashes with 'foo(E<? extends IB>)'; both methods have same erasure">void foo(E<? extends IA> x)</error> {}
|
||||
void foo(E<? extends IB> x) {}
|
||||
<error descr="'foo(E<? extends IA>)' is already defined in 'E'">void foo(E<? extends IA> x)</error> {}
|
||||
<error descr="'foo(E<? extends IB>)' is already defined in 'E'">void foo(E<? extends IB> x)</error> {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
class A<T extends Iterable<?>>{
|
||||
T get() {return null;}
|
||||
T x;
|
||||
void foo(A<? extends Iterable<String> > a){
|
||||
String s = bar(a.get());
|
||||
String s1 = bar(a.x);
|
||||
}
|
||||
<Tb> Tb bar(Iterable<Tb> a){
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
import java.util.*;
|
||||
|
||||
interface A<T extends A<? extends A<T>>> { }
|
||||
|
||||
class C {
|
||||
void foo(List<A<? extends A<?>>> x){
|
||||
List<A<?>> y = x;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
import java.util.List;
|
||||
|
||||
interface A<T extends List<String>> {
|
||||
T m();
|
||||
}
|
||||
|
||||
abstract class C {
|
||||
abstract <S> A<? extends S> foo();
|
||||
void bar() {
|
||||
this.<List<?>>foo().m().get(0).toLowerCase();
|
||||
}
|
||||
}
|
||||
@@ -922,4 +922,16 @@ public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase {
|
||||
public void testDistinguishTypeArgs() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testRecursiveCapturedWildcardTypes() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testRecursiveCapturedWildcardTypesIDEA139167() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testRecursiveCapturedWildcardTypesIDEA139157() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user