[JS IR] Fix export of constructor with default argument (KT-41275)

This commit is contained in:
Svyatoslav Kuzmich
2020-08-31 15:32:23 +03:00
parent 5b136516c4
commit 162d9744ff
9 changed files with 56 additions and 15 deletions
@@ -40,7 +40,7 @@ class JsIrBackendContext(
override val irBuiltIns: IrBuiltIns,
val symbolTable: SymbolTable,
irModuleFragment: IrModuleFragment,
val additionalExportedDeclarations: Set<FqName>,
val additionalExportedDeclarationNames: Set<FqName>,
override val configuration: CompilerConfiguration, // TODO: remove configuration from backend context
override val scriptMode: Boolean = false,
override val es6mode: Boolean = false
@@ -65,6 +65,8 @@ class JsIrBackendContext(
val externalPackageFragment = mutableMapOf<IrFileSymbol, IrFile>()
val externalDeclarations = hashSetOf<IrDeclaration>()
val additionalExportedDeclarations = mutableSetOf<IrDeclaration>()
val bodilessBuiltInsPackageFragment: IrPackageFragment = IrExternalPackageFragmentImpl(
DescriptorlessExternalPackageFragmentSymbol(),
FqName("kotlin")
@@ -331,9 +331,19 @@ class ExportModelGenerator(val context: JsIrBackendContext) {
if (function.isFakeOverriddenFromAny())
return Exportability.NotNeeded
if (function.name.asString().endsWith("-impl"))
val nameString = function.name.asString()
if (nameString.endsWith("-impl"))
return Exportability.NotNeeded
// Workaround in case IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER is rewritten.
// TODO: Properly fix KT-41613
if (nameString.endsWith("\$") && function.valueParameters.any { "\$mask" in it.name.asString() }) {
return Exportability.NotNeeded
}
val name = function.getExportedIdentifier()
// TODO: Use [] syntax instead of prohibiting
if (name in allReservedWords)
@@ -379,7 +389,10 @@ private fun getExportCandidate(declaration: IrDeclaration): IrDeclarationWithNam
}
private fun shouldDeclarationBeExported(declaration: IrDeclarationWithName, context: JsIrBackendContext): Boolean {
if (declaration.fqNameWhenAvailable in context.additionalExportedDeclarations)
if (declaration.fqNameWhenAvailable in context.additionalExportedDeclarationNames)
return true
if (declaration in context.additionalExportedDeclarations)
return true
if (declaration.isJsExport())
@@ -5,14 +5,15 @@
package org.jetbrains.kotlin.ir.backend.js.lower
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.export.isExported
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.util.file
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
// Move static member declarations from classes to top level
class StaticMembersLowering(val context: CommonBackendContext) : DeclarationTransformer {
class StaticMembersLowering(val context: JsIrBackendContext) : DeclarationTransformer {
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
(declaration.parent as? IrClass)?.let { irClass ->
val isStatic = when (declaration) {
@@ -23,6 +24,11 @@ class StaticMembersLowering(val context: CommonBackendContext) : DeclarationTran
}
if (isStatic) {
// JsExport might be inherited from parent declaration which would be broken if we move it out of its parent.
// Marking declaration as exported explicitly.
if (declaration.isExported(context)) {
context.additionalExportedDeclarations.add(declaration)
}
declaration.parent = irClass.file
irClass.file.declarations += declaration
return listOf()
@@ -312,7 +312,8 @@ class NameTables(
parent = parent.parent
}
return mappedNames[mapToKey(declaration)] ?: error("Can't find name for declaration ${declaration.render()}")
return mappedNames[mapToKey(declaration)]
?: error("Can't find name for declaration ${declaration.render()}")
}
fun getNameForMemberField(field: IrField): String {
@@ -316,11 +316,11 @@ private val blockDecomposerLoweringPhase = makeCustomWasmModulePhase(
// description = "Generate invocations to kotlin.test suite and test functions"
//)
//
private val staticMembersLoweringPhase = makeWasmModulePhase(
::StaticMembersLowering,
name = "StaticMembersLowering",
description = "Move static member declarations to top-level"
)
//private val staticMembersLoweringPhase = makeWasmModulePhase(
// ::StaticMembersLowering,
// name = "StaticMembersLowering",
// description = "Move static member declarations to top-level"
//)
private val builtInsLoweringPhase = makeWasmModulePhase(
::BuiltInsLowering,
@@ -434,7 +434,7 @@ val wasmPhases = NamedCompilerPhase(
objectDeclarationLoweringPhase then
objectUsageLoweringPhase then
staticMembersLoweringPhase then
// staticMembersLoweringPhase then
validateIrAfterLowering
)
@@ -30,4 +30,8 @@ declare namespace JS_TESTS {
static delegateToPrimary(y: string): DerivedClassWithSecondaryCtor;
static delegateToCreateFromInts(y: number, z: number): DerivedClassWithSecondaryCtor;
}
class KotlinGreeter {
constructor(greeting: string);
readonly greeting: string;
}
}
@@ -8,6 +8,8 @@
// TODO fix statics export in DCE-driven mode
// SKIP_DCE_DRIVEN
// FILE: f1.kt
@file:JsExport
class ClassWithDefaultCtor {
@@ -54,4 +56,9 @@ class DerivedClassWithSecondaryCtor : OpenClassWithMixedConstructors {
@JsName("delegateToCreateFromInts")
constructor(y: Int, z: Int) : super(y, z)
}
}
// FILE: f2.kt
@JsExport
class KotlinGreeter(val greeting: String = "helau")
@@ -1,5 +1,5 @@
"use strict";
var ClassWithDefaultCtor = JS_TESTS.ClassWithDefaultCtor, ClassWithPrimaryCtor = JS_TESTS.ClassWithPrimaryCtor, ClassWithSecondaryCtor = JS_TESTS.ClassWithSecondaryCtor, ClassWithMultipleSecondaryCtors = JS_TESTS.ClassWithMultipleSecondaryCtors, DerivedClassWithSecondaryCtor = JS_TESTS.DerivedClassWithSecondaryCtor, OpenClassWithMixedConstructors = JS_TESTS.OpenClassWithMixedConstructors;
var ClassWithDefaultCtor = JS_TESTS.ClassWithDefaultCtor, ClassWithPrimaryCtor = JS_TESTS.ClassWithPrimaryCtor, ClassWithSecondaryCtor = JS_TESTS.ClassWithSecondaryCtor, ClassWithMultipleSecondaryCtors = JS_TESTS.ClassWithMultipleSecondaryCtors, DerivedClassWithSecondaryCtor = JS_TESTS.DerivedClassWithSecondaryCtor, OpenClassWithMixedConstructors = JS_TESTS.OpenClassWithMixedConstructors, KotlinGreeter = JS_TESTS.KotlinGreeter;
function box() {
var o1 = new ClassWithDefaultCtor();
if (o1.x !== "ClassWithDefaultCtor::x")
@@ -31,5 +31,8 @@ function box() {
var o10 = DerivedClassWithSecondaryCtor.delegateToCreateFromInts(-10, 20);
if (o10.x !== "fromStrings:-10:20")
return "Fail: DerivedClassWithSecondaryCtor.delegateToCreateFromInts";
var kg = new KotlinGreeter("Hi");
if (kg.greeting != "Hi")
return "Fail: KotlinGreeter";
return "OK";
}
@@ -4,7 +4,8 @@ const {
ClassWithSecondaryCtor,
ClassWithMultipleSecondaryCtors,
DerivedClassWithSecondaryCtor,
OpenClassWithMixedConstructors
OpenClassWithMixedConstructors,
KotlinGreeter
} = JS_TESTS;
function box(): string {
@@ -43,5 +44,9 @@ function box(): string {
const o10 = DerivedClassWithSecondaryCtor.delegateToCreateFromInts(-10, 20);
if (o10.x !== "fromStrings:-10:20") return "Fail: DerivedClassWithSecondaryCtor.delegateToCreateFromInts";
const kg = new KotlinGreeter("Hi");
if (kg.greeting != "Hi") return "Fail: KotlinGreeter";
return "OK";
}