IR: deal with conflicting variances in computeSubstitutedSyntheticAccessor

This commit is contained in:
Georgy Bronnikov
2020-04-06 21:25:52 +03:00
parent 5700da2bae
commit 9ccda31189
8 changed files with 77 additions and 41 deletions
@@ -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")
@@ -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
@@ -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()
@@ -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<T1> {
* class I<T2> {
* public String getFoo() { ... }
* }
* }
*
* k.kt
* fun f(i: O<String>.I<Int>) = i.foo
*
*
* for that case front end creates synthetic property foo
* private val <T1', T2'> O<T1'>.I<T2'>.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")
}
// 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
)
}
@@ -0,0 +1,16 @@
// TARGET_BACKEND: JVM
// FILE: C.java
class C<T> {
public C<? super T> getXx() { return this; }
}
// FILE: test.kt
fun test() {
var c: C<out Any?> = C()
c = c.xx
}
fun box() = "OK"
@@ -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")
@@ -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")
@@ -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")