Don't approximate captured types while substitute them in upper bound position
This commit is contained in:
+8
-8
@@ -12,15 +12,15 @@ class A<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun foo2(a: A<out CharSequence>, b: A<in CharSequence>) {
|
fun foo2(a: A<out CharSequence>, b: A<in CharSequence>) {
|
||||||
a.foo1(Out<CharSequence>())
|
a.foo1(<!TYPE_MISMATCH!>Out<CharSequence>()<!>)
|
||||||
a.foo1<Out<CharSequence>>(Out())
|
a.foo1<<!UPPER_BOUND_VIOLATED!>Out<CharSequence><!>>(Out())
|
||||||
|
|
||||||
a.foo1(Out())
|
a.foo1(Out())
|
||||||
a.foo1(Out<Nothing>())
|
a.foo1(Out<Nothing>())
|
||||||
|
|
||||||
a.foo2(Inv())
|
a.foo2(Inv())
|
||||||
a.foo2(Inv<CharSequence>())
|
a.foo2(<!TYPE_MISMATCH!>Inv<CharSequence>()<!>)
|
||||||
a.foo2<Inv<CharSequence>>(Inv())
|
a.foo2<<!UPPER_BOUND_VIOLATED!>Inv<CharSequence><!>>(<!TYPE_MISMATCH!>Inv()<!>)
|
||||||
|
|
||||||
a.foo3(In())
|
a.foo3(In())
|
||||||
a.foo3(In<CharSequence>())
|
a.foo3(In<CharSequence>())
|
||||||
@@ -31,12 +31,12 @@ fun foo2(a: A<out CharSequence>, b: A<in CharSequence>) {
|
|||||||
b.foo1<Out<CharSequence>>(Out())
|
b.foo1<Out<CharSequence>>(Out())
|
||||||
|
|
||||||
b.foo2(Inv())
|
b.foo2(Inv())
|
||||||
b.foo2(Inv<CharSequence>())
|
b.foo2(<!TYPE_MISMATCH!>Inv<CharSequence>()<!>)
|
||||||
b.foo2<Inv<CharSequence>>(Inv())
|
b.foo2<<!UPPER_BOUND_VIOLATED!>Inv<CharSequence><!>>(<!TYPE_MISMATCH!>Inv()<!>)
|
||||||
|
|
||||||
|
|
||||||
b.foo3(In<CharSequence>())
|
b.foo3(<!TYPE_MISMATCH!>In<CharSequence>()<!>)
|
||||||
b.foo3<In<CharSequence>>(In())
|
b.foo3<<!UPPER_BOUND_VIOLATED!>In<CharSequence><!>>(In())
|
||||||
|
|
||||||
b.foo3(In<Any?>())
|
b.foo3(In<Any?>())
|
||||||
b.foo3(In())
|
b.foo3(In())
|
||||||
|
|||||||
@@ -20,10 +20,12 @@ import kotlin.annotations.jvm.Mutable;
|
|||||||
import kotlin.annotations.jvm.ReadOnly;
|
import kotlin.annotations.jvm.ReadOnly;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.SourceElement;
|
import org.jetbrains.kotlin.descriptors.SourceElement;
|
||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl;
|
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl;
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -55,7 +57,7 @@ public class DescriptorSubstitutor {
|
|||||||
@NotNull @Mutable List<TypeParameterDescriptor> result,
|
@NotNull @Mutable List<TypeParameterDescriptor> result,
|
||||||
@Nullable boolean[] wereChanges
|
@Nullable boolean[] wereChanges
|
||||||
) {
|
) {
|
||||||
Map<TypeConstructor, TypeProjection> mutableSubstitution = new HashMap<TypeConstructor, TypeProjection>();
|
Map<TypeConstructor, TypeProjection> mutableSubstitutionMap = new HashMap<TypeConstructor, TypeProjection>();
|
||||||
|
|
||||||
Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> substitutedMap = new HashMap<TypeParameterDescriptor, TypeParameterDescriptorImpl>();
|
Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> substitutedMap = new HashMap<TypeParameterDescriptor, TypeParameterDescriptorImpl>();
|
||||||
int index = 0;
|
int index = 0;
|
||||||
@@ -71,20 +73,26 @@ public class DescriptorSubstitutor {
|
|||||||
descriptor.getStorageManager()
|
descriptor.getStorageManager()
|
||||||
);
|
);
|
||||||
|
|
||||||
mutableSubstitution.put(descriptor.getTypeConstructor(), new TypeProjectionImpl(substituted.getDefaultType()));
|
mutableSubstitutionMap.put(descriptor.getTypeConstructor(), new TypeProjectionImpl(substituted.getDefaultType()));
|
||||||
|
|
||||||
substitutedMap.put(descriptor, substituted);
|
substitutedMap.put(descriptor, substituted);
|
||||||
result.add(substituted);
|
result.add(substituted);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeSubstitutor substitutor = TypeSubstitutor.createChainedSubstitutor(
|
TypeConstructorSubstitution mutableSubstitution = TypeConstructorSubstitution.createByConstructorsMap(mutableSubstitutionMap);
|
||||||
originalSubstitution, TypeConstructorSubstitution.createByConstructorsMap(mutableSubstitution)
|
TypeSubstitutor substitutor = TypeSubstitutor.createChainedSubstitutor(originalSubstitution, mutableSubstitution);
|
||||||
);
|
TypeSubstitutor nonApproximatingSubstitutor =
|
||||||
|
TypeSubstitutor.createChainedSubstitutor(originalSubstitution.replaceWithNonApproximating(), mutableSubstitution);
|
||||||
|
|
||||||
for (TypeParameterDescriptor descriptor : typeParameters) {
|
for (TypeParameterDescriptor descriptor : typeParameters) {
|
||||||
TypeParameterDescriptorImpl substituted = substitutedMap.get(descriptor);
|
TypeParameterDescriptorImpl substituted = substitutedMap.get(descriptor);
|
||||||
for (KotlinType upperBound : descriptor.getUpperBounds()) {
|
for (KotlinType upperBound : descriptor.getUpperBounds()) {
|
||||||
KotlinType substitutedBound = substitutor.substitute(upperBound, Variance.OUT_VARIANCE);
|
ClassifierDescriptor upperBoundDeclaration = upperBound.getConstructor().getDeclarationDescriptor();
|
||||||
|
TypeSubstitutor boundSubstitutor = upperBoundDeclaration instanceof TypeParameterDescriptor && TypeUtilsKt.hasTypeParameterRecursiveBounds((TypeParameterDescriptor) upperBoundDeclaration)
|
||||||
|
? substitutor
|
||||||
|
: nonApproximatingSubstitutor;
|
||||||
|
|
||||||
|
KotlinType substitutedBound = boundSubstitutor.substitute(upperBound, Variance.OUT_VARIANCE);
|
||||||
if (substitutedBound == null) return null;
|
if (substitutedBound == null) return null;
|
||||||
|
|
||||||
if (substitutedBound != upperBound && wereChanges != null) {
|
if (substitutedBound != upperBound && wereChanges != null) {
|
||||||
|
|||||||
@@ -42,6 +42,16 @@ abstract class TypeSubstitution {
|
|||||||
open fun filterAnnotations(annotations: Annotations) = annotations
|
open fun filterAnnotations(annotations: Annotations) = annotations
|
||||||
|
|
||||||
fun buildSubstitutor(): TypeSubstitutor = TypeSubstitutor.create(this)
|
fun buildSubstitutor(): TypeSubstitutor = TypeSubstitutor.create(this)
|
||||||
|
|
||||||
|
fun replaceWithNonApproximating() = object : TypeSubstitution() {
|
||||||
|
override fun get(key: KotlinType) = this@TypeSubstitution[key]
|
||||||
|
override fun approximateCapturedTypes() = false
|
||||||
|
override fun approximateContravariantCapturedTypes() = false
|
||||||
|
override fun filterAnnotations(annotations: Annotations) = this@TypeSubstitution.filterAnnotations(annotations)
|
||||||
|
override fun prepareTopLevelType(topLevelType: KotlinType, position: Variance) =
|
||||||
|
this@TypeSubstitution.prepareTopLevelType(topLevelType, position)
|
||||||
|
override fun isEmpty() = this@TypeSubstitution.isEmpty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class TypeConstructorSubstitution : TypeSubstitution() {
|
abstract class TypeConstructorSubstitution : TypeSubstitution() {
|
||||||
|
|||||||
@@ -216,6 +216,7 @@ private fun KotlinType.extractTypeParametersFromUpperBounds(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmOverloads
|
||||||
fun hasTypeParameterRecursiveBounds(
|
fun hasTypeParameterRecursiveBounds(
|
||||||
typeParameter: TypeParameterDescriptor,
|
typeParameter: TypeParameterDescriptor,
|
||||||
selfConstructor: TypeConstructor? = null,
|
selfConstructor: TypeConstructor? = null,
|
||||||
|
|||||||
Reference in New Issue
Block a user