diff --git a/compiler/testData/codegen/box/delegation/withDefaultParameters.kt b/compiler/testData/codegen/box/delegation/withDefaultParameters.kt new file mode 100644 index 00000000000..dd9e8a968f6 --- /dev/null +++ b/compiler/testData/codegen/box/delegation/withDefaultParameters.kt @@ -0,0 +1,60 @@ +// IGNORE_BACKEND: JVM + +var log = "" +fun log(a: String) { + log += a + ";" +} + +interface C { + fun foo(x: Int): Unit { + log("C.foo($x)") + } +} + +interface I { + fun foo(x: Int = 1): Unit +} + +class G(c: C) : C by c, I +class H(c: C) : I, C by c + +fun test1() { + log = "" + + val g1 = G(object: C {}) + g1.foo(2) + g1.foo() + val g2 = G(object: C { + override fun foo(x: Int) { + log("[2] object:C.foo($x)") + } + }) + g2.foo(2) + g2.foo() +} + +fun test2() { + log = "" + + val h1 = H(object: C {}) + h1.foo(2) + h1.foo() + val h2 = H(object: C { + override fun foo(x: Int) { + log("[2] object:C.foo($x)") + } + }) + h2.foo(2) + h2.foo() +} + + +fun box(): String { + test1() + if (log != "C.foo(2);C.foo(1);[2] object:C.foo(2);[2] object:C.foo(1);") return "fail1: $log" + + test2() + if (log != "C.foo(2);C.foo(1);[2] object:C.foo(2);[2] object:C.foo(1);") return "fail2: $log" + + return "OK" +} \ No newline at end of file diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 95239a6cd1d..d75f2a2b4ed 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -7075,6 +7075,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegation/kt8154.kt"); doTest(fileName); } + + @TestMetadata("withDefaultParameters.kt") + public void testWithDefaultParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegation/withDefaultParameters.kt"); + try { + doTest(fileName); + } + catch (Throwable ignore) { + return; + } + throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + } } @TestMetadata("compiler/testData/codegen/box/destructuringDeclInLambdaParam") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 1f111811a35..390c8955e3b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -7075,6 +7075,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegation/kt8154.kt"); doTest(fileName); } + + @TestMetadata("withDefaultParameters.kt") + public void testWithDefaultParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegation/withDefaultParameters.kt"); + try { + doTest(fileName); + } + catch (Throwable ignore) { + return; + } + throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + } } @TestMetadata("compiler/testData/codegen/box/destructuringDeclInLambdaParam") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index c678b080e02..a9c710f0b62 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -7048,6 +7048,18 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) public static class Delegation extends AbstractLightAnalysisModeTest { + @TestMetadata("withDefaultParameters.kt") + public void ignoreWithDefaultParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegation/withDefaultParameters.kt"); + try { + doTest(fileName); + } + catch (Throwable ignore) { + return; + } + throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + } + public void testAllFilesPresentInDelegation() throws Exception { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/delegation"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 3cd906b0491..5bcef3105b0 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -7879,6 +7879,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegation/kt8154.kt"); doTest(fileName); } + + @TestMetadata("withDefaultParameters.kt") + public void testWithDefaultParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegation/withDefaultParameters.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/codegen/box/destructuringDeclInLambdaParam") diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassModelGenerator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassModelGenerator.kt index 1adcf41b464..5bc8ac32706 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassModelGenerator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassModelGenerator.kt @@ -192,7 +192,8 @@ class ClassModelGenerator(val context: StaticContext) { val sourceName = context.getNameForDescriptor(key).ident val targetName = context.getNameForDescriptor(value).ident if (sourceName != targetName) { - model.postDeclarationBlock.statements += generateDelegateCall(descriptor, key, value, JsLiteral.THIS, translationContext) + val statement = generateDelegateCall(descriptor, key, value, JsLiteral.THIS, translationContext, false) + model.postDeclarationBlock.statements += statement } } } @@ -228,7 +229,7 @@ class ClassModelGenerator(val context: StaticContext) { val translationContext = TranslationContext.rootContext(context) model.postDeclarationBlock.statements += generateDelegateCall(descriptor, fromDescriptor, toDescriptor, JsLiteral.THIS, - translationContext) + translationContext, false) } private fun copyMethod( diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DelegationTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DelegationTranslator.kt index 7a277c212a4..e8d179dcd7d 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DelegationTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DelegationTranslator.kt @@ -196,6 +196,7 @@ class DelegationTranslator( delegateName: JsName ) { val delegateRef = JsNameRef(delegateName, JsLiteral.THIS) - context().addDeclarationStatement(generateDelegateCall(classDescriptor, descriptor, overriddenDescriptor, delegateRef, context())) + val statement = generateDelegateCall(classDescriptor, descriptor, overriddenDescriptor, delegateRef, context(), true) + context().addDeclarationStatement(statement) } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt index b887f70096e..114509ba0c7 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt @@ -35,6 +35,7 @@ import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.simpleReturnFunction import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.descriptorUtil.hasOrInheritsParametersWithDefaultValue import org.jetbrains.kotlin.types.KotlinType fun generateDelegateCall( @@ -42,9 +43,18 @@ fun generateDelegateCall( fromDescriptor: FunctionDescriptor, toDescriptor: FunctionDescriptor, thisObject: JsExpression, - context: TranslationContext + context: TranslationContext, + detectDefaultParameters: Boolean ): JsStatement { - val overriddenMemberFunctionName = context.getNameForDescriptor(toDescriptor) + fun FunctionDescriptor.getNameForFunctionWithPossibleDefaultParam() = + if (detectDefaultParameters && hasOrInheritsParametersWithDefaultValue()) { + context.scope().declareName(context.getNameForDescriptor(this).ident + Namer.DEFAULT_PARAMETER_IMPLEMENTOR_SUFFIX) + } + else { + context.getNameForDescriptor(this) + } + + val overriddenMemberFunctionName = toDescriptor.getNameForFunctionWithPossibleDefaultParam() val overriddenMemberFunctionRef = JsNameRef(overriddenMemberFunctionName, thisObject) val parameters = SmartList() @@ -71,10 +81,14 @@ fun generateDelegateCall( JsInvocation(overriddenMemberFunctionRef, args) } - val functionObject = simpleReturnFunction(context.getScopeForDescriptor(fromDescriptor), invocation) + val functionObject = simpleReturnFunction(context.scope(), invocation) functionObject.parameters.addAll(parameters) - return context.addFunctionToPrototype(classDescriptor, fromDescriptor, functionObject) + val fromFunctionName = fromDescriptor.getNameForFunctionWithPossibleDefaultParam() + + val prototypeRef = JsAstUtils.prototypeOf(context.getInnerReference(classDescriptor)) + val functionRef = JsNameRef(fromFunctionName, prototypeRef) + return JsAstUtils.assignment(functionRef, functionObject).makeStmt() } fun List.splitToRanges(classifier: (T) -> S): List, S>> {