From 3b168651525890b658baa50d65b5761aa2f4ac73 Mon Sep 17 00:00:00 2001 From: Victor Petukhov Date: Wed, 7 Jul 2021 14:01:26 +0300 Subject: [PATCH] Don't approximate captured types while substitute them in upper bound position --- .../projectionsScope/typeParameterBounds.kt | 16 +++++++-------- .../kotlin/types/DescriptorSubstitutor.java | 20 +++++++++++++------ .../kotlin/types/TypeSubstitution.kt | 10 ++++++++++ .../org/jetbrains/kotlin/types/TypeUtils.kt | 1 + 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/typeParameterBounds.kt b/compiler/testData/diagnostics/tests/generics/projectionsScope/typeParameterBounds.kt index dd6ce679c4e..da3c5bfd356 100644 --- a/compiler/testData/diagnostics/tests/generics/projectionsScope/typeParameterBounds.kt +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/typeParameterBounds.kt @@ -12,15 +12,15 @@ class A { } fun foo2(a: A, b: A) { - a.foo1(Out()) - a.foo1>(Out()) + a.foo1(Out()) + a.foo1<Out>(Out()) a.foo1(Out()) a.foo1(Out()) a.foo2(Inv()) - a.foo2(Inv()) - a.foo2>(Inv()) + a.foo2(Inv()) + a.foo2<Inv>(Inv()) a.foo3(In()) a.foo3(In()) @@ -31,12 +31,12 @@ fun foo2(a: A, b: A) { b.foo1>(Out()) b.foo2(Inv()) - b.foo2(Inv()) - b.foo2>(Inv()) + b.foo2(Inv()) + b.foo2<Inv>(Inv()) - b.foo3(In()) - b.foo3>(In()) + b.foo3(In()) + b.foo3<In>(In()) b.foo3(In()) b.foo3(In()) diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/DescriptorSubstitutor.java b/core/descriptors/src/org/jetbrains/kotlin/types/DescriptorSubstitutor.java index 147c34c6d22..ac648ab5805 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/DescriptorSubstitutor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/DescriptorSubstitutor.java @@ -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 result, @Nullable boolean[] wereChanges ) { - Map mutableSubstitution = new HashMap(); + Map mutableSubstitutionMap = new HashMap(); Map substitutedMap = new HashMap(); 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) { diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitution.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitution.kt index 835936ae961..0703b53d2d2 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitution.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitution.kt @@ -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() { diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt index e173bf075a0..3e873c24270 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt @@ -216,6 +216,7 @@ private fun KotlinType.extractTypeParametersFromUpperBounds( } } +@JvmOverloads fun hasTypeParameterRecursiveBounds( typeParameter: TypeParameterDescriptor, selfConstructor: TypeConstructor? = null,