From 8a569cc698662373d4e46b8363a4f629a5eb6487 Mon Sep 17 00:00:00 2001 From: Roman Artemev Date: Thu, 4 Jul 2019 18:10:43 +0300 Subject: [PATCH] [JS IR BE] Do not create `$default` stub for external function and any its fake override --- .../lower/DefaultArgumentStubGenerator.kt | 7 ++- .../lower/JsDefaultArgumentStubGenerator.kt | 2 +- .../js/transformers/irToJs/jsAstUtils.kt | 4 +- .../org/jetbrains/kotlin/ir/util/IrUtils.kt | 7 +++ .../ir/semantics/IrBoxJsTestGenerated.java | 5 +++ .../js/test/semantics/BoxJsTestGenerated.java | 5 +++ .../box/jsModule/externalClassWithDefaults.js | 13 ++++++ .../box/jsModule/externalClassWithDefaults.kt | 44 +++++++++++++++++++ 8 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 js/js.translator/testData/box/jsModule/externalClassWithDefaults.js create mode 100644 js/js.translator/testData/box/jsModule/externalClassWithDefaults.kt diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/DefaultArgumentStubGenerator.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/DefaultArgumentStubGenerator.kt index 0a5506b9ae9..639aff30605 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/DefaultArgumentStubGenerator.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/DefaultArgumentStubGenerator.kt @@ -396,12 +396,15 @@ class DefaultParameterCleaner constructor(val context: CommonBackendContext) : F // TODO this implementation is exponential private fun IrFunction.needsDefaultArgumentsLowering(skipInlineMethods: Boolean, skipExternalMethods: Boolean): Boolean { if (isInline && skipInlineMethods) return false - if (skipExternalMethods && isEffectivelyExternal()) return false + if (skipExternalMethods && isExternalOrInheritedFromExternal()) return false if (valueParameters.any { it.defaultValue != null }) return true if (this !is IrSimpleFunction) return false - return overriddenSymbols.any { it.owner.needsDefaultArgumentsLowering(skipInlineMethods, skipExternalMethods) } + fun IrSimpleFunction.inheritsDefaultValues(): Boolean = + valueParameters.any { it.defaultValue != null } || overriddenSymbols.any { it.owner.inheritsDefaultValues() } + + return inheritsDefaultValues() } private fun IrFunction.generateDefaultsFunctionImpl( diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/JsDefaultArgumentStubGenerator.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/JsDefaultArgumentStubGenerator.kt index 709bdd5fef7..c99897434c9 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/JsDefaultArgumentStubGenerator.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/JsDefaultArgumentStubGenerator.kt @@ -27,7 +27,7 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name -class JsDefaultArgumentStubGenerator(override val context: JsIrBackendContext) : DefaultArgumentStubGenerator(context, true, false) { +class JsDefaultArgumentStubGenerator(override val context: JsIrBackendContext) : DefaultArgumentStubGenerator(context, true, true) { override fun needSpecialDispatch(irFunction: IrSimpleFunction) = irFunction.isOverridableOrOverrides diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsAstUtils.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsAstUtils.kt index 4b4f400093d..830d0734987 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsAstUtils.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsAstUtils.kt @@ -15,7 +15,7 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression import org.jetbrains.kotlin.ir.expressions.IrWhen -import org.jetbrains.kotlin.ir.util.isEffectivelyExternal +import org.jetbrains.kotlin.ir.util.isExternalOrInheritedFromExternal import org.jetbrains.kotlin.js.backend.ast.* fun jsVar(name: JsName, initializer: IrExpression?, context: JsGenerationContext): JsVars { @@ -72,7 +72,7 @@ fun translateCallArguments(expression: IrMemberAccessExpression, context: JsGene val argument = expression.getValueArgument(index) val result = argument?.accept(transformer, context) if (result == null) { - require(expression is IrFunctionAccessExpression && expression.symbol.owner.isEffectivelyExternal()) + assert(expression is IrFunctionAccessExpression && expression.symbol.owner.isExternalOrInheritedFromExternal()) JsPrefixOperation(JsUnaryOperator.VOID, JsIntLiteral(1)) } else result diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt index def90224b9b..c26040b02ed 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt @@ -360,6 +360,13 @@ fun IrDeclaration.isEffectivelyExternal(): Boolean { } } +fun IrFunction.isExternalOrInheritedFromExternal(): Boolean { + fun isExternalOrInheritedFromExternalImpl(f: IrSimpleFunction): Boolean = + f.isEffectivelyExternal() || f.overriddenSymbols.any { isExternalOrInheritedFromExternalImpl(it.owner) } + + return isEffectivelyExternal() || (this is IrSimpleFunction && isExternalOrInheritedFromExternalImpl(this)) +} + inline fun IrDeclarationContainer.findDeclaration(predicate: (T) -> Boolean): T? = declarations.find { it is T && predicate(it) } as? T diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrBoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrBoxJsTestGenerated.java index 9df05a978c5..5ef9c44cbc7 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrBoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrBoxJsTestGenerated.java @@ -4918,6 +4918,11 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest { runTest("js/js.translator/testData/box/jsModule/externalClass.kt"); } + @TestMetadata("externalClassWithDefaults.kt") + public void testExternalClassWithDefaults() throws Exception { + runTest("js/js.translator/testData/box/jsModule/externalClassWithDefaults.kt"); + } + @TestMetadata("externalFunction.kt") public void testExternalFunction() throws Exception { runTest("js/js.translator/testData/box/jsModule/externalFunction.kt"); 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 620ae5dde6b..3795bfc35fa 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 @@ -4933,6 +4933,11 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { runTest("js/js.translator/testData/box/jsModule/externalClass.kt"); } + @TestMetadata("externalClassWithDefaults.kt") + public void testExternalClassWithDefaults() throws Exception { + runTest("js/js.translator/testData/box/jsModule/externalClassWithDefaults.kt"); + } + @TestMetadata("externalFunction.kt") public void testExternalFunction() throws Exception { runTest("js/js.translator/testData/box/jsModule/externalFunction.kt"); diff --git a/js/js.translator/testData/box/jsModule/externalClassWithDefaults.js b/js/js.translator/testData/box/jsModule/externalClassWithDefaults.js new file mode 100644 index 00000000000..bbdb9886202 --- /dev/null +++ b/js/js.translator/testData/box/jsModule/externalClassWithDefaults.js @@ -0,0 +1,13 @@ +define("lib", [], function() { + function A(ss) { + this.s = ss || "A" + } + A.prototype.foo = function (y) { + return y || "K"; + }; + A.prototype.bar = function (y) { + return y || "O"; + }; + + return A; +}); \ No newline at end of file diff --git a/js/js.translator/testData/box/jsModule/externalClassWithDefaults.kt b/js/js.translator/testData/box/jsModule/externalClassWithDefaults.kt new file mode 100644 index 00000000000..01b743cbe8b --- /dev/null +++ b/js/js.translator/testData/box/jsModule/externalClassWithDefaults.kt @@ -0,0 +1,44 @@ +// EXPECTED_REACHABLE_NODES: 1284 +// MODULE_KIND: AMD +package foo + +@JsModule("lib") +external open class A(ss: String = definedExternally) { + val s: String + fun foo(y: String = definedExternally): String = definedExternally + fun bar(y: String = definedExternally): String = definedExternally +} + +class C: A { + constructor(ss: String) : super(ss) {} + constructor() : super() {} + + fun qux(s: String = "O") = s +} + + +fun box(): String { + val a = A() + val c = C() + + val r1 = a.foo("O") + c.foo() + if (r1 != "OK") return "Fail1: $r1" + + val r2 = a.bar() + c.bar("K") + if (r2 != "OK") return "Fail2: $r2" + + val r3 = c.qux() + c.qux("K") + if (r3 != "OK") return "Fail3: $r3" + + if (a.s != "A") return "Fail4: ${a.s}" + if (c.s != "A") return "Fail5: ${c.s}" + + val a2 = A("A2") + val c2 = C("C2") + + val r6 = a2.s + c2.s + if (r6 != "A2C2") return "Fail6: $r6" + + return "OK" + +} \ No newline at end of file