IR: work around a bug in interface delegation descriptors
interface I {
fun f(x: Int = 1)
}
class C(val y: I) : I by y {
// implicit `override fun f(x: Int) = y.f(x)` has a default value for `x`
}
-- the only case where a function with overridden symbols has defaults.
This commit is contained in:
+24
-13
@@ -334,27 +334,38 @@ private fun IrFunction.generateDefaultsFunction(
|
|||||||
context: CommonBackendContext,
|
context: CommonBackendContext,
|
||||||
skipInlineMethods: Boolean,
|
skipInlineMethods: Boolean,
|
||||||
skipExternalMethods: Boolean
|
skipExternalMethods: Boolean
|
||||||
): IrFunction? = context.ir.defaultParameterDeclarationsCache[this] ?: when {
|
): IrFunction? {
|
||||||
skipInlineMethods && isInline -> null
|
if (skipInlineMethods && isInline) return null
|
||||||
skipExternalMethods && isExternalOrInheritedFromExternal() -> null
|
if (skipExternalMethods && isExternalOrInheritedFromExternal()) return null
|
||||||
valueParameters.any { it.defaultValue != null } ->
|
context.ir.defaultParameterDeclarationsCache[this]?.let { return it }
|
||||||
generateDefaultsFunctionImpl(context, IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER).also {
|
if (this is IrSimpleFunction) {
|
||||||
context.ir.defaultParameterDeclarationsCache[this] = it
|
|
||||||
}
|
|
||||||
this is IrSimpleFunction -> {
|
|
||||||
// If this is an override of a function with default arguments, produce a fake override of a default stub.
|
// If this is an override of a function with default arguments, produce a fake override of a default stub.
|
||||||
val overriddenStubs = overriddenSymbols.mapNotNull {
|
val overriddenStubs = overriddenSymbols.mapNotNull {
|
||||||
it.owner.generateDefaultsFunction(context, skipInlineMethods, skipExternalMethods)?.symbol as IrSimpleFunctionSymbol?
|
it.owner.generateDefaultsFunction(context, skipInlineMethods, skipExternalMethods)?.symbol as IrSimpleFunctionSymbol?
|
||||||
}
|
}
|
||||||
if (overriddenStubs.isNotEmpty())
|
if (overriddenStubs.isNotEmpty()) {
|
||||||
generateDefaultsFunctionImpl(context, IrDeclarationOrigin.FAKE_OVERRIDE).also {
|
return generateDefaultsFunctionImpl(context, IrDeclarationOrigin.FAKE_OVERRIDE).also {
|
||||||
(it as IrSimpleFunction).overriddenSymbols.addAll(overriddenStubs)
|
(it as IrSimpleFunction).overriddenSymbols.addAll(overriddenStubs)
|
||||||
context.ir.defaultParameterDeclarationsCache[this] = it
|
context.ir.defaultParameterDeclarationsCache[this] = it
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
null
|
|
||||||
}
|
}
|
||||||
else -> null
|
// Note: this is intentionally done *after* checking for overrides. While normally `override fun`s
|
||||||
|
// have no default parameters, there is an exception in case of interface delegation:
|
||||||
|
// interface I {
|
||||||
|
// fun f(x: Int = 1)
|
||||||
|
// }
|
||||||
|
// class C(val y: I) : I by y {
|
||||||
|
// // implicit `override fun f(x: Int) = y.f(x)` has a default value for `x`
|
||||||
|
// }
|
||||||
|
// Since this bug causes the metadata serializer to write the "has default value" flag into compiled
|
||||||
|
// binaries, it's way too late to fix it. Hence the workaround.
|
||||||
|
if (valueParameters.any { it.defaultValue != null }) {
|
||||||
|
return generateDefaultsFunctionImpl(context, IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER).also {
|
||||||
|
context.ir.defaultParameterDeclarationsCache[this] = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrFunction.generateDefaultsFunctionImpl(context: CommonBackendContext, newOrigin: IrDeclarationOrigin): IrFunction {
|
private fun IrFunction.generateDefaultsFunctionImpl(context: CommonBackendContext, newOrigin: IrDeclarationOrigin): IrFunction {
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// FILE: A.kt
|
||||||
|
package lib
|
||||||
|
|
||||||
|
interface A {
|
||||||
|
fun f(x: String = "OK"): String
|
||||||
|
}
|
||||||
|
|
||||||
|
class B : A {
|
||||||
|
override fun f(x: String) = x
|
||||||
|
}
|
||||||
|
|
||||||
|
class C(val x: A) : A by x
|
||||||
|
|
||||||
|
// FILE: B.kt
|
||||||
|
import lib.*
|
||||||
|
|
||||||
|
fun box() = C(B()).f()
|
||||||
+5
@@ -118,6 +118,11 @@ public class CompileKotlinAgainstKotlinTestGenerated extends AbstractCompileKotl
|
|||||||
runTest("compiler/testData/compileKotlinAgainstKotlin/defaultLambdaRegeneration2.kt");
|
runTest("compiler/testData/compileKotlinAgainstKotlin/defaultLambdaRegeneration2.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("delegatedDefault.kt")
|
||||||
|
public void testDelegatedDefault() throws Exception {
|
||||||
|
runTest("compiler/testData/compileKotlinAgainstKotlin/delegatedDefault.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("doublyNestedClass.kt")
|
@TestMetadata("doublyNestedClass.kt")
|
||||||
public void testDoublyNestedClass() throws Exception {
|
public void testDoublyNestedClass() throws Exception {
|
||||||
runTest("compiler/testData/compileKotlinAgainstKotlin/doublyNestedClass.kt");
|
runTest("compiler/testData/compileKotlinAgainstKotlin/doublyNestedClass.kt");
|
||||||
|
|||||||
Generated
+5
@@ -113,6 +113,11 @@ public class IrCompileKotlinAgainstKotlinTestGenerated extends AbstractIrCompile
|
|||||||
runTest("compiler/testData/compileKotlinAgainstKotlin/defaultLambdaRegeneration2.kt");
|
runTest("compiler/testData/compileKotlinAgainstKotlin/defaultLambdaRegeneration2.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("delegatedDefault.kt")
|
||||||
|
public void testDelegatedDefault() throws Exception {
|
||||||
|
runTest("compiler/testData/compileKotlinAgainstKotlin/delegatedDefault.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("doublyNestedClass.kt")
|
@TestMetadata("doublyNestedClass.kt")
|
||||||
public void testDoublyNestedClass() throws Exception {
|
public void testDoublyNestedClass() throws Exception {
|
||||||
runTest("compiler/testData/compileKotlinAgainstKotlin/doublyNestedClass.kt");
|
runTest("compiler/testData/compileKotlinAgainstKotlin/doublyNestedClass.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user