IR: don't attempt to move defaults to actual in another module
May happen when a function in an `expect` class is aliased through an `actual typealias`; the matching declaration is filtered out in `ExpectedActualResolver.findActualForExpected` as it has no source.
This commit is contained in:
@@ -63,7 +63,12 @@ class ExpectDeclarationRemover(val symbolTable: ReferenceSymbolTable, private va
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val actualParameter = function.findActualForExpected().valueParameters[index]
|
// If the containing declaration is an `expect class` that matches an `actual typealias`,
|
||||||
|
// the `actual fun` or `actual constructor` for this may be in a different module.
|
||||||
|
// Nothing we can do with those.
|
||||||
|
// TODO they may not actually have the defaults though -- may be a frontend bug.
|
||||||
|
val actualFunction = function.findActualForExpected() ?: return
|
||||||
|
val actualParameter = actualFunction.valueParameters[index]
|
||||||
|
|
||||||
// Keep actual default value if present. They are generally not allowed but can be suppressed with
|
// Keep actual default value if present. They are generally not allowed but can be suppressed with
|
||||||
// @Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
|
// @Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
|
||||||
@@ -79,19 +84,19 @@ class ExpectDeclarationRemover(val symbolTable: ReferenceSymbolTable, private va
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrFunction.findActualForExpected(): IrFunction =
|
private fun IrFunction.findActualForExpected(): IrFunction? =
|
||||||
symbolTable.referenceFunction(descriptor.findActualForExpect()).owner
|
descriptor.findActualForExpect()?.let { symbolTable.referenceFunction(it).owner }
|
||||||
|
|
||||||
private fun IrClass.findActualForExpected(): IrClass =
|
private fun IrClass.findActualForExpected(): IrClass? =
|
||||||
symbolTable.referenceClass(descriptor.findActualForExpect()).owner
|
descriptor.findActualForExpect()?.let { symbolTable.referenceClass(it).owner }
|
||||||
|
|
||||||
private inline fun <reified T : MemberDescriptor> T.findActualForExpect() = with(ExpectedActualResolver) {
|
private inline fun <reified T : MemberDescriptor> T.findActualForExpect() = with(ExpectedActualResolver) {
|
||||||
val descriptor = this@findActualForExpect
|
val descriptor = this@findActualForExpect
|
||||||
|
|
||||||
if (!descriptor.isExpect) error(this)
|
if (!descriptor.isExpect) error(this)
|
||||||
|
|
||||||
findCompatibleActualForExpected(descriptor.module).singleOrNull() ?: error(descriptor)
|
findCompatibleActualForExpected(descriptor.module).singleOrNull()
|
||||||
} as T
|
} as T?
|
||||||
|
|
||||||
private fun IrExpression.remapExpectValueSymbols(): IrExpression {
|
private fun IrExpression.remapExpectValueSymbols(): IrExpression {
|
||||||
return this.transform(object : IrElementTransformerVoid() {
|
return this.transform(object : IrElementTransformerVoid() {
|
||||||
@@ -123,17 +128,17 @@ class ExpectDeclarationRemover(val symbolTable: ReferenceSymbolTable, private va
|
|||||||
return when (parent) {
|
return when (parent) {
|
||||||
is IrClass -> {
|
is IrClass -> {
|
||||||
assert(parameter == parent.thisReceiver)
|
assert(parameter == parent.thisReceiver)
|
||||||
parent.findActualForExpected().thisReceiver!!
|
parent.findActualForExpected()!!.thisReceiver!!
|
||||||
}
|
}
|
||||||
|
|
||||||
is IrFunction -> when (parameter) {
|
is IrFunction -> when (parameter) {
|
||||||
parent.dispatchReceiverParameter ->
|
parent.dispatchReceiverParameter ->
|
||||||
parent.findActualForExpected().dispatchReceiverParameter!!
|
parent.findActualForExpected()!!.dispatchReceiverParameter!!
|
||||||
parent.extensionReceiverParameter ->
|
parent.extensionReceiverParameter ->
|
||||||
parent.findActualForExpected().extensionReceiverParameter!!
|
parent.findActualForExpected()!!.extensionReceiverParameter!!
|
||||||
else -> {
|
else -> {
|
||||||
assert(parent.valueParameters[parameter.index] == parameter)
|
assert(parent.valueParameters[parameter.index] == parameter)
|
||||||
parent.findActualForExpected().valueParameters[parameter.index]
|
parent.findActualForExpected()!!.valueParameters[parameter.index]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
-1
@@ -1,5 +1,4 @@
|
|||||||
// !LANGUAGE: +MultiPlatformProjects
|
// !LANGUAGE: +MultiPlatformProjects
|
||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// WITH_REFLECT
|
// WITH_REFLECT
|
||||||
// FILE: main.kt
|
// FILE: main.kt
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// !LANGUAGE: +MultiPlatformProjects
|
||||||
|
// FILE: impl.kt
|
||||||
|
class A(val result: String = "OK")
|
||||||
|
|
||||||
|
// FILE: multiplatform.kt
|
||||||
|
expect class B(result: String = "FAIL")
|
||||||
|
|
||||||
|
actual typealias B = A
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
return B().result
|
||||||
|
}
|
||||||
+5
@@ -128,6 +128,11 @@ public class CompileKotlinAgainstKotlinTestGenerated extends AbstractCompileKotl
|
|||||||
runTest("compiler/testData/compileKotlinAgainstKotlin/enum.kt");
|
runTest("compiler/testData/compileKotlinAgainstKotlin/enum.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("expectClassActualTypeAlias.kt")
|
||||||
|
public void testExpectClassActualTypeAlias() throws Exception {
|
||||||
|
runTest("compiler/testData/compileKotlinAgainstKotlin/expectClassActualTypeAlias.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("inlineClassFromBinaryDependencies.kt")
|
@TestMetadata("inlineClassFromBinaryDependencies.kt")
|
||||||
public void testInlineClassFromBinaryDependencies() throws Exception {
|
public void testInlineClassFromBinaryDependencies() throws Exception {
|
||||||
runTest("compiler/testData/compileKotlinAgainstKotlin/inlineClassFromBinaryDependencies.kt");
|
runTest("compiler/testData/compileKotlinAgainstKotlin/inlineClassFromBinaryDependencies.kt");
|
||||||
|
|||||||
Generated
+5
@@ -123,6 +123,11 @@ public class IrCompileKotlinAgainstKotlinTestGenerated extends AbstractIrCompile
|
|||||||
runTest("compiler/testData/compileKotlinAgainstKotlin/enum.kt");
|
runTest("compiler/testData/compileKotlinAgainstKotlin/enum.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("expectClassActualTypeAlias.kt")
|
||||||
|
public void testExpectClassActualTypeAlias() throws Exception {
|
||||||
|
runTest("compiler/testData/compileKotlinAgainstKotlin/expectClassActualTypeAlias.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("inlineClassFromBinaryDependencies.kt")
|
@TestMetadata("inlineClassFromBinaryDependencies.kt")
|
||||||
public void testInlineClassFromBinaryDependencies() throws Exception {
|
public void testInlineClassFromBinaryDependencies() throws Exception {
|
||||||
runTest("compiler/testData/compileKotlinAgainstKotlin/inlineClassFromBinaryDependencies.kt");
|
runTest("compiler/testData/compileKotlinAgainstKotlin/inlineClassFromBinaryDependencies.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user