diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index fd82b92332b..6978d0f060d 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -14387,6 +14387,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT public void testJavaNestedSamInterface() throws Exception { runTest("compiler/testData/codegen/box/javaInterop/generics/javaNestedSamInterface.kt"); } + + @TestMetadata("propertyVarianceConflict.kt") + public void testPropertyVarianceConflict() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/generics/propertyVarianceConflict.kt"); + } } @TestMetadata("compiler/testData/codegen/box/javaInterop/notNullAssertions") diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt index e84b1772233..656fe11cde8 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt @@ -330,9 +330,13 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen ktExpression.startOffsetSkippingComments, ktExpression.endOffset, origin, propertyIrType, getterSymbol, - getterDescriptor?.let { computeSubstitutedSyntheticAccessor(unwrappedPropertyDescriptor, it) }, + getterDescriptor?.let { + computeSubstitutedSyntheticAccessor(unwrappedPropertyDescriptor, it, unwrappedPropertyDescriptor.getter!!) + }, setterSymbol, - setterDescriptor?.let { computeSubstitutedSyntheticAccessor(unwrappedPropertyDescriptor, it) }, + setterDescriptor?.let { + computeSubstitutedSyntheticAccessor(unwrappedPropertyDescriptor, it, unwrappedPropertyDescriptor.setter!!) + }, typeArgumentsList, propertyReceiver, superQualifierSymbol diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt index fb8db9c749b..f3c33daf047 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt @@ -211,7 +211,9 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator IrStatementOrigin.GET_PROPERTY, superQualifierSymbol ).apply { - context.callToSubstitutedDescriptorMap[this] = computeSubstitutedSyntheticAccessor(descriptor, getMethodDescriptor) + context.callToSubstitutedDescriptorMap[this] = computeSubstitutedSyntheticAccessor( + descriptor, getMethodDescriptor, descriptor.getter!! + ) putTypeArguments(call.typeArguments) { it.toIrType() } dispatchReceiver = dispatchReceiverValue?.load() extensionReceiver = extensionReceiverValue?.load() diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/IrUtils.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/IrUtils.kt index 25d26f30966..2dfbe07e9d4 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/IrUtils.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/IrUtils.kt @@ -17,12 +17,10 @@ package org.jetbrains.kotlin.psi2ir.intermediate import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl -import org.jetbrains.kotlin.ir.expressions.typeParametersCount -import org.jetbrains.kotlin.types.TypeConstructor -import org.jetbrains.kotlin.types.TypeSubstitutor fun IrVariable.defaultLoad(): IrExpression = IrGetValueImpl(startOffset, endOffset, type, symbol) @@ -53,7 +51,11 @@ fun CallReceiver.adjustForCallee(callee: CallableMemberDescriptor): CallReceiver } -fun computeSubstitutedSyntheticAccessor(propertyDescriptor: PropertyDescriptor, accessorFunctionDescriptor: FunctionDescriptor): FunctionDescriptor { +fun computeSubstitutedSyntheticAccessor( + propertyDescriptor: PropertyDescriptor, + accessorFunctionDescriptor: FunctionDescriptor, + substitutedExtensionAccessorDescriptor: PropertyAccessorDescriptor +): FunctionDescriptor { if (propertyDescriptor.original == propertyDescriptor) return accessorFunctionDescriptor // Compute substituted accessor descriptor in case of Synthetic Java property `Java: getFoo() -> Kotlin: foo` @@ -65,38 +67,30 @@ fun computeSubstitutedSyntheticAccessor(propertyDescriptor: PropertyDescriptor, if (accessorFunctionDescriptor !is SimpleFunctionDescriptor) return accessorFunctionDescriptor - /** - * Consider java class like - * O.java - * class O { - * class I { - * public String getFoo() { ... } - * } - * } - * - * k.kt - * fun f(i: O.I) = i.foo - * - * - * for that case front end creates synthetic property foo - * private val O.I.foo get() = this.getFoo() - * - * So to get substituted descriptor for getFoo() we need to extract substitution from extension receiver type. - * To do so map Tx parameters onto Tx' arguments like - * T1' -> String - * T2' -> Int - * into - * T1 -> String - * T2 -> Int - */ + return copyTypesFromExtensionAccessor(accessorFunctionDescriptor, substitutedExtensionAccessorDescriptor) +} - val classDescriptor = accessorFunctionDescriptor.containingDeclaration as ClassDescriptor - val collectedTypeParameters = classDescriptor.typeConstructor.parameters.map { it.typeConstructor } - assert(collectedTypeParameters.size == propertyDescriptor.typeParametersCount) - - val typeArguments = propertyDescriptor.extensionReceiverParameter!!.type.arguments - assert(typeArguments.size == collectedTypeParameters.size) - - val typeSubstitutor = TypeSubstitutor.create(collectedTypeParameters.zip(typeArguments).toMap()) - return accessorFunctionDescriptor.substitute(typeSubstitutor) ?: error("Cannot substitute descriptor for $accessorFunctionDescriptor") -} \ No newline at end of file +// When computing substituted descriptor for a synthetic accessor of a synthesized property, +// the property descriptor's accessor field almost has the right type, +// except with extension receiver instead of dispatch receiver. Need to patch it up. +private fun copyTypesFromExtensionAccessor( + accessorFunctionDescriptor: SimpleFunctionDescriptor, + extensionAccessorDescriptor: PropertyAccessorDescriptor +): FunctionDescriptor = + SimpleFunctionDescriptorImpl.create( + accessorFunctionDescriptor.containingDeclaration, + accessorFunctionDescriptor.annotations, + accessorFunctionDescriptor.name, + accessorFunctionDescriptor.kind, + accessorFunctionDescriptor.source + ).apply { + initialize( + null, + extensionAccessorDescriptor.extensionReceiverParameter?.copy(this), + emptyList(), + extensionAccessorDescriptor.valueParameters.map { it.copy(this, it.name, it.index) }, + extensionAccessorDescriptor.returnType, + accessorFunctionDescriptor.modality, + accessorFunctionDescriptor.visibility + ) + } \ No newline at end of file diff --git a/compiler/testData/codegen/box/javaInterop/generics/propertyVarianceConflict.kt b/compiler/testData/codegen/box/javaInterop/generics/propertyVarianceConflict.kt new file mode 100644 index 00000000000..691d4908467 --- /dev/null +++ b/compiler/testData/codegen/box/javaInterop/generics/propertyVarianceConflict.kt @@ -0,0 +1,16 @@ +// TARGET_BACKEND: JVM + +// FILE: C.java + +class C { + public C getXx() { return this; } +} + +// FILE: test.kt + +fun test() { + var c: C = C() + c = c.xx +} + +fun box() = "OK" \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 93b2c91c4c6..33241571d11 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -15602,6 +15602,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { public void testJavaNestedSamInterface() throws Exception { runTest("compiler/testData/codegen/box/javaInterop/generics/javaNestedSamInterface.kt"); } + + @TestMetadata("propertyVarianceConflict.kt") + public void testPropertyVarianceConflict() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/generics/propertyVarianceConflict.kt"); + } } @TestMetadata("compiler/testData/codegen/box/javaInterop/notNullAssertions") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index fef5472297a..adbac04e30e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -15602,6 +15602,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes public void testJavaNestedSamInterface() throws Exception { runTest("compiler/testData/codegen/box/javaInterop/generics/javaNestedSamInterface.kt"); } + + @TestMetadata("propertyVarianceConflict.kt") + public void testPropertyVarianceConflict() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/generics/propertyVarianceConflict.kt"); + } } @TestMetadata("compiler/testData/codegen/box/javaInterop/notNullAssertions") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 05d1f2f0b6f..a68e4f13ebb 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -14387,6 +14387,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes public void testJavaNestedSamInterface() throws Exception { runTest("compiler/testData/codegen/box/javaInterop/generics/javaNestedSamInterface.kt"); } + + @TestMetadata("propertyVarianceConflict.kt") + public void testPropertyVarianceConflict() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/generics/propertyVarianceConflict.kt"); + } } @TestMetadata("compiler/testData/codegen/box/javaInterop/notNullAssertions")