Fix translation of delegated functions with default params in JS BE
See KT-17285
This commit is contained in:
@@ -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"
|
||||||
|
}
|
||||||
+12
@@ -7075,6 +7075,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegation/kt8154.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegation/kt8154.kt");
|
||||||
doTest(fileName);
|
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")
|
@TestMetadata("compiler/testData/codegen/box/destructuringDeclInLambdaParam")
|
||||||
|
|||||||
@@ -7075,6 +7075,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegation/kt8154.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegation/kt8154.kt");
|
||||||
doTest(fileName);
|
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")
|
@TestMetadata("compiler/testData/codegen/box/destructuringDeclInLambdaParam")
|
||||||
|
|||||||
@@ -7048,6 +7048,18 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
public static class Delegation extends AbstractLightAnalysisModeTest {
|
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 {
|
public void testAllFilesPresentInDelegation() throws Exception {
|
||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/delegation"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/delegation"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7879,6 +7879,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegation/kt8154.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegation/kt8154.kt");
|
||||||
doTest(fileName);
|
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")
|
@TestMetadata("compiler/testData/codegen/box/destructuringDeclInLambdaParam")
|
||||||
|
|||||||
+3
-2
@@ -192,7 +192,8 @@ class ClassModelGenerator(val context: StaticContext) {
|
|||||||
val sourceName = context.getNameForDescriptor(key).ident
|
val sourceName = context.getNameForDescriptor(key).ident
|
||||||
val targetName = context.getNameForDescriptor(value).ident
|
val targetName = context.getNameForDescriptor(value).ident
|
||||||
if (sourceName != targetName) {
|
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)
|
val translationContext = TranslationContext.rootContext(context)
|
||||||
model.postDeclarationBlock.statements += generateDelegateCall(descriptor, fromDescriptor, toDescriptor, JsLiteral.THIS,
|
model.postDeclarationBlock.statements += generateDelegateCall(descriptor, fromDescriptor, toDescriptor, JsLiteral.THIS,
|
||||||
translationContext)
|
translationContext, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun copyMethod(
|
private fun copyMethod(
|
||||||
|
|||||||
+2
-1
@@ -196,6 +196,7 @@ class DelegationTranslator(
|
|||||||
delegateName: JsName
|
delegateName: JsName
|
||||||
) {
|
) {
|
||||||
val delegateRef = JsNameRef(delegateName, JsLiteral.THIS)
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.js.translate.utils.TranslationUtils.simpleReturnFunction
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.hasOrInheritsParametersWithDefaultValue
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
fun generateDelegateCall(
|
fun generateDelegateCall(
|
||||||
@@ -42,9 +43,18 @@ fun generateDelegateCall(
|
|||||||
fromDescriptor: FunctionDescriptor,
|
fromDescriptor: FunctionDescriptor,
|
||||||
toDescriptor: FunctionDescriptor,
|
toDescriptor: FunctionDescriptor,
|
||||||
thisObject: JsExpression,
|
thisObject: JsExpression,
|
||||||
context: TranslationContext
|
context: TranslationContext,
|
||||||
|
detectDefaultParameters: Boolean
|
||||||
): JsStatement {
|
): 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 overriddenMemberFunctionRef = JsNameRef(overriddenMemberFunctionName, thisObject)
|
||||||
|
|
||||||
val parameters = SmartList<JsParameter>()
|
val parameters = SmartList<JsParameter>()
|
||||||
@@ -71,10 +81,14 @@ fun generateDelegateCall(
|
|||||||
JsInvocation(overriddenMemberFunctionRef, args)
|
JsInvocation(overriddenMemberFunctionRef, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
val functionObject = simpleReturnFunction(context.getScopeForDescriptor(fromDescriptor), invocation)
|
val functionObject = simpleReturnFunction(context.scope(), invocation)
|
||||||
functionObject.parameters.addAll(parameters)
|
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 <T, S> List<T>.splitToRanges(classifier: (T) -> S): List<Pair<List<T>, S>> {
|
fun <T, S> List<T>.splitToRanges(classifier: (T) -> S): List<Pair<List<T>, S>> {
|
||||||
|
|||||||
Reference in New Issue
Block a user