mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
separate capture conversion from substitution
This commit is contained in:
@@ -724,7 +724,11 @@ public final class PsiUtil extends PsiUtilCore {
|
||||
final PsiType substituted = substitutor.substitute(typeParameter);
|
||||
if (substituted instanceof PsiWildcardType) {
|
||||
if (substitutionMap == null) substitutionMap = new HashMap<PsiTypeParameter, PsiType>(substitutor.getSubstitutionMap());
|
||||
substitutionMap.put(typeParameter, PsiCapturedWildcardType.create((PsiWildcardType)substituted, context, typeParameter));
|
||||
substitutionMap.put(typeParameter,
|
||||
captureTypeParameterBounds(typeParameter, substituted, context,
|
||||
substitutor.put(typeParameter,
|
||||
PsiCapturedWildcardType
|
||||
.create((PsiWildcardType)substituted, context, typeParameter))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -742,6 +746,80 @@ public final class PsiUtil extends PsiUtilCore {
|
||||
return type;
|
||||
}
|
||||
|
||||
public static PsiType captureTypeParameterBounds(@NotNull PsiTypeParameter typeParameter, PsiType substituted,
|
||||
PsiElement context,
|
||||
PsiSubstitutor substitutor) {
|
||||
PsiType oldSubstituted = substituted;
|
||||
PsiElement captureContext = context;
|
||||
if (substituted instanceof PsiCapturedWildcardType) {
|
||||
final PsiCapturedWildcardType captured = (PsiCapturedWildcardType)substituted;
|
||||
substituted = captured.getWildcard();
|
||||
captureContext = captured.getContext();
|
||||
}
|
||||
if (substituted instanceof PsiWildcardType && !((PsiWildcardType)substituted).isSuper()) {
|
||||
PsiType originalBound = ((PsiWildcardType)substituted).getBound();
|
||||
PsiManager manager = typeParameter.getManager();
|
||||
final PsiType[] boundTypes = typeParameter.getExtendsListTypes();
|
||||
for (PsiType boundType : boundTypes) {
|
||||
PsiType substitutedBoundType = substitutor.substitute(boundType);
|
||||
PsiWildcardType wildcardType = (PsiWildcardType)substituted;
|
||||
if (substitutedBoundType != null && !(substitutedBoundType instanceof PsiWildcardType) &&
|
||||
!substitutedBoundType.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) {
|
||||
if (originalBound == null ||
|
||||
!TypeConversionUtil.erasure(substitutedBoundType).isAssignableFrom(TypeConversionUtil.erasure(originalBound)) &&
|
||||
!TypeConversionUtil.erasure(substitutedBoundType).isAssignableFrom(originalBound)) { //erasure is essential to avoid infinite recursion
|
||||
if (wildcardType.isExtends()) {
|
||||
final PsiType bound = wildcardType.getBound();
|
||||
if (bound instanceof PsiArrayType && substitutedBoundType instanceof PsiArrayType &&
|
||||
!bound.isAssignableFrom(substitutedBoundType) && !substitutedBoundType.isAssignableFrom(bound)) {
|
||||
continue;
|
||||
}
|
||||
final PsiType glb = GenericsUtil.getGreatestLowerBound(bound, substitutedBoundType);
|
||||
if (glb != null) {
|
||||
substituted = PsiWildcardType.createExtends(manager, glb);
|
||||
}
|
||||
}
|
||||
else {
|
||||
//unbounded
|
||||
substituted = substitutedBoundType instanceof PsiCapturedWildcardType
|
||||
? ((PsiCapturedWildcardType)substitutedBoundType).getWildcard()
|
||||
: PsiWildcardType.createExtends(manager, substitutedBoundType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (substituted instanceof PsiWildcardType && ((PsiWildcardType)substituted).isSuper()) {
|
||||
final PsiType[] boundTypes = typeParameter.getExtendsListTypes();
|
||||
PsiType glb = null;
|
||||
for (PsiType boundType : boundTypes) {
|
||||
final PsiType substitutedBound = substitutor.substitute(boundType);
|
||||
if (substitutedBound != null) {
|
||||
if (glb == null) {
|
||||
glb = substitutedBound;
|
||||
}
|
||||
else {
|
||||
glb = GenericsUtil.getGreatestLowerBound(glb, substitutedBound);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (glb != null && captureContext != null) {
|
||||
final PsiCapturedWildcardType capturedWildcardType = oldSubstituted instanceof PsiCapturedWildcardType
|
||||
? (PsiCapturedWildcardType)oldSubstituted
|
||||
: PsiCapturedWildcardType.create((PsiWildcardType)substituted, captureContext, typeParameter);
|
||||
capturedWildcardType.setUpperBound(glb);
|
||||
return capturedWildcardType;
|
||||
}
|
||||
}
|
||||
|
||||
if (captureContext != null) {
|
||||
LOG.assertTrue(substituted instanceof PsiWildcardType, substituted);
|
||||
substituted = oldSubstituted instanceof PsiCapturedWildcardType && substituted == ((PsiCapturedWildcardType)oldSubstituted).getWildcard()
|
||||
? oldSubstituted
|
||||
: PsiCapturedWildcardType.create((PsiWildcardType)substituted, captureContext, typeParameter);
|
||||
}
|
||||
return substituted;
|
||||
}
|
||||
|
||||
public static boolean isInsideJavadocComment(PsiElement element) {
|
||||
return PsiTreeUtil.getParentOfType(element, PsiDocComment.class, true) != null;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.light.LightTypeParameter;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import gnu.trove.THashMap;
|
||||
import gnu.trove.TObjectHashingStrategy;
|
||||
@@ -29,7 +28,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -53,6 +51,7 @@ public class PsiSubstitutorImpl implements PsiSubstitutor {
|
||||
};
|
||||
|
||||
private final Map<PsiTypeParameter, PsiType> mySubstitutionMap;
|
||||
private final SubstitutionVisitor mySimpleSubstitutionVisitor = new SubstitutionVisitor();
|
||||
|
||||
private PsiSubstitutorImpl(@NotNull Map<PsiTypeParameter, PsiType> map) {
|
||||
mySubstitutionMap = new THashMap<PsiTypeParameter, PsiType>(map, PSI_EQUIVALENCE);
|
||||
@@ -101,13 +100,13 @@ public class PsiSubstitutorImpl implements PsiSubstitutor {
|
||||
return null;
|
||||
}
|
||||
PsiUtil.ensureValidType(type);
|
||||
PsiType substituted = type.accept(myAddingBoundsSubstitutionVisitor);
|
||||
PsiType substituted = type.accept(mySimpleSubstitutionVisitor);
|
||||
return correctExternalSubstitution(substituted, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiType substituteWithBoundsPromotion(@NotNull PsiTypeParameter typeParameter) {
|
||||
return addBounds(substitute(typeParameter), typeParameter);
|
||||
return PsiUtil.captureTypeParameterBounds(typeParameter, substitute(typeParameter), null, this);
|
||||
}
|
||||
|
||||
public boolean equals(final Object o) {
|
||||
@@ -135,7 +134,7 @@ public class PsiSubstitutorImpl implements PsiSubstitutor {
|
||||
return PsiType.getJavaLangObject(typeParameter.getManager(), typeParameter.getResolveScope());
|
||||
}
|
||||
|
||||
private abstract static class SubstitutionVisitorBase extends PsiTypeMapper {
|
||||
private class SubstitutionVisitor extends PsiTypeMapper {
|
||||
@Override
|
||||
public PsiType visitCapturedWildcardType(PsiCapturedWildcardType type) {
|
||||
return visitWildcardType(type.getWildcard());
|
||||
@@ -181,7 +180,7 @@ public class PsiSubstitutorImpl implements PsiSubstitutor {
|
||||
}
|
||||
}
|
||||
|
||||
private static PsiType handleBoundComposition(PsiWildcardType wildcardType, PsiWildcardType bound) {
|
||||
private PsiType handleBoundComposition(PsiWildcardType wildcardType, PsiWildcardType bound) {
|
||||
final PsiType newBoundBound = bound.getBound();
|
||||
if (bound.isExtends() == wildcardType.isExtends()) {
|
||||
if (newBoundBound != null) {
|
||||
@@ -197,7 +196,7 @@ public class PsiSubstitutorImpl implements PsiSubstitutor {
|
||||
return PsiWildcardType.createUnbounded(wildcardType.getManager());
|
||||
}
|
||||
|
||||
private static PsiWildcardType rebound(PsiWildcardType type, PsiType newBound) {
|
||||
private PsiWildcardType rebound(PsiWildcardType type, PsiType newBound) {
|
||||
LOG.assertTrue(type.getBound() != null);
|
||||
LOG.assertTrue(newBound.isValid());
|
||||
|
||||
@@ -214,26 +213,6 @@ public class PsiSubstitutorImpl implements PsiSubstitutor {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract PsiType visitClassType(PsiClassType classType);
|
||||
|
||||
}
|
||||
|
||||
private final SubstitutionVisitor myAddingBoundsSubstitutionVisitor = new SubstitutionVisitor(SubstituteKind.ADD_BOUNDS);
|
||||
private final SubstitutionVisitor mySimpleSubstitutionVisitor = new SubstitutionVisitor(SubstituteKind.SIMPLE);
|
||||
|
||||
enum SubstituteKind {
|
||||
SIMPLE,
|
||||
ADD_BOUNDS
|
||||
}
|
||||
|
||||
private class SubstitutionVisitor extends SubstitutionVisitorBase {
|
||||
private SubstitutionVisitor(final SubstituteKind kind) {
|
||||
myKind = kind;
|
||||
}
|
||||
|
||||
private final SubstituteKind myKind;
|
||||
|
||||
@Override
|
||||
public PsiType visitClassType(PsiClassType classType) {
|
||||
final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics();
|
||||
@@ -262,15 +241,7 @@ public class PsiSubstitutorImpl implements PsiSubstitutor {
|
||||
}
|
||||
|
||||
private PsiType substituteTypeParameter(@NotNull PsiTypeParameter typeParameter) {
|
||||
PsiType t = getFromMap(typeParameter);
|
||||
if (myKind == SubstituteKind.SIMPLE) {
|
||||
return t;
|
||||
}
|
||||
else if (myKind == SubstituteKind.ADD_BOUNDS) {
|
||||
return addBounds(t, typeParameter);
|
||||
}
|
||||
|
||||
return t;
|
||||
return getFromMap(typeParameter);
|
||||
}
|
||||
|
||||
private PsiType substituteInternal(PsiType type) {
|
||||
@@ -284,30 +255,10 @@ public class PsiSubstitutorImpl implements PsiSubstitutor {
|
||||
if (original == null) {
|
||||
substMap.put(param, null);
|
||||
} else {
|
||||
/*boolean alreadyFound = false;
|
||||
for (Map.Entry<PsiTypeParameter, PsiType> entry : substMap.entrySet()) {
|
||||
if (original.equals(originalSubstitutor.substitute(entry.getKey()))) {
|
||||
substMap.put(param, entry.getValue());
|
||||
alreadyFound = true;
|
||||
}
|
||||
}
|
||||
if (alreadyFound) continue;*/
|
||||
PsiType substituted;
|
||||
if (original instanceof PsiWildcardType) {
|
||||
substituted = substituteInternal(original);
|
||||
if (substituted instanceof PsiCapturedWildcardType) {
|
||||
substituted = PsiCapturedWildcardType.create(((PsiCapturedWildcardType)substituted).getWildcard(), ((PsiCapturedWildcardType)substituted).getContext(), param);
|
||||
}
|
||||
else if (substituted instanceof PsiWildcardType) {
|
||||
PsiType bound = ((PsiWildcardType)substituted).getBound();
|
||||
if (bound instanceof PsiCapturedWildcardType) {
|
||||
bound = PsiCapturedWildcardType.create(((PsiCapturedWildcardType)bound).getWildcard(), ((PsiCapturedWildcardType)bound).getContext(), param);
|
||||
substituted = ((PsiWildcardType)substituted).isExtends() ? PsiWildcardType.createExtends(((PsiWildcardType)substituted).getManager(), bound)
|
||||
: PsiWildcardType.createSuper(((PsiWildcardType)substituted).getManager(), bound);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
substituted = substituteInternal(original);
|
||||
PsiType substituted = substituteInternal(original);
|
||||
if (original instanceof PsiWildcardType && substituted instanceof PsiCapturedWildcardType) {
|
||||
substituted = PsiCapturedWildcardType.create(((PsiCapturedWildcardType)substituted).getWildcard(),
|
||||
((PsiCapturedWildcardType)substituted).getContext(), param);
|
||||
}
|
||||
//if (substituted == null) return false;
|
||||
substMap.put(param, substituted);
|
||||
@@ -321,72 +272,6 @@ public class PsiSubstitutorImpl implements PsiSubstitutor {
|
||||
}
|
||||
}
|
||||
|
||||
private PsiType addBounds(PsiType substituted, @NotNull PsiTypeParameter typeParameter) {
|
||||
PsiType oldSubstituted = substituted;
|
||||
PsiElement captureContext = null;
|
||||
if (substituted instanceof PsiCapturedWildcardType) {
|
||||
final PsiCapturedWildcardType captured = (PsiCapturedWildcardType)substituted;
|
||||
substituted = captured.getWildcard();
|
||||
captureContext = captured.getContext();
|
||||
}
|
||||
if (substituted instanceof PsiWildcardType && !((PsiWildcardType)substituted).isSuper()) {
|
||||
PsiType originalBound = ((PsiWildcardType)substituted).getBound();
|
||||
PsiManager manager = typeParameter.getManager();
|
||||
final PsiType[] boundTypes = typeParameter.getExtendsListTypes();
|
||||
for (PsiType boundType : boundTypes) {
|
||||
PsiType substitutedBoundType = boundType.accept(mySimpleSubstitutionVisitor);
|
||||
PsiWildcardType wildcardType = (PsiWildcardType)substituted;
|
||||
if (substitutedBoundType != null && !(substitutedBoundType instanceof PsiWildcardType) && !substitutedBoundType.equalsToText(
|
||||
CommonClassNames.JAVA_LANG_OBJECT)) {
|
||||
if (originalBound == null ||
|
||||
!TypeConversionUtil.erasure(substitutedBoundType).isAssignableFrom(TypeConversionUtil.erasure(originalBound)) &&
|
||||
!TypeConversionUtil.erasure(substitutedBoundType).isAssignableFrom(originalBound)) { //erasure is essential to avoid infinite recursion
|
||||
if (wildcardType.isExtends()) {
|
||||
final PsiType bound = wildcardType.getBound();
|
||||
if (bound instanceof PsiArrayType && substitutedBoundType instanceof PsiArrayType &&
|
||||
!bound.isAssignableFrom(substitutedBoundType) && !substitutedBoundType.isAssignableFrom(bound)) {
|
||||
continue;
|
||||
}
|
||||
final PsiType glb = GenericsUtil.getGreatestLowerBound(bound, substitutedBoundType);
|
||||
if (glb != null) {
|
||||
substituted = PsiWildcardType.createExtends(manager, glb);
|
||||
}
|
||||
}
|
||||
else {
|
||||
//unbounded
|
||||
substituted = substitutedBoundType instanceof PsiCapturedWildcardType ? ((PsiCapturedWildcardType)substitutedBoundType).getWildcard() : PsiWildcardType.createExtends(manager, substitutedBoundType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (substituted instanceof PsiWildcardType && ((PsiWildcardType)substituted).isSuper()) {
|
||||
final PsiType[] boundTypes = typeParameter.getExtendsListTypes();
|
||||
PsiType glb = null;
|
||||
for (PsiType boundType : boundTypes) {
|
||||
final PsiType substitutedBound = boundType.accept(mySimpleSubstitutionVisitor);
|
||||
if (substitutedBound != null) {
|
||||
if (glb == null) {
|
||||
glb = substitutedBound;
|
||||
}
|
||||
else {
|
||||
glb = GenericsUtil.getGreatestLowerBound(glb, substitutedBound);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (glb != null && captureContext != null) {
|
||||
final PsiCapturedWildcardType capturedWildcardType = PsiCapturedWildcardType.create((PsiWildcardType)substituted, captureContext, typeParameter);
|
||||
capturedWildcardType.setUpperBound(glb);
|
||||
return capturedWildcardType;
|
||||
}
|
||||
}
|
||||
|
||||
if (captureContext != null) {
|
||||
substituted = oldSubstituted instanceof PsiCapturedWildcardType && substituted == ((PsiCapturedWildcardType)oldSubstituted).getWildcard()
|
||||
? oldSubstituted : PsiCapturedWildcardType.create((PsiWildcardType)substituted, captureContext, typeParameter);
|
||||
}
|
||||
return substituted;
|
||||
}
|
||||
|
||||
private PsiType correctExternalSubstitution(PsiType substituted, @NotNull PsiType original) {
|
||||
if (substituted != null) {
|
||||
return substituted;
|
||||
|
||||
+2
-2
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
package pck;
|
||||
|
||||
interface A<T>
|
||||
interface A<T>
|
||||
{
|
||||
T foo();
|
||||
}
|
||||
|
||||
interface B<T extends Cloneable> extends A<T> { }
|
||||
|
||||
class C<T extends A<?> & B<?>>
|
||||
class C<T extends A<? extends Cloneable> & B<?>>
|
||||
{
|
||||
void bar(T x)
|
||||
{
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ class SortTest<R extends Comparable<R>> implements Comparable<SortTest<R>> {
|
||||
SortTest<?> t2 = new SortTest<Integer>(0);
|
||||
list.add(t2);
|
||||
<error descr="Inferred type 'SortTest<?>' for type parameter 'T' is not within its bound; should implement 'java.lang.Comparable<? super SortTest<?>>'">Collections.sort(list)</error>;
|
||||
t1.compareTo<error descr="'compareTo(SortTest<capture<? extends java.lang.Comparable<capture<?>>>>)' in 'SortTest' cannot be applied to '(SortTest<capture<?>>)'">(t2)</error>;
|
||||
t1.compareTo<error descr="'compareTo(SortTest<capture<? extends java.lang.Comparable<capture<?>>>>)' in 'SortTest' cannot be applied to '(SortTest<capture<? extends java.lang.Comparable<capture<?>>>>)'">(t2)</error>;
|
||||
|
||||
//this should be OK
|
||||
SortTest<?>[] arr = new SortTest<?>[0];
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ class SortTest<R extends Comparable<R>> implements Comparable<SortTest<R>> {
|
||||
SortTest<?> t2 = new SortTest<Integer>(0);
|
||||
list.add(t2);
|
||||
Collections.sort<error descr="'sort(java.util.List<T>)' in 'java.util.Collections' cannot be applied to '(java.util.ArrayList<SortTest<?>>)'">(list)</error>;
|
||||
t1.compareTo<error descr="'compareTo(SortTest<capture<? extends java.lang.Comparable<capture<?>>>>)' in 'SortTest' cannot be applied to '(SortTest<capture<?>>)'">(t2)</error>;
|
||||
t1.compareTo<error descr="'compareTo(SortTest<capture<? extends java.lang.Comparable<capture<?>>>>)' in 'SortTest' cannot be applied to '(SortTest<capture<? extends java.lang.Comparable<capture<?>>>>)'">(t2)</error>;
|
||||
|
||||
//this should be OK
|
||||
SortTest<?>[] arr = new SortTest<?>[0];
|
||||
|
||||
Reference in New Issue
Block a user