JVM: Fix default parameter values handling

When we generate call for 'foo', we make decision about invoking
a 'foo$default' too late, after the call arguments are generated.
If 'foo' was an override, and base class (interface) was generic,
'foo' in base class could have a different Kotlin and JVM
signature, so the arguments we generated could be generated wrong
(primitive or inline class values instead of boxes, see KT-38680).
Also, we always selected first base class in supertypes list,
which caused KT-15971.

Look into resolved call and see if we should actually call
'foo$default' instead of 'foo' when determining actual callable.

Overrides can't introduce default parameter values, and
override-equivalent inherited methods with default parameters
is an error in a child class. Thus, if we are calling a class
member function with a default parameters, there should be one
and only one overridden function that has default parameter values
and overrides nothing.
This commit is contained in:
Dmitry Petrov
2020-05-12 18:42:27 +03:00
parent dc9f64fc9d
commit 2f82c5b6af
21 changed files with 188 additions and 62 deletions
@@ -17,11 +17,13 @@
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
import org.jetbrains.kotlin.resolve.calls.model.VarargValueArgument
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.descriptorUtil.overriddenTreeUniqueAsSequence
import org.jetbrains.kotlin.utils.DFS
import org.jetbrains.kotlin.utils.mapToIndex
@@ -123,3 +125,34 @@ private fun CallableDescriptor.defaultValueFromJava(index: Int): Boolean = DFS.i
descriptor.valueParameters[index].declaresDefaultValue()
}
)
fun shouldInvokeDefaultArgumentsStub(resolvedCall: ResolvedCall<*>): Boolean {
val descriptor = resolvedCall.resultingDescriptor
val valueArgumentsByIndex = resolvedCall.valueArgumentsByIndex ?: return false
for (index in valueArgumentsByIndex.indices) {
val resolvedValueArgument = valueArgumentsByIndex[index]
if (resolvedValueArgument is DefaultValueArgument && !descriptor.defaultValueFromJava(index)) {
return true
}
}
return false
}
fun getFunctionWithDefaultArguments(functionDescriptor: FunctionDescriptor): FunctionDescriptor {
if (functionDescriptor.containingDeclaration !is ClassDescriptor) return functionDescriptor
if (functionDescriptor.overriddenDescriptors.isEmpty()) return functionDescriptor
// We are calling a function with some arguments mapped as defaults.
// Multiple override-equivalent functions from different supertypes with (potentially different) default values
// can't be overridden by any function in a subtype.
// Also, a function overriding some other function can't introduce default parameter values.
// Thus, among all overridden functions should be one (and only one) function
// that doesn't override anything and has parameters with default values.
return functionDescriptor.overriddenTreeUniqueAsSequence(true)
.firstOrNull { function ->
function.kind == CallableMemberDescriptor.Kind.DECLARATION &&
function.overriddenDescriptors.isEmpty() &&
function.valueParameters.any { valueParameter -> valueParameter.hasDefaultValue() }
}
?: functionDescriptor
}
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
@@ -2566,7 +2566,19 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
return intrinsic.toCallable(fd, superCall, resolvedCall, this);
}
return typeMapper.mapToCallableMethod(SamCodegenUtil.resolveSamAdapter(fd), superCall, null, resolvedCall);
fd = SamCodegenUtil.resolveSamAdapter(fd);
if (ArgumentGeneratorKt.shouldInvokeDefaultArgumentsStub(resolvedCall)) {
// When we invoke a function with some arguments mapped as defaults,
// we later reroute this call to an overridden function in a base class that processes the default arguments.
// If the base class is generic, this overridden function can have a different Kotlin signature
// (see KT-38681 and related issues).
// Here we replace a function with a corresponding overridden function,
// and the rest is figured out by argument generation and type mapper.
fd = ArgumentGeneratorKt.getFunctionWithDefaultArguments(fd);
}
return typeMapper.mapToCallableMethod(fd, superCall, null, resolvedCall);
}
public void invokeMethodWithArguments(
@@ -60,6 +60,7 @@ import org.jetbrains.org.objectweb.asm.Opcodes.*
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.commons.Method
import java.util.*
fun generateIsCheck(
v: InstructionAdapter,
@@ -12913,6 +12913,16 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/inlineClasses/kt38680.kt");
}
@TestMetadata("kt38680a.kt")
public void testKt38680a() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt38680a.kt");
}
@TestMetadata("kt38680b.kt")
public void testKt38680b() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt38680b.kt");
}
@TestMetadata("mangledDefaultParameterFunction.kt")
public void testMangledDefaultParameterFunction() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt");
@@ -1,6 +1,3 @@
// IGNORE_BACKEND: JVM
// See KT-15971
interface Foo {
fun foo(a: Double = 1.0): Double
}
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM
interface Q {
fun foo(a: Double): Double
}
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM
interface Q {
fun foo(a: Double) = 0.0
}
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM
interface Q {
fun foo(a: Double): Double
}
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM
interface I<T> {
val prop: T
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM
interface I<T> {
val prop: T
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM
interface I<T> {
val prop: T
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM
var log = ""
fun log(a: String) {
+15
View File
@@ -0,0 +1,15 @@
// !LANGUAGE: +InlineClasses
inline class IC(val s: String)
interface IFoo<T> {
fun foo(x: T, s: String = "K"): String
fun bar(x: T) = foo(x)
}
class FooImpl : IFoo<IC> {
override fun foo(x: IC, s: String): String = x.s + s
}
fun box(): String = FooImpl().bar(IC("O"))
+17
View File
@@ -0,0 +1,17 @@
// !LANGUAGE: +InlineClasses
inline class IC(val s: String)
interface IFoo<T> {
fun foo(x: T, s: String = "K"): String
}
interface IFoo2<T> : IFoo<T> {
fun bar(x: T) = foo(x)
}
class FooImpl : IFoo2<IC> {
override fun foo(x: IC, s: String): String = x.s + s
}
fun box(): String = FooImpl().bar(IC("O"))
@@ -1,6 +1,5 @@
// !LANGUAGE: +MultiPlatformProjects
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM
// FILE: lib.kt
@@ -14128,6 +14128,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/inlineClasses/kt38680.kt");
}
@TestMetadata("kt38680a.kt")
public void testKt38680a() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt38680a.kt");
}
@TestMetadata("kt38680b.kt")
public void testKt38680b() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt38680b.kt");
}
@TestMetadata("mangledDefaultParameterFunction.kt")
public void testMangledDefaultParameterFunction() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt");
@@ -9868,21 +9868,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class DefaultArguments extends AbstractLightAnalysisModeTest {
@TestMetadata("implementedByFake.kt")
public void ignoreImplementedByFake() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/implementedByFake.kt");
}
@TestMetadata("implementedByFake2.kt")
public void ignoreImplementedByFake2() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/implementedByFake2.kt");
}
@TestMetadata("implementedByFake3.kt")
public void ignoreImplementedByFake3() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/implementedByFake3.kt");
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
@@ -9901,6 +9886,21 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/defaultArguments/complexInheritance.kt");
}
@TestMetadata("implementedByFake.kt")
public void testImplementedByFake() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/implementedByFake.kt");
}
@TestMetadata("implementedByFake2.kt")
public void testImplementedByFake2() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/implementedByFake2.kt");
}
@TestMetadata("implementedByFake3.kt")
public void testImplementedByFake3() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/implementedByFake3.kt");
}
@TestMetadata("inheritedFromInterfaceViaAbstractSuperclass.kt")
public void testInheritedFromInterfaceViaAbstractSuperclass() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/inheritedFromInterfaceViaAbstractSuperclass.kt");
@@ -10106,26 +10106,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Function extends AbstractLightAnalysisModeTest {
@TestMetadata("funInTraitChain.kt")
public void ignoreFunInTraitChain() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/function/funInTraitChain.kt");
}
@TestMetadata("kt15971.kt")
public void ignoreKt15971() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/function/kt15971.kt");
}
@TestMetadata("kt15971_2.kt")
public void ignoreKt15971_2() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/function/kt15971_2.kt");
}
@TestMetadata("kt15971_3.kt")
public void ignoreKt15971_3() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/function/kt15971_3.kt");
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
@@ -10194,6 +10174,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/defaultArguments/function/funInTrait.kt");
}
@TestMetadata("funInTraitChain.kt")
public void testFunInTraitChain() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/function/funInTraitChain.kt");
}
@TestMetadata("innerExtentionFunction.kt")
public void testInnerExtentionFunction() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/function/innerExtentionFunction.kt");
@@ -10214,6 +10199,21 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/defaultArguments/function/innerExtentionFunctionManyArgs.kt");
}
@TestMetadata("kt15971.kt")
public void testKt15971() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/function/kt15971.kt");
}
@TestMetadata("kt15971_2.kt")
public void testKt15971_2() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/function/kt15971_2.kt");
}
@TestMetadata("kt15971_3.kt")
public void testKt15971_3() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/function/kt15971_3.kt");
}
@TestMetadata("kt36188.kt")
public void testKt36188() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/function/kt36188.kt");
@@ -10798,11 +10798,6 @@ 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 {
runTest("compiler/testData/codegen/box/delegation/withDefaultParameters.kt");
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
@@ -10880,6 +10875,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
public void testSimple1_0() throws Exception {
runTest("compiler/testData/codegen/box/delegation/simple1.0.kt");
}
@TestMetadata("withDefaultParameters.kt")
public void testWithDefaultParameters() throws Exception {
runTest("compiler/testData/codegen/box/delegation/withDefaultParameters.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/destructuringDeclInLambdaParam")
@@ -14133,6 +14133,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/inlineClasses/kt38680.kt");
}
@TestMetadata("kt38680a.kt")
public void testKt38680a() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt38680a.kt");
}
@TestMetadata("kt38680b.kt")
public void testKt38680b() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt38680b.kt");
}
@TestMetadata("mangledDefaultParameterFunction.kt")
public void testMangledDefaultParameterFunction() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt");
@@ -18634,11 +18644,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class DefaultArguments extends AbstractLightAnalysisModeTest {
@TestMetadata("delegatedExpectedInterface.kt")
public void ignoreDelegatedExpectedInterface() throws Exception {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/delegatedExpectedInterface.kt");
}
@TestMetadata("superCall.kt")
public void ignoreSuperCall() throws Exception {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/superCall.kt");
@@ -18672,6 +18677,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/constructor.kt");
}
@TestMetadata("delegatedExpectedInterface.kt")
public void testDelegatedExpectedInterface() throws Exception {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/delegatedExpectedInterface.kt");
}
@TestMetadata("dispatchReceiverValue.kt")
public void testDispatchReceiverValue() throws Exception {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/dispatchReceiverValue.kt");
@@ -12913,6 +12913,16 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/inlineClasses/kt38680.kt");
}
@TestMetadata("kt38680a.kt")
public void testKt38680a() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt38680a.kt");
}
@TestMetadata("kt38680b.kt")
public void testKt38680b() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt38680b.kt");
}
@TestMetadata("mangledDefaultParameterFunction.kt")
public void testMangledDefaultParameterFunction() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt");
@@ -11123,6 +11123,16 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/inlineClasses/kt38680.kt");
}
@TestMetadata("kt38680a.kt")
public void testKt38680a() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt38680a.kt");
}
@TestMetadata("kt38680b.kt")
public void testKt38680b() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt38680b.kt");
}
@TestMetadata("mangledDefaultParameterFunction.kt")
public void testMangledDefaultParameterFunction() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt");
@@ -11188,6 +11188,16 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/inlineClasses/kt38680.kt");
}
@TestMetadata("kt38680a.kt")
public void testKt38680a() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt38680a.kt");
}
@TestMetadata("kt38680b.kt")
public void testKt38680b() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt38680b.kt");
}
@TestMetadata("mangledDefaultParameterFunction.kt")
public void testMangledDefaultParameterFunction() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt");