JS: more default arguments fixes (KT-24413, KT-21968 fixed)

MPP-related:
* inherited from interfaces
* inherited body from interface
* default arguments in an interface, implemented by a class delegate
* super call of a method with default argument

Also:
* inheritance from an interface and another interface descendant (KT-21968)
* inheritance through an intermediate interface
This commit is contained in:
Anton Bannykh
2018-05-15 14:55:59 +03:00
parent da7b59984f
commit 03e46ce0ca
21 changed files with 357 additions and 55 deletions
@@ -6743,11 +6743,6 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/defaultArguments/simpleFromOtherFile.kt");
}
@TestMetadata("superCallCheck.kt")
public void testSuperCallCheck() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/superCallCheck.kt");
}
@TestMetadata("compiler/testData/codegen/box/defaultArguments/constructor")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -6770,11 +6765,6 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/defaultArguments/constructor/annotationWithEmptyArray.kt");
}
@TestMetadata("checkIfConstructorIsSynthetic.kt")
public void testCheckIfConstructorIsSynthetic() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/constructor/checkIfConstructorIsSynthetic.kt");
}
@TestMetadata("defArgs1.kt")
public void testDefArgs1() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/constructor/defArgs1.kt");
@@ -6824,11 +6814,6 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
public void testKt3060() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/constructor/kt3060.kt");
}
@TestMetadata("manyArgs.kt")
public void testManyArgs() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/constructor/manyArgs.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/defaultArguments/convention")
@@ -6876,6 +6861,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/defaultArguments/function"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
}
@TestMetadata("complexInheritance.kt")
public void testComplexInheritance() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/function/complexInheritance.kt");
}
@TestMetadata("covariantOverride.kt")
public void testCovariantOverride() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/function/covariantOverride.kt");
@@ -6926,6 +6916,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
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");
@@ -11713,6 +11708,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
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("function.kt")
public void testFunction() throws Exception {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/function.kt");
@@ -11728,6 +11728,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedClass.kt");
}
@TestMetadata("inheritedFromExpectedInterface.kt")
public void testInheritedFromExpectedInterface() throws Exception {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedInterface.kt");
}
@TestMetadata("inheritedFromExpectedMethod.kt")
public void testInheritedFromExpectedMethod() throws Exception {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedMethod.kt");
@@ -11738,6 +11743,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedInExpectedDeclarations.kt");
}
@TestMetadata("inheritedViaAnotherInterfaceIndirectly.kt")
public void testInheritedViaAnotherInterfaceIndirectly() throws Exception {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedViaAnotherInterfaceIndirectly.kt");
}
@TestMetadata("inlineFunctionWithDefaultLambda.kt")
public void testInlineFunctionWithDefaultLambda() throws Exception {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/inlineFunctionWithDefaultLambda.kt");
@@ -11747,6 +11757,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
public void testKt23239() throws Exception {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/kt23239.kt");
}
@TestMetadata("superCall.kt")
public void testSuperCall() throws Exception {
runTest("compiler/testData/codegen/box/multiplatform/defaultArguments/superCall.kt");
}
}
}
@@ -24,12 +24,9 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.translate.context.Namer
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.js.translate.utils.*
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.prototypeOf
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
import org.jetbrains.kotlin.js.translate.utils.generateDelegateCall
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.*
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
@@ -85,9 +82,10 @@ class ClassModelGenerator(val context: TranslationContext) {
// However, D inherits `foo` without suffix (i.e. it corresponds to I's dispatcher function).
// We must copy B.foo to D.foo$default and then I.foo to D.foo
private fun tryCopyWhenImplementingInterfaceWithDefaultArgs(member: FunctionDescriptor, model: JsClassModel): Boolean {
val fromInterface = member.overriddenDescriptors.firstOrNull { it.hasOwnParametersWithDefaultValue() } ?: return false
val fromInterface = member.overriddenDescriptors.firstOrNull { it.hasOrInheritsParametersWithDefaultValue() } ?: return false
if (!DescriptorUtils.isInterface(fromInterface.containingDeclaration)) return false
val fromClass = member.overriddenDescriptors.firstOrNull { !DescriptorUtils.isInterface(it.containingDeclaration) } ?: return false
if (fromClass.hasOrInheritsParametersWithDefaultValue()) return false
val targetClass = member.containingDeclaration as ClassDescriptor
val fromInterfaceName = context.getNameForDescriptor(fromInterface).ident
@@ -28,9 +28,6 @@ import org.jetbrains.kotlin.js.translate.utils.BindingUtils.getClassDescriptor
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getSupertypesWithoutFakes
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
import org.jetbrains.kotlin.resolve.calls.components.isActualParameterWithCorrespondingExpectedDefault
import org.jetbrains.kotlin.resolve.descriptorUtil.hasOwnParametersWithDefaultValue
class DeclarationBodyVisitor(
private val containingClass: ClassDescriptor,
@@ -111,12 +108,8 @@ class DeclarationBodyVisitor(
initializerStatements.add(statement)
}
private fun hasParametersWithDefaultValue(descriptor: FunctionDescriptor) = descriptor.valueParameters.any { it.hasDefaultValue() }
private fun hasCorrespondingExpectParametersWithDefaultValue(descriptor: FunctionDescriptor) =
descriptor.valueParameters.any { it.isActualParameterWithCorrespondingExpectedDefault }
override fun addFunction(descriptor: FunctionDescriptor, expression: JsExpression?, psi: KtElement?) {
if (!hasParametersWithDefaultValue(descriptor) || !descriptor.isOverridableOrOverrides) {
if (!descriptor.hasOrInheritsParametersWithDefaultValue() || !descriptor.isOverridableOrOverrides) {
if (expression != null) {
context.addDeclarationStatement(context.addFunctionToPrototype(containingClass, descriptor, expression))
}
@@ -130,7 +123,7 @@ class DeclarationBodyVisitor(
context.addDeclarationStatement(JsAstUtils.assignment(functionRef, expression).makeStmt())
}
if (descriptor.hasOwnParametersWithDefaultValue() || hasCorrespondingExpectParametersWithDefaultValue(descriptor)) {
if (descriptor.hasOwnParametersWithDefaultValue()) {
val caller = JsFunction(context.getScopeForDescriptor(containingClass), JsBlock(), "")
caller.source = psi?.finalElement
val callerContext = context
@@ -48,6 +48,7 @@ import java.util.stream.Collectors;
import static org.jetbrains.kotlin.js.backend.ast.JsBinaryOperator.*;
import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getCallableDescriptorForOperationExpression;
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.*;
import static org.jetbrains.kotlin.js.translate.utils.UtilsKt.hasOrInheritsParametersWithDefaultValue;
public final class TranslationUtils {
private static final Set<FqNameUnsafe> CLASSES_WITH_NON_BOXED_CHARS = new HashSet<>(Arrays.asList(
@@ -405,10 +406,10 @@ public final class TranslationUtils {
}
public static boolean isOverridableFunctionWithDefaultParameters(@NotNull FunctionDescriptor descriptor) {
return DescriptorUtilsKt.hasOrInheritsParametersWithDefaultValue(descriptor) &&
!(descriptor instanceof ConstructorDescriptor) &&
descriptor.getContainingDeclaration() instanceof ClassDescriptor &&
ModalityKt.isOverridable(descriptor);
return hasOrInheritsParametersWithDefaultValue(descriptor) &&
!(descriptor instanceof ConstructorDescriptor) &&
descriptor.getContainingDeclaration() instanceof ClassDescriptor &&
ModalityKt.isOverridable(descriptor);
}
@NotNull
@@ -28,11 +28,12 @@ import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.simpleReturnFunc
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.components.isActualParameterWithCorrespondingExpectedDefault
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.hasOrInheritsParametersWithDefaultValue
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.utils.DFS
fun generateDelegateCall(
classDescriptor: ClassDescriptor,
@@ -270,4 +271,13 @@ fun TranslationContext.getPrimitiveNumericComparisonInfo(expression: KtExpressio
} else {
null
}
}
}
fun FunctionDescriptor.hasOrInheritsParametersWithDefaultValue(): Boolean = DFS.ifAny(
listOf(this),
{ current -> current.overriddenDescriptors.map { it.original } },
{ it.hasOwnParametersWithDefaultValue() }
)
fun FunctionDescriptor.hasOwnParametersWithDefaultValue() =
original.valueParameters.any { it.declaresDefaultValue() || it.isActualParameterWithCorrespondingExpectedDefault }