diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt index eccd135c131..6dbe2803a91 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt @@ -40,7 +40,7 @@ class JsIrBackendContext( override val irBuiltIns: IrBuiltIns, val symbolTable: SymbolTable, irModuleFragment: IrModuleFragment, - val additionalExportedDeclarations: Set, + val additionalExportedDeclarationNames: Set, 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() val externalDeclarations = hashSetOf() + val additionalExportedDeclarations = mutableSetOf() + val bodilessBuiltInsPackageFragment: IrPackageFragment = IrExternalPackageFragmentImpl( DescriptorlessExternalPackageFragmentSymbol(), FqName("kotlin") diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelGenerator.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelGenerator.kt index 28428c5bf14..69c0b9bb9bb 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelGenerator.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelGenerator.kt @@ -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()) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/StaticMembersLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/StaticMembersLowering.kt index 1acec4bb641..856a6f68070 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/StaticMembersLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/StaticMembersLowering.kt @@ -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? { (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() diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt index b13c5755714..ce602f659b9 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt @@ -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 { diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt index 50c16356c6d..3a2ad262d04 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt @@ -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 ) diff --git a/js/js.translator/testData/typescript-export/constructors/constructors.d.ts b/js/js.translator/testData/typescript-export/constructors/constructors.d.ts index a36e85f1c95..5c712041e5e 100644 --- a/js/js.translator/testData/typescript-export/constructors/constructors.d.ts +++ b/js/js.translator/testData/typescript-export/constructors/constructors.d.ts @@ -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; + } } diff --git a/js/js.translator/testData/typescript-export/constructors/constructors.kt b/js/js.translator/testData/typescript-export/constructors/constructors.kt index 256baa988fa..8e543dcf2dd 100644 --- a/js/js.translator/testData/typescript-export/constructors/constructors.kt +++ b/js/js.translator/testData/typescript-export/constructors/constructors.kt @@ -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) -} \ No newline at end of file +} + +// FILE: f2.kt + +@JsExport +class KotlinGreeter(val greeting: String = "helau") \ No newline at end of file diff --git a/js/js.translator/testData/typescript-export/constructors/constructors__main.js b/js/js.translator/testData/typescript-export/constructors/constructors__main.js index 9958fedf771..489fd99b83b 100644 --- a/js/js.translator/testData/typescript-export/constructors/constructors__main.js +++ b/js/js.translator/testData/typescript-export/constructors/constructors__main.js @@ -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"; } diff --git a/js/js.translator/testData/typescript-export/constructors/constructors__main.ts b/js/js.translator/testData/typescript-export/constructors/constructors__main.ts index 3a81d7004c3..1271902ce0f 100644 --- a/js/js.translator/testData/typescript-export/constructors/constructors__main.ts +++ b/js/js.translator/testData/typescript-export/constructors/constructors__main.ts @@ -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"; } \ No newline at end of file