Fix StackOverflowError while mapping recursive intersection-type
#KT-10972 Fixed
This commit is contained in:
@@ -76,6 +76,7 @@ import org.jetbrains.kotlin.serialization.deserialization.DeserializedType;
|
|||||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor;
|
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor;
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor;
|
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor;
|
||||||
import org.jetbrains.kotlin.types.*;
|
import org.jetbrains.kotlin.types.*;
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions;
|
import org.jetbrains.kotlin.util.OperatorNameConventions;
|
||||||
import org.jetbrains.org.objectweb.asm.Type;
|
import org.jetbrains.org.objectweb.asm.Type;
|
||||||
import org.jetbrains.org.objectweb.asm.commons.Method;
|
import org.jetbrains.org.objectweb.asm.commons.Method;
|
||||||
@@ -429,6 +430,15 @@ public class KotlinTypeMapper {
|
|||||||
TypeConstructor constructor = jetType.getConstructor();
|
TypeConstructor constructor = jetType.getConstructor();
|
||||||
if (constructor instanceof IntersectionTypeConstructor) {
|
if (constructor instanceof IntersectionTypeConstructor) {
|
||||||
jetType = CommonSupertypes.commonSupertype(new ArrayList<KotlinType>(constructor.getSupertypes()));
|
jetType = CommonSupertypes.commonSupertype(new ArrayList<KotlinType>(constructor.getSupertypes()));
|
||||||
|
|
||||||
|
// interface In<in E>
|
||||||
|
// open class A : In<A>
|
||||||
|
// open class B : In<B>
|
||||||
|
// commonSupertype(A, B) = In<A & B>
|
||||||
|
// So replace arguments with star-projections to prevent infinite recursive mapping
|
||||||
|
// It's not very important because such types anyway are prohibited in declarations
|
||||||
|
jetType = TypeUtilsKt.replaceArgumentsWithStarProjections(jetType);
|
||||||
|
|
||||||
constructor = jetType.getConstructor();
|
constructor = jetType.getConstructor();
|
||||||
}
|
}
|
||||||
DeclarationDescriptor descriptor = constructor.getDeclarationDescriptor();
|
DeclarationDescriptor descriptor = constructor.getDeclarationDescriptor();
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
interface In<in E>
|
||||||
|
open class A : In<A>
|
||||||
|
open class B : In<B>
|
||||||
|
|
||||||
|
inline fun <reified T : Any> select(x: T, y: T) = T::class.java.simpleName
|
||||||
|
|
||||||
|
// This test checks mostly that no StackOverflow happens while mapping type argument of select-call (In<A & B>)
|
||||||
|
// See KT-10972
|
||||||
|
fun foo(): String = select(A(), B())
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
if (foo() != "In") return "fail"
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -12193,6 +12193,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nestedIntersection.kt")
|
||||||
|
public void testNestedIntersection() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/nestedIntersection.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("objectCaptureOuterConstructorProperty.kt")
|
@TestMetadata("objectCaptureOuterConstructorProperty.kt")
|
||||||
public void testObjectCaptureOuterConstructorProperty() throws Exception {
|
public void testObjectCaptureOuterConstructorProperty() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/objectCaptureOuterConstructorProperty.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/objectCaptureOuterConstructorProperty.kt");
|
||||||
|
|||||||
+1
-24
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.types.*
|
|||||||
import org.jetbrains.kotlin.types.Variance.*
|
import org.jetbrains.kotlin.types.Variance.*
|
||||||
import org.jetbrains.kotlin.types.typeUtil.createProjection
|
import org.jetbrains.kotlin.types.typeUtil.createProjection
|
||||||
import org.jetbrains.kotlin.types.typeUtil.replaceAnnotations
|
import org.jetbrains.kotlin.types.typeUtil.replaceAnnotations
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections
|
||||||
import org.jetbrains.kotlin.utils.sure
|
import org.jetbrains.kotlin.utils.sure
|
||||||
import org.jetbrains.kotlin.utils.toReadOnlyList
|
import org.jetbrains.kotlin.utils.toReadOnlyList
|
||||||
|
|
||||||
@@ -415,27 +416,3 @@ internal fun TypeParameterDescriptor.getErasedUpperBound(
|
|||||||
return defaultValue()
|
return defaultValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KotlinType.replaceArgumentsWithStarProjections(): KotlinType {
|
|
||||||
if (constructor.parameters.isEmpty() || constructor.declarationDescriptor == null) return this
|
|
||||||
|
|
||||||
// We could just create JetTypeImpl with current type constructor and star projections,
|
|
||||||
// but we want to preserve flexibility of type, and that it what TypeSubstitutor does
|
|
||||||
return TypeSubstitutor.create(ConstantStarSubstitution).substitute(this, Variance.INVARIANT)!!
|
|
||||||
}
|
|
||||||
|
|
||||||
private object ConstantStarSubstitution : TypeSubstitution() {
|
|
||||||
override fun get(key: KotlinType): TypeProjection? {
|
|
||||||
// Let substitutor deal with flexibility
|
|
||||||
if (key.isFlexible()) return null
|
|
||||||
|
|
||||||
val newProjections = key.constructor.parameters.map(::StarProjectionImpl)
|
|
||||||
|
|
||||||
val substitution = TypeConstructorSubstitution.create(key.constructor, newProjections)
|
|
||||||
|
|
||||||
return TypeProjectionImpl(
|
|
||||||
TypeSubstitutor.create(substitution).substitute(key.constructor.declarationDescriptor!!.defaultType, Variance.INVARIANT)!!
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isEmpty() = false
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -154,3 +154,28 @@ fun KotlinType.getImmediateSuperclassNotAny(): KotlinType? {
|
|||||||
|
|
||||||
fun KotlinType.asTypeProjection(): TypeProjection = TypeProjectionImpl(this)
|
fun KotlinType.asTypeProjection(): TypeProjection = TypeProjectionImpl(this)
|
||||||
fun KotlinType.contains(predicate: (KotlinType) -> Boolean) = TypeUtils.contains(this, predicate)
|
fun KotlinType.contains(predicate: (KotlinType) -> Boolean) = TypeUtils.contains(this, predicate)
|
||||||
|
|
||||||
|
fun KotlinType.replaceArgumentsWithStarProjections(): KotlinType {
|
||||||
|
if (constructor.parameters.isEmpty() || constructor.declarationDescriptor == null) return this
|
||||||
|
|
||||||
|
// We could just create JetTypeImpl with current type constructor and star projections,
|
||||||
|
// but we want to preserve flexibility of type, and that it what TypeSubstitutor does
|
||||||
|
return TypeSubstitutor.create(ConstantStarSubstitution).substitute(this, Variance.INVARIANT)!!
|
||||||
|
}
|
||||||
|
|
||||||
|
private object ConstantStarSubstitution : TypeSubstitution() {
|
||||||
|
override fun get(key: KotlinType): TypeProjection? {
|
||||||
|
// Let substitutor deal with flexibility
|
||||||
|
if (key.isFlexible()) return null
|
||||||
|
|
||||||
|
val newProjections = key.constructor.parameters.map(::StarProjectionImpl)
|
||||||
|
|
||||||
|
val substitution = TypeConstructorSubstitution.create(key.constructor, newProjections)
|
||||||
|
|
||||||
|
return TypeProjectionImpl(
|
||||||
|
TypeSubstitutor.create(substitution).substitute(key.constructor.declarationDescriptor!!.defaultType, Variance.INVARIANT)!!
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isEmpty() = false
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user