From c350280e649281cb0615e729bbb33f9f32b768f8 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Wed, 12 Jul 2023 15:59:05 +0200 Subject: [PATCH] K2: fix enhancement building for Java methods with type parameters Before this commit, we copied each type parameter during method enhancement, while not copying the symbol. This led to symbol clashes in MPP scenarios and various other problems. Now we create a fully-functional type parameter copy in enhancement and perform a substitution of old type parameters with new ones in receiver type, value parameter types, return type, and type parameter upper bounds. #KT-59766 Fixed #KT-59738 Fixed --- ...LightTreeBlackBoxCodegenTestGenerated.java | 6 +++ .../FirPsiBlackBoxCodegenTestGenerated.java | 6 +++ .../java/enhancement/SignatureEnhancement.kt | 49 +++++++++++++++---- .../k2/javaMethodWithTypeParameter.kt | 42 ++++++++++++++++ .../IrBlackBoxCodegenTestGenerated.java | 6 +++ ...kBoxCodegenWithIrInlinerTestGenerated.java | 6 +++ .../LightAnalysisModeTestGenerated.java | 5 ++ 7 files changed, 110 insertions(+), 10 deletions(-) create mode 100644 compiler/testData/codegen/box/multiplatform/k2/javaMethodWithTypeParameter.kt diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java index 7188a4d43bc..6e2fd6e1ff1 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java @@ -33460,6 +33460,12 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr runTest("compiler/testData/codegen/box/multiplatform/k2/anonymousObjectAndSpecificImplementationInDeserializedIr.kt"); } + @Test + @TestMetadata("javaMethodWithTypeParameter.kt") + public void testJavaMethodWithTypeParameter() throws Exception { + runTest("compiler/testData/codegen/box/multiplatform/k2/javaMethodWithTypeParameter.kt"); + } + @Nested @TestMetadata("compiler/testData/codegen/box/multiplatform/k2/annotations") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java index 4798ae416a2..291f885c584 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java @@ -33460,6 +33460,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo runTest("compiler/testData/codegen/box/multiplatform/k2/anonymousObjectAndSpecificImplementationInDeserializedIr.kt"); } + @Test + @TestMetadata("javaMethodWithTypeParameter.kt") + public void testJavaMethodWithTypeParameter() throws Exception { + runTest("compiler/testData/codegen/box/multiplatform/k2/javaMethodWithTypeParameter.kt"); + } + @Nested @TestMetadata("compiler/testData/codegen/box/multiplatform/k2/annotations") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt index b18fde82208..204c0845991 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt @@ -31,6 +31,7 @@ import org.jetbrains.kotlin.fir.java.resolveIfJavaType import org.jetbrains.kotlin.fir.java.symbols.FirJavaOverriddenSyntheticPropertySymbol import org.jetbrains.kotlin.fir.java.toConeKotlinTypeProbablyFlexible import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider +import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptor import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag @@ -251,6 +252,9 @@ class FirSignatureEnhancement( val functionSymbol: FirFunctionSymbol<*> var isJavaRecordComponent = false + val typeParameterSubstitutionMap = mutableMapOf() + var typeParameterSubstitutor: ConeSubstitutorByMap? = null + val function = when (firMethod) { is FirJavaConstructor -> { val symbol = FirConstructorSymbol(methodId).also { functionSymbol = it } @@ -288,6 +292,7 @@ class FirSignatureEnhancement( moduleData = this@FirSignatureEnhancement.moduleData resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES origin = FirDeclarationOrigin.Enhancement + // TODO: we should set a new origin / containing declaration to type parameters (KT-60440) this.typeParameters += (enhancedTypeParameters ?: firMethod.typeParameters) } } @@ -297,14 +302,6 @@ class FirSignatureEnhancement( source = firMethod.source moduleData = this@FirSignatureEnhancement.moduleData origin = FirDeclarationOrigin.Enhancement - returnTypeRef = newReturnTypeRef - receiverParameter = newReceiverTypeRef?.let { receiverType -> - buildReceiverParameter { - typeRef = receiverType - annotations += firMethod.valueParameters.first().annotations - source = receiverType.source?.fakeElement(KtFakeSourceElementKind.ReceiverFromType) - } - } this.name = name!! status = firMethod.status @@ -316,10 +313,39 @@ class FirSignatureEnhancement( "Unexpected type parameter type: ${typeParameter::class.simpleName}" } - buildTypeParameterCopy(typeParameter) { + // TODO: we probably shouldn't build a copy second time. See performFirstRoundOfBoundsResolution (KT-60446) + val newTypeParameter = buildTypeParameterCopy(typeParameter) { origin = FirDeclarationOrigin.Enhancement + symbol = FirTypeParameterSymbol() containingDeclarationSymbol = functionSymbol } + typeParameterSubstitutionMap[typeParameter.symbol] = ConeTypeParameterTypeImpl( + newTypeParameter.symbol.toLookupTag(), isNullable = false + ) + newTypeParameter + } + if (typeParameterSubstitutionMap.isNotEmpty()) { + typeParameterSubstitutor = ConeSubstitutorByMap(typeParameterSubstitutionMap, session) + } + returnTypeRef = newReturnTypeRef.withReplacedConeType( + typeParameterSubstitutor?.substituteOrNull(newReturnTypeRef.coneType) + ) + val substitutedReceiverTypeRef = newReceiverTypeRef?.withReplacedConeType( + typeParameterSubstitutor?.substituteOrNull(newReturnTypeRef.coneType) + ) + receiverParameter = substitutedReceiverTypeRef?.let { receiverType -> + buildReceiverParameter { + typeRef = receiverType + annotations += firMethod.valueParameters.first().annotations + source = receiverType.source?.fakeElement(KtFakeSourceElementKind.ReceiverFromType) + } + } + typeParameters.forEach { typeParameter -> + typeParameter.replaceBounds( + typeParameter.bounds.map { boundTypeRef -> + boundTypeRef.withReplacedConeType(typeParameterSubstitutor?.substituteOrNull(boundTypeRef.coneType)) + } + ) } dispatchReceiverType = firMethod.dispatchReceiverType @@ -336,7 +362,9 @@ class FirSignatureEnhancement( containingFunctionSymbol = functionSymbol moduleData = this@FirSignatureEnhancement.moduleData origin = FirDeclarationOrigin.Enhancement - returnTypeRef = enhancedReturnType + returnTypeRef = enhancedReturnType.withReplacedConeType( + typeParameterSubstitutor?.substituteOrNull(enhancedReturnType.coneType) + ) this.name = valueParameter.name symbol = FirValueParameterSymbol(this.name) defaultValue = valueParameter.defaultValue @@ -388,6 +416,7 @@ class FirSignatureEnhancement( typeParametersCopy += if (typeParameter is FirTypeParameter) { initialBounds.add(typeParameter.bounds.toList()) buildTypeParameterCopy(typeParameter) { + // TODO: we should create a new symbol to avoid clashing (KT-60445) bounds.clear() typeParameter.bounds.mapTo(bounds) { it.resolveIfJavaType(session, javaTypeParameterStack, FirJavaTypeConversionMode.TYPE_PARAMETER_BOUND_FIRST_ROUND) diff --git a/compiler/testData/codegen/box/multiplatform/k2/javaMethodWithTypeParameter.kt b/compiler/testData/codegen/box/multiplatform/k2/javaMethodWithTypeParameter.kt new file mode 100644 index 00000000000..cf5a09eff40 --- /dev/null +++ b/compiler/testData/codegen/box/multiplatform/k2/javaMethodWithTypeParameter.kt @@ -0,0 +1,42 @@ +// LANGUAGE: +MultiPlatformProjects +// ISSUE: KT-59766 +// WITH_STDLIB +// TARGET_BACKEND: JVM_IR +// FULL_JDK + +// MODULE: lib-jvm +// FILE: lib.kt + +import java.util.concurrent.* + +fun CompletionStage.foo() { + handle { value, exception -> + + } +} + +// MODULE: jvm()()(lib-jvm) +// FILE: jvm.kt + +package kotlinx.coroutines.future + +import java.util.concurrent.* +import java.util.function.* + +fun CompletionStage.asDeferred() { + handle { value, exception -> + + } +} + +class ContinuationHandler : BiFunction { + override fun apply(result: T?, exception: Throwable?) { + + } +} + +fun box(): String { + val handler = ContinuationHandler() + CompletableFuture().asDeferred() + return "OK" +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index c5b0df402e9..41d94fa8e39 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -33460,6 +33460,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/multiplatform/k2/anonymousObjectAndSpecificImplementationInDeserializedIr.kt"); } + @Test + @TestMetadata("javaMethodWithTypeParameter.kt") + public void testJavaMethodWithTypeParameter() throws Exception { + runTest("compiler/testData/codegen/box/multiplatform/k2/javaMethodWithTypeParameter.kt"); + } + @Nested @TestMetadata("compiler/testData/codegen/box/multiplatform/k2/annotations") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java index b34747b2a51..f5bbe68d5f4 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java @@ -33460,6 +33460,12 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack runTest("compiler/testData/codegen/box/multiplatform/k2/anonymousObjectAndSpecificImplementationInDeserializedIr.kt"); } + @Test + @TestMetadata("javaMethodWithTypeParameter.kt") + public void testJavaMethodWithTypeParameter() throws Exception { + runTest("compiler/testData/codegen/box/multiplatform/k2/javaMethodWithTypeParameter.kt"); + } + @Nested @TestMetadata("compiler/testData/codegen/box/multiplatform/k2/annotations") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 299f260f981..dbeb7b8fbde 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -28487,6 +28487,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/multiplatform/k2/anonymousObjectAndSpecificImplementationInDeserializedIr.kt"); } + @TestMetadata("javaMethodWithTypeParameter.kt") + public void testJavaMethodWithTypeParameter() throws Exception { + runTest("compiler/testData/codegen/box/multiplatform/k2/javaMethodWithTypeParameter.kt"); + } + @TestMetadata("compiler/testData/codegen/box/multiplatform/k2/annotations") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)