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>) {
|
||||
a.foo1(Out<CharSequence>())
|
||||
a.foo1<Out<CharSequence>>(Out())
|
||||
a.foo1(<!TYPE_MISMATCH!>Out<CharSequence>()<!>)
|
||||
a.foo1<<!UPPER_BOUND_VIOLATED!>Out<CharSequence><!>>(Out())
|
||||
|
||||
a.foo1(Out())
|
||||
a.foo1(Out<Nothing>())
|
||||
|
||||
a.foo2(Inv())
|
||||
a.foo2(Inv<CharSequence>())
|
||||
a.foo2<Inv<CharSequence>>(Inv())
|
||||
a.foo2(<!TYPE_MISMATCH!>Inv<CharSequence>()<!>)
|
||||
a.foo2<<!UPPER_BOUND_VIOLATED!>Inv<CharSequence><!>>(<!TYPE_MISMATCH!>Inv()<!>)
|
||||
|
||||
a.foo3(In())
|
||||
a.foo3(In<CharSequence>())
|
||||
@@ -31,12 +31,12 @@ fun foo2(a: A<out CharSequence>, b: A<in CharSequence>) {
|
||||
b.foo1<Out<CharSequence>>(Out())
|
||||
|
||||
b.foo2(Inv())
|
||||
b.foo2(Inv<CharSequence>())
|
||||
b.foo2<Inv<CharSequence>>(Inv())
|
||||
b.foo2(<!TYPE_MISMATCH!>Inv<CharSequence>()<!>)
|
||||
b.foo2<<!UPPER_BOUND_VIOLATED!>Inv<CharSequence><!>>(<!TYPE_MISMATCH!>Inv()<!>)
|
||||
|
||||
|
||||
b.foo3(In<CharSequence>())
|
||||
b.foo3<In<CharSequence>>(In())
|
||||
b.foo3(<!TYPE_MISMATCH!>In<CharSequence>()<!>)
|
||||
b.foo3<<!UPPER_BOUND_VIOLATED!>In<CharSequence><!>>(In())
|
||||
|
||||
b.foo3(In<Any?>())
|
||||
b.foo3(In())
|
||||
|
||||
@@ -20,10 +20,12 @@ import kotlin.annotations.jvm.Mutable;
|
||||
import kotlin.annotations.jvm.ReadOnly;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement;
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl;
|
||||
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -55,7 +57,7 @@ public class DescriptorSubstitutor {
|
||||
@NotNull @Mutable List<TypeParameterDescriptor> result,
|
||||
@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>();
|
||||
int index = 0;
|
||||
@@ -71,20 +73,26 @@ public class DescriptorSubstitutor {
|
||||
descriptor.getStorageManager()
|
||||
);
|
||||
|
||||
mutableSubstitution.put(descriptor.getTypeConstructor(), new TypeProjectionImpl(substituted.getDefaultType()));
|
||||
mutableSubstitutionMap.put(descriptor.getTypeConstructor(), new TypeProjectionImpl(substituted.getDefaultType()));
|
||||
|
||||
substitutedMap.put(descriptor, substituted);
|
||||
result.add(substituted);
|
||||
}
|
||||
|
||||
TypeSubstitutor substitutor = TypeSubstitutor.createChainedSubstitutor(
|
||||
originalSubstitution, TypeConstructorSubstitution.createByConstructorsMap(mutableSubstitution)
|
||||
);
|
||||
TypeConstructorSubstitution mutableSubstitution = TypeConstructorSubstitution.createByConstructorsMap(mutableSubstitutionMap);
|
||||
TypeSubstitutor substitutor = TypeSubstitutor.createChainedSubstitutor(originalSubstitution, mutableSubstitution);
|
||||
TypeSubstitutor nonApproximatingSubstitutor =
|
||||
TypeSubstitutor.createChainedSubstitutor(originalSubstitution.replaceWithNonApproximating(), mutableSubstitution);
|
||||
|
||||
for (TypeParameterDescriptor descriptor : typeParameters) {
|
||||
TypeParameterDescriptorImpl substituted = substitutedMap.get(descriptor);
|
||||
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 != upperBound && wereChanges != null) {
|
||||
|
||||
@@ -42,6 +42,16 @@ abstract class TypeSubstitution {
|
||||
open fun filterAnnotations(annotations: Annotations) = annotations
|
||||
|
||||
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() {
|
||||
|
||||
@@ -216,6 +216,7 @@ private fun KotlinType.extractTypeParametersFromUpperBounds(
|
||||
}
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun hasTypeParameterRecursiveBounds(
|
||||
typeParameter: TypeParameterDescriptor,
|
||||
selfConstructor: TypeConstructor? = null,
|
||||
|
||||
Reference in New Issue
Block a user