From 4e496cf2b206ec7bcd899150329bd755ad232e5f Mon Sep 17 00:00:00 2001 From: Anton Bannykh Date: Fri, 10 Aug 2018 18:12:03 +0300 Subject: [PATCH] JS: don't throw AssertionError from RedundantCallElimination Also mark JS `call` function to avoid removing a custom `call` --- .../ast/metadata/metadataProperties.kt | 2 ++ .../inline/clean/RedundantCallElimination.kt | 8 ++++-- .../kotlin/js/inline/util/invocationUtils.kt | 2 +- .../js/test/semantics/BoxJsTestGenerated.java | 5 ++++ .../test/semantics/IrBoxJsTestGenerated.java | 5 ++++ .../kotlin/js/translate/context/Namer.java | 4 ++- .../inline/faultyRedundantCallElimination.kt | 27 +++++++++++++++++++ 7 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 js/js.translator/testData/box/inline/faultyRedundantCallElimination.kt diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/metadata/metadataProperties.kt b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/metadata/metadataProperties.kt index ce547fc1977..4dc8f53612e 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/metadata/metadataProperties.kt +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/metadata/metadataProperties.kt @@ -47,6 +47,8 @@ var JsInvocation.descriptor: CallableDescriptor? by MetadataProperty(default = n var JsInvocation.psiElement: PsiElement? by MetadataProperty(default = null) +var JsNameRef.isJsCall: Boolean by MetadataProperty(default = false) + var JsNameRef.inlineStrategy: InlineStrategy? by MetadataProperty(default = null) var JsNameRef.descriptor: CallableDescriptor? by MetadataProperty(default = null) diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/RedundantCallElimination.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/RedundantCallElimination.kt index 49953bb2c30..524ac9ebefb 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/RedundantCallElimination.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/RedundantCallElimination.kt @@ -20,7 +20,7 @@ import org.jetbrains.kotlin.js.backend.ast.JsBlock import org.jetbrains.kotlin.js.backend.ast.JsInvocation import org.jetbrains.kotlin.js.backend.ast.JsNameRef import org.jetbrains.kotlin.js.backend.ast.RecursiveJsVisitor -import org.jetbrains.kotlin.js.inline.util.getCallerQualifier +import org.jetbrains.kotlin.js.backend.ast.metadata.isJsCall import org.jetbrains.kotlin.js.inline.util.isCallInvocation // Replaces a.foo.call(a, b) with a.foo(b) @@ -37,7 +37,11 @@ class RedundantCallElimination(private val root: JsBlock) { private fun tryEliminate(invocation: JsInvocation) { if (!isCallInvocation(invocation)) return - val qualifier = getCallerQualifier(invocation) as? JsNameRef ?: return + val call = invocation.qualifier as? JsNameRef ?: return + + if (!call.isJsCall) return + + val qualifier = call.qualifier as? JsNameRef ?: return val receiver = qualifier.qualifier as? JsNameRef ?: return val firstArg = invocation.arguments.firstOrNull() as? JsNameRef ?: return diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/invocationUtils.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/invocationUtils.kt index 9bcb1e75709..69eab576f42 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/invocationUtils.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/invocationUtils.kt @@ -70,7 +70,7 @@ fun isCallInvocation(invocation: JsInvocation): Boolean { if (qualifier.name?.descriptor != null) return false - return qualifier?.ident == Namer.CALL_FUNCTION && arguments.isNotEmpty() + return qualifier?.ident == Namer.CALL_FUNCTION && arguments.isNotEmpty() && qualifier.qualifier != null } /** diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java index 847702a15f1..8c39384bdc8 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java @@ -3835,6 +3835,11 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { runTest("js/js.translator/testData/box/inline/extensionWithManyArguments.kt"); } + @TestMetadata("faultyRedundantCallElimination.kt") + public void testFaultyRedundantCallElimination() throws Exception { + runTest("js/js.translator/testData/box/inline/faultyRedundantCallElimination.kt"); + } + @TestMetadata("identityEquals.kt") public void testIdentityEquals() throws Exception { runTest("js/js.translator/testData/box/inline/identityEquals.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java index fc2e388fe9b..34c38ecf302 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java @@ -3835,6 +3835,11 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest { runTest("js/js.translator/testData/box/inline/extensionWithManyArguments.kt"); } + @TestMetadata("faultyRedundantCallElimination.kt") + public void testFaultyRedundantCallElimination() throws Exception { + runTest("js/js.translator/testData/box/inline/faultyRedundantCallElimination.kt"); + } + @TestMetadata("identityEquals.kt") public void testIdentityEquals() throws Exception { runTest("js/js.translator/testData/box/inline/identityEquals.kt"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java index fda2397b09e..753ca5d5d8b 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java @@ -162,7 +162,9 @@ public final class Namer { @NotNull public static JsNameRef getFunctionCallRef(@NotNull JsExpression functionExpression) { - return pureFqn(CALL_FUNCTION, functionExpression); + JsNameRef result = pureFqn(CALL_FUNCTION, functionExpression); + MetadataProperties.setJsCall(result, true); + return result; } @NotNull diff --git a/js/js.translator/testData/box/inline/faultyRedundantCallElimination.kt b/js/js.translator/testData/box/inline/faultyRedundantCallElimination.kt new file mode 100644 index 00000000000..8c38f9ce01d --- /dev/null +++ b/js/js.translator/testData/box/inline/faultyRedundantCallElimination.kt @@ -0,0 +1,27 @@ +// IGNORE_BACKEND: JS_IR +// EXPECTED_REACHABLE_NODES: 1189 + +// MODULE: lib +// FILE: lib.kt + +fun String.call() = this + "O" + +inline fun O() = "".call() + +object A { + val foo = Foo +} + +object Foo { + @JsName("call") + fun call(a: A, k: String) = k +} + +inline fun K(a: A) = a.foo.call(a, "K") + +// MODULE: main(lib) +// FILE: main.kt + +val a = A + +fun box() = O() + K(a) \ No newline at end of file