From 1481ad21f585c824235cb62b561ef958241cbeea Mon Sep 17 00:00:00 2001 From: Ilya Goncharov Date: Wed, 24 Nov 2021 12:25:50 +0000 Subject: [PATCH] Enum implementing exported interface [JS IR] Not export get instance enum function [JS IR] Enum corresponding class is not considered in export [JS IR] All enums are abstract and with private constructor [JS IR] Any methods is left in d.ts [JS IR] Make enum with declarations inside corresponding class [JS IR] Export of interface through fake override [JS IR] Include enum entry corresponding class members into export model Merge-request: KT-MR-5031 ^KT-49779 fixed ^KT-49773 fixed --- .../org/jetbrains/kotlin/ir/backend/js/Dce.kt | 2 +- .../ir/backend/js/DeclarationOrigins.kt | 3 +- .../ir/backend/js/export/ExportModel.kt | 11 +- .../backend/js/export/ExportModelGenerator.kt | 52 +++++--- .../js/export/ExportModelToTsDeclarations.kt | 5 +- .../js/lower/ClassReferenceLowering.kt | 2 +- .../ir/backend/js/lower/EnumClassLowering.kt | 3 +- .../transformers/irToJs/JsClassGenerator.kt | 12 +- .../kotlin/ir/backend/js/StatementOrigins.kt | 1 + .../testData/box/export/exportEnumClass.kt | 20 +-- .../declarations/declarations.d.ts | 2 +- .../inheritance/inheritance.d.ts | 57 +++++++++ .../inheritance/inheritance.kt | 118 +++++++++++++++++- .../inheritance/inheritance__main.js | 99 +++++++++++++++ .../inheritance/inheritance__main.ts | 74 +++++++++++ .../visibility/visibility.d.ts | 15 +++ .../visibility/visibility.kt | 5 + 17 files changed, 440 insertions(+), 41 deletions(-) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/Dce.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/Dce.kt index 6b0f3e319ae..55edf0dc08d 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/Dce.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/Dce.kt @@ -405,7 +405,7 @@ fun usefulDeclarations( // https://youtrack.jetbrains.com/issue/KT-46672 // TODO: Possibly solution with origin is not so good // There is option with applying this hack to jsGetKClass - if (expression.origin == JsLoweredDeclarationOrigin.CLASS_REFERENCE) { + if (expression.origin == JsStatementOrigins.CLASS_REFERENCE) { // Maybe we need to filter primary constructor // Although at this time, we should have only primary constructor (ref as IrClass) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/DeclarationOrigins.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/DeclarationOrigins.kt index 40a538fcbb6..ca8ad59c6c0 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/DeclarationOrigins.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/DeclarationOrigins.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.ir.backend.js import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl -import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl object JsLoweredDeclarationOrigin : IrDeclarationOrigin { object JS_INTRINSICS_STUB : IrDeclarationOriginImpl("JS_INTRINSICS_STUB") @@ -16,5 +15,5 @@ object JsLoweredDeclarationOrigin : IrDeclarationOrigin { object BRIDGE_WITHOUT_STABLE_NAME : IrDeclarationOriginImpl("BRIDGE_WITHOUT_STABLE_NAME") object OBJECT_GET_INSTANCE_FUNCTION : IrDeclarationOriginImpl("OBJECT_GET_INSTANCE_FUNCTION") object JS_SHADOWED_EXPORT : IrDeclarationOriginImpl("JS_SHADOWED_EXPORT") - object CLASS_REFERENCE : IrStatementOriginImpl("CLASS_REFERENCE") + object ENUM_GET_INSTANCE_FUNCTION : IrDeclarationOriginImpl("ENUM_GET_INSTANCE_FUNCTION") } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModel.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModel.kt index f262aafc4ae..5405d5ef6d2 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModel.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModel.kt @@ -37,8 +37,11 @@ data class ExportedFunction( data class ExportedConstructor( val parameters: List, + val visibility: ExportedVisibility +) : ExportedDeclaration() { val isProtected: Boolean -) : ExportedDeclaration() + get() = visibility == ExportedVisibility.PROTECTED +} data class ExportedConstructSignature( val parameters: List, @@ -131,3 +134,9 @@ sealed class ExportedType { fun withImplicitlyExported(implicitlyExportedType: Boolean) = if (implicitlyExportedType) ImplicitlyExportedType(this) else this } + +enum class ExportedVisibility(val keyword: String) { + DEFAULT(""), + PRIVATE("private "), + PROTECTED("protected ") +} 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 930e6378a2a..a9febeea511 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 @@ -10,12 +10,14 @@ import org.jetbrains.kotlin.backend.common.ir.isMethodOfAny import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.DescriptorVisibilities +import org.jetbrains.kotlin.descriptors.DescriptorVisibility import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin import org.jetbrains.kotlin.ir.backend.js.lower.ES6AddInternalParametersToConstructorPhase.ES6_INIT_BOX_PARAMETER import org.jetbrains.kotlin.ir.backend.js.lower.ES6AddInternalParametersToConstructorPhase.ES6_RESULT_TYPE_PARAMETER import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName +import org.jetbrains.kotlin.ir.backend.js.utils.isExportedInterface import org.jetbrains.kotlin.ir.backend.js.utils.isJsExport import org.jetbrains.kotlin.ir.backend.js.utils.sanitizeName import org.jetbrains.kotlin.ir.declarations.* @@ -71,8 +73,12 @@ class ExportModelGenerator( } } - private fun exportFunction(function: IrSimpleFunction): ExportedDeclaration? = - when (val exportability = functionExportability(function)) { + private fun exportFunction(function: IrSimpleFunction): ExportedDeclaration? { + if (function.origin == JsLoweredDeclarationOrigin.ENUM_GET_INSTANCE_FUNCTION) { + return null + } + + return when (val exportability = functionExportability(function)) { is Exportability.NotNeeded -> null is Exportability.Prohibited -> ErrorDeclaration(exportability.reason) is Exportability.Allowed -> { @@ -90,6 +96,7 @@ class ExportModelGenerator( ) } } + } private fun exportConstructor(constructor: IrConstructor): ExportedDeclaration? { if (!constructor.isPrimary) return null @@ -97,7 +104,7 @@ class ExportModelGenerator( constructor.valueParameters.filterNot { it.origin === ES6_RESULT_TYPE_PARAMETER || it.origin === ES6_INIT_BOX_PARAMETER } return ExportedConstructor( parameters = allValueParameters.map { exportParameter(it) }, - isProtected = constructor.visibility == DescriptorVisibilities.PROTECTED + visibility = constructor.visibility.toExportedVisibility() ) } @@ -115,7 +122,7 @@ class ExportModelGenerator( // TODO: Report a frontend error if (accessor.extensionReceiverParameter != null) return null - if (accessor.isFakeOverride && !accessor.isEnumFakeOverriddenDeclaration(context)) { + if (accessor.isFakeOverride && !accessor.isAllowedFakeOverriddenDeclaration(context)) { return null } } @@ -254,11 +261,20 @@ class ExportModelGenerator( enumExportedMember } + val privateConstructor = ExportedConstructor( + parameters = emptyList(), + visibility = ExportedVisibility.PRIVATE + ) + return exportClass( klass, - members, + listOf(privateConstructor) + members, nestedClasses - ) + ).let { + (it as ExportedClass).copy( + isAbstract = true, + ) + } } private fun exportClassDeclarations( @@ -382,7 +398,7 @@ class ExportModelGenerator( val enumEntries = enumEntriesToOrdinal.keys return when (candidate) { is IrProperty -> { - if (candidate.isEnumFakeOverriddenDeclaration(context)) { + if (candidate.isAllowedFakeOverriddenDeclaration(context)) { val type: ExportedType? = when (candidate.getExportedIdentifier()) { "name" -> enumEntries .map { it.getExportedIdentifier() } @@ -507,7 +523,7 @@ class ExportModelGenerator( return Exportability.Prohibited("Inline reified function") if (function.isSuspend) return Exportability.Prohibited("Suspend function") - if (function.isFakeOverride) + if (function.isFakeOverride && !function.isAllowedFakeOverriddenDeclaration(context)) return Exportability.NotNeeded if (function.origin == JsLoweredDeclarationOrigin.BRIDGE_WITHOUT_STABLE_NAME || function.origin == JsLoweredDeclarationOrigin.BRIDGE_WITH_STABLE_NAME || @@ -524,9 +540,6 @@ class ExportModelGenerator( return Exportability.NotNeeded } - if (function.isFakeOverriddenFromAny()) - return Exportability.NotNeeded - val nameString = function.name.asString() if (nameString.endsWith("-impl")) return Exportability.NotNeeded @@ -605,7 +618,7 @@ private fun shouldDeclarationBeExported(declaration: IrDeclarationWithName, cont if (overriddenNonEmpty) { return declaration.isOverriddenExported(context) || (declaration as? IrSimpleFunction)?.isMethodOfAny() == true // Handle names for special functions - || declaration.isEnumFakeOverriddenDeclaration(context) + || declaration.isAllowedFakeOverriddenDeclaration(context) } } @@ -619,12 +632,17 @@ private fun shouldDeclarationBeExported(declaration: IrDeclarationWithName, cont } } -fun IrOverridableDeclaration<*>.isEnumFakeOverriddenDeclaration(context: JsIrBackendContext?): Boolean { +fun IrOverridableDeclaration<*>.isAllowedFakeOverriddenDeclaration(context: JsIrBackendContext?): Boolean { + if (this.resolveFakeOverride(allowAbstract = true)?.parentClassOrNull.isExportedInterface()) { + return true + } + return context?.irBuiltIns?.enumClass?.let { enumClass -> overriddenSymbols .asSequence() .map { it.owner } - .filterIsInstance() + .filterIsInstance>() + .filter { it.overriddenSymbols.isEmpty() } .mapNotNull { it.parentClassOrNull } .map { it.symbol } .any { it == enumClass } @@ -640,6 +658,12 @@ fun IrDeclaration.isExported(context: JsIrBackendContext?): Boolean { return shouldDeclarationBeExported(candidate, context) } +private fun DescriptorVisibility.toExportedVisibility() = + when (this) { + DescriptorVisibilities.PROTECTED -> ExportedVisibility.PROTECTED + else -> ExportedVisibility.DEFAULT + } + private val reservedWords = setOf( "break", "case", diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelToTsDeclarations.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelToTsDeclarations.kt index 7acb73c7d62..d7edb983fe8 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelToTsDeclarations.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelToTsDeclarations.kt @@ -93,9 +93,8 @@ fun ExportedDeclaration.toTypeScript(indent: String, prefix: String = ""): Strin } is ExportedConstructor -> { - val visibility = if (isProtected) "protected " else "" val renderedParameters = parameters.joinToString(", ") { it.toTypeScript(indent) } - "${visibility}constructor($renderedParameters);" + "${visibility.keyword}constructor($renderedParameters);" } is ExportedConstructSignature -> { @@ -220,7 +219,7 @@ fun ExportedClass.withProtectedConstructors(): ExportedClass { if (it !is ExportedConstructor || it.isProtected) { it } else { - it.copy(isProtected = true) + it.copy(visibility = ExportedVisibility.PROTECTED) } }) } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ClassReferenceLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ClassReferenceLowering.kt index 309a07f37ef..8f6f50e0b06 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ClassReferenceLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ClassReferenceLowering.kt @@ -142,7 +142,7 @@ class ClassReferenceLowering(val context: JsCommonBackendContext) : BodyLowering JsIrBuilder.buildCall( reflectionSymbols.getClassData, typeArguments = listOf(type), - origin = JsLoweredDeclarationOrigin.CLASS_REFERENCE + origin = JsStatementOrigins.CLASS_REFERENCE ) private fun buildCall(name: IrSimpleFunctionSymbol, vararg args: IrExpression): IrExpression = diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt index 97955fb4a45..b2f7ae9eb62 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.DescriptorVisibilities.PRIVATE import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext +import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor @@ -445,7 +446,7 @@ class EnumEntryCreateGetInstancesFunsLowering(val context: JsCommonBackendContex context.irFactory.buildFun { name = Name.identifier(createEntryAccessorName(irClass.name.identifier, enumEntry)) returnType = enumEntry.getType(irClass) - origin = JsIrBuilder.SYNTHESIZED_DECLARATION + origin = JsLoweredDeclarationOrigin.ENUM_GET_INSTANCE_FUNCTION }.apply { parent = irClass } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt index 1e4ac20a111..89cb920e5ca 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt @@ -6,9 +6,8 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs import org.jetbrains.kotlin.descriptors.DescriptorVisibilities -import org.jetbrains.kotlin.descriptors.DescriptorVisibility import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.ir.backend.js.export.isEnumFakeOverriddenDeclaration +import org.jetbrains.kotlin.ir.backend.js.export.isAllowedFakeOverriddenDeclaration import org.jetbrains.kotlin.ir.backend.js.export.isExported import org.jetbrains.kotlin.ir.backend.js.export.isOverriddenExported import org.jetbrains.kotlin.ir.backend.js.utils.* @@ -102,7 +101,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo classBlock.statements += generateClassMetadata() - if (!irClass.isInterface && !irClass.isEnumEntry) { + if (!irClass.isInterface) { for (property in properties) { if (property.getter?.extensionReceiverParameter != null || property.setter?.extensionReceiverParameter != null) continue @@ -110,7 +109,10 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo if (!property.visibility.isPublicAPI) continue - if (property.isFakeOverride && !property.isEnumFakeOverriddenDeclaration(context.staticContext.backendContext)) + if ( + property.isFakeOverride && + !property.isAllowedFakeOverriddenDeclaration(context.staticContext.backendContext) + ) continue fun IrSimpleFunction.propertyAccessorForwarder( @@ -145,7 +147,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo val noOverriddenExportedSetter = property.setter?.isOverriddenExported(context.staticContext.backendContext) == false val needsOverride = (overriddenExportedGetter && noOverriddenExportedSetter) || - property.isEnumFakeOverriddenDeclaration(context.staticContext.backendContext) + property.isAllowedFakeOverriddenDeclaration(context.staticContext.backendContext) if (irClass.isExported(context.staticContext.backendContext) && (overriddenSymbols.isEmpty() || needsOverride) || diff --git a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/StatementOrigins.kt b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/StatementOrigins.kt index 0da49c5ddda..2aa19dcb08e 100644 --- a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/StatementOrigins.kt +++ b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/StatementOrigins.kt @@ -18,4 +18,5 @@ interface JsStatementOrigins { object FACTORY_ORIGIN : IrDeclarationOriginImpl("FACTORY_ORIGIN") object COROUTINE_ROOT_LOOP : IrStatementOriginImpl("COROUTINE_ROOT_LOOP") object COROUTINE_SWITCH : IrStatementOriginImpl("COROUTINE_SWITCH") + object CLASS_REFERENCE : IrStatementOriginImpl("CLASS_REFERENCE") } \ No newline at end of file diff --git a/js/js.translator/testData/box/export/exportEnumClass.kt b/js/js.translator/testData/box/export/exportEnumClass.kt index d66c439819d..334d94787ec 100644 --- a/js/js.translator/testData/box/export/exportEnumClass.kt +++ b/js/js.translator/testData/box/export/exportEnumClass.kt @@ -29,6 +29,7 @@ enum class Bar { init { d = "d2" } + fun huh() = "huh" }; val foo = ordinal @@ -66,19 +67,20 @@ function box() { if (this["export_enum_class"].Bar.A.bay() !== "A") return "fail15" if (this["export_enum_class"].Bar.B.bay() !== "B") return "fail16" - if (this["export_enum_class"].Bar.B.constructor.prototype.hasOwnProperty('baz')) return "fail17" + if (this["export_enum_class"].Bar.B.constructor.prototype.hasOwnProperty('d')) return "fail17" + if (this["export_enum_class"].Bar.B.constructor.prototype.hasOwnProperty('huh')) return "fail18" - if (this["export_enum_class"].Foo.valueOf("A") !== this["export_enum_class"].Foo.A) return "fail18" - if (this["export_enum_class"].Foo.valueOf("B") !== this["export_enum_class"].Foo.B) return "fail19" + if (this["export_enum_class"].Foo.valueOf("A") !== this["export_enum_class"].Foo.A) return "fail19" + if (this["export_enum_class"].Foo.valueOf("B") !== this["export_enum_class"].Foo.B) return "fail20" - if (this["export_enum_class"].Foo.values().indexOf(this["export_enum_class"].Foo.A) === -1) return "fail20" - if (this["export_enum_class"].Foo.values().indexOf(this["export_enum_class"].Foo.B) === -1) return "fail21" + if (this["export_enum_class"].Foo.values().indexOf(this["export_enum_class"].Foo.A) === -1) return "fail21" + if (this["export_enum_class"].Foo.values().indexOf(this["export_enum_class"].Foo.B) === -1) return "fail22" - if (this["export_enum_class"].Foo.A.name !== "A") return "fail22" - if (this["export_enum_class"].Foo.B.name !== "B") return "fail23" + if (this["export_enum_class"].Foo.A.name !== "A") return "fail23" + if (this["export_enum_class"].Foo.B.name !== "B") return "fail24" - if (this["export_enum_class"].Foo.A.ordinal !== 0) return "fail24" - if (this["export_enum_class"].Foo.B.ordinal !== 1) return "fail23" + if (this["export_enum_class"].Foo.A.ordinal !== 0) return "fail25" + if (this["export_enum_class"].Foo.B.ordinal !== 1) return "fail26" return "OK" } \ No newline at end of file diff --git a/js/js.translator/testData/typescript-export/declarations/declarations.d.ts b/js/js.translator/testData/typescript-export/declarations/declarations.d.ts index 3ccd1d33c13..fb0e2ba2abf 100644 --- a/js/js.translator/testData/typescript-export/declarations/declarations.d.ts +++ b/js/js.translator/testData/typescript-export/declarations/declarations.d.ts @@ -100,7 +100,7 @@ declare namespace JS_TESTS { readonly prop: string; } } - class TestEnumClass { + abstract class TestEnumClass { private constructor(); readonly constructorParameter: string; static readonly A: foo.TestEnumClass & { diff --git a/js/js.translator/testData/typescript-export/inheritance/inheritance.d.ts b/js/js.translator/testData/typescript-export/inheritance/inheritance.d.ts index 07241a5220e..edc86ef62ed 100644 --- a/js/js.translator/testData/typescript-export/inheritance/inheritance.d.ts +++ b/js/js.translator/testData/typescript-export/inheritance/inheritance.d.ts @@ -37,5 +37,62 @@ declare namespace JS_TESTS { const O2: { foo(): number; } & foo.OC; + interface I3 { + readonly foo: string; + bar: string; + readonly baz: string; + bay(): string; + readonly __doNotUseIt: __doNotImplementIt; + } + function getI3(): foo.I3; + function getA(): foo.I3; + function getB(): foo.I3; + function getC(): foo.I3; + abstract class A2 implements foo.I3 { + constructor(); + abstract readonly foo: string; + abstract bar: string; + abstract readonly baz: string; + abstract bay(): string; + readonly __doNotUseIt: __doNotImplementIt; + } + class B2 extends foo.A2 { + constructor(); + readonly foo: string; + bar: string; + readonly baz: string; + bay(): string; + } + class C2 extends foo.B2 { + constructor(); + readonly foo: string; + bar: string; + baz: string; + bay(): string; + } + abstract class EC implements foo.I3 { + private constructor(); + static readonly EC1: foo.EC & { + readonly name: "EC1"; + readonly ordinal: 0; + }; + static readonly EC2: foo.EC & { + readonly name: "EC2"; + readonly ordinal: 1; + }; + static readonly EC3: foo.EC & { + readonly name: "EC3"; + readonly ordinal: 2; + }; + readonly foo: string; + bar: string; + bay(): string; + static values(): Array; + static valueOf(value: string): foo.EC; + readonly name: "EC1" | "EC2" | "EC3"; + readonly ordinal: 0 | 1 | 2; + abstract readonly baz: string; + readonly __doNotUseIt: __doNotImplementIt; + } } } diff --git a/js/js.translator/testData/typescript-export/inheritance/inheritance.kt b/js/js.translator/testData/typescript-export/inheritance/inheritance.kt index 7f1080a20fa..cd484e10328 100644 --- a/js/js.translator/testData/typescript-export/inheritance/inheritance.kt +++ b/js/js.translator/testData/typescript-export/inheritance/inheritance.kt @@ -7,22 +7,23 @@ // MODULE: JS_TESTS // FILE: inheritance.kt -@file:JsExport - package foo +@JsExport external interface I { var x: T val y: S fun z(u: U) } +@JsExport external interface I2 { var x: String val y: Boolean fun z(z: Int) } +@JsExport abstract class AC : I2 { override var x = "AC" override abstract val y: Boolean @@ -32,6 +33,7 @@ abstract class AC : I2 { abstract val acAbstractProp: String } +@JsExport open class OC( override val y: Boolean, override val acAbstractProp: String @@ -43,11 +45,121 @@ open class OC( private fun privateFun(): String = "privateFun" } +@JsExport final class FC : OC(true, "FC") +@JsExport object O1 : OC(true, "O1") +@JsExport object O2 : OC(true, "O2") { @JsName("foo") // TODO: Should work without JsName fun foo(): Int = 10 -} \ No newline at end of file +} + +@JsExport +interface I3 { + val foo: String + var bar: String + val baz: String + + fun bay(): String +} + +@JsExport +fun getI3(): I3 = object : I3 { + override val foo: String = "fooI3" + + override var bar: String = "barI3" + + override var baz: String = "bazI3" + + override fun bay(): String = "bayI3" +} + +abstract class A : I3 + +@JsExport +fun getA(): I3 = object : A() { + override val foo: String = "fooA" + + override var bar: String = "barA" + + override var baz: String = "bazA" + + override fun bay(): String = "bayA" +} + +open class B : A() { + override val foo: String = "fooB" + + override var bar: String = "barB" + + override val baz: String = "bazB" + + override fun bay(): String = "bayB" +} + +@JsExport +fun getB(): I3 = B() + +open class C : B() { + override val foo: String = "fooC" + + override var bar: String = "barC" + + override var baz: String = "bazC" + + override fun bay(): String = "bayC" +} + +@JsExport +fun getC(): I3 = C() + +@JsExport +abstract class A2 : I3 + +@JsExport +open class B2 : A2() { + override val foo: String = "fooB2" + + override var bar: String = "barB2" + + override val baz: String = "bazB2" + + override fun bay(): String = "bayB2" +} + +@JsExport +open class C2 : B2() { + override val foo: String = "fooC2" + + override var bar: String = "barC2" + + override var baz: String = "bazC2" + + override fun bay(): String = "bayC2" +} + +@JsExport +enum class EC : I3 { + EC1 { + override var baz = "ec1" + + val bah = "bah" + + fun huh() = "huh" + }, + EC2 { + override var baz = "ec2" + }, + EC3 { + override var baz = "ec3" + }; + + override val foo: String = "foo" + + override var bar = "bar" + + override fun bay(): String = "bay" +} diff --git a/js/js.translator/testData/typescript-export/inheritance/inheritance__main.js b/js/js.translator/testData/typescript-export/inheritance/inheritance__main.js index 9540ab956b0..b25545bf97c 100644 --- a/js/js.translator/testData/typescript-export/inheritance/inheritance__main.js +++ b/js/js.translator/testData/typescript-export/inheritance/inheritance__main.js @@ -17,6 +17,13 @@ var AC = JS_TESTS.foo.AC; var FC = JS_TESTS.foo.FC; var O1 = JS_TESTS.foo.O1; var O2 = JS_TESTS.foo.O2; +var getI3 = JS_TESTS.foo.getI3; +var getA = JS_TESTS.foo.getA; +var getB = JS_TESTS.foo.getB; +var getC = JS_TESTS.foo.getC; +var B2 = JS_TESTS.foo.B2; +var C2 = JS_TESTS.foo.C2; +var EC = JS_TESTS.foo.EC; var Impl = /** @class */ (function (_super) { __extends(Impl, _super); function Impl() { @@ -36,6 +43,16 @@ var Impl = /** @class */ (function (_super) { }); return Impl; }(AC)); +// class A2Impl extends A2 { +// bar: string = "barA2" +// readonly baz: string = "bazA2" +// readonly foo: string = "fooA2" +// +// bay(): string { +// return "bayA2"; +// } +// +// } function box() { var impl = new Impl(); if (impl.acProp !== "acProp") @@ -66,5 +83,87 @@ function box() { return "Fail 9"; if (O2.foo() != 10) return "Fail 10"; + if (getI3().foo != "fooI3") + return "Fail 11"; + if (getI3().bar != "barI3") + return "Fail 12"; + if (getI3().baz != "bazI3") + return "Fail 13"; + if (getI3().bay() != "bayI3") + return "Fail 14"; + if (getA().foo != "fooA") + return "Fail 15"; + if (getA().bar != "barA") + return "Fail 16"; + if (getA().baz != "bazA") + return "Fail 17"; + if (getA().bay() != "bayA") + return "Fail 18"; + if (getB().foo != "fooB") + return "Fail 19"; + if (getB().bar != "barB") + return "Fail 20"; + if (getB().baz != "bazB") + return "Fail 21"; + if (getB().bay() != "bayB") + return "Fail 22"; + if (getC().foo != "fooC") + return "Fail 23"; + if (getC().bar != "barC") + return "Fail 24"; + if (getC().baz != "bazC") + return "Fail 25"; + if (getC().bay() != "bayC") + return "Fail 26"; + // const a2Impl = new A2Impl() + // if (a2Impl.foo != "fooA2") return "Fail 27" + // if (a2Impl.bar != "barA2") return "Fail 28" + // if (a2Impl.baz != "bazA2") return "Fail 29" + // if (a2Impl.bay() != "bayA2") return "Fail 30" + var b2 = new B2(); + if (b2.foo != "fooB2") + return "Fail 31"; + if (b2.bar != "barB2") + return "Fail 32"; + if (b2.baz != "bazB2") + return "Fail 33"; + if (b2.bay() != "bayB2") + return "Fail 34"; + var c2 = new C2(); + if (c2.foo != "fooC2") + return "Fail 35"; + if (c2.bar != "barC2") + return "Fail 36"; + if (c2.baz != "bazC2") + return "Fail 37"; + c2.baz = "bazC2-2"; + if (c2.baz != "bazC2-2") + return "Fail 38"; + if (c2.bay() != "bayC2") + return "Fail 39"; + if (EC.EC1.foo != "foo") + return "Fail 40"; + if (EC.EC1.bar != "bar") + return "Fail 41"; + if (EC.EC1.baz != "ec1") + return "Fail 42"; + if (EC.EC1.bay() != "bay") + return "Fail 43"; + if (EC.EC2.foo != "foo") + return "Fail 44"; + if (EC.EC2.bar != "bar") + return "Fail 45"; + if (EC.EC2.baz != "ec2") + return "Fail 46"; + if (EC.EC2.bay() != "bay") + return "Fail 47"; + if (EC.EC3.foo != "foo") + return "Fail 48"; + if (EC.EC3.bar != "bar") + return "Fail 49"; + if (EC.EC3.baz != "ec3") + return "Fail 50"; + if (EC.EC3.bay() != "bay") + return "Fail 51"; return "OK"; } diff --git a/js/js.translator/testData/typescript-export/inheritance/inheritance__main.ts b/js/js.translator/testData/typescript-export/inheritance/inheritance__main.ts index aa47a3b68d3..cd0be08464c 100644 --- a/js/js.translator/testData/typescript-export/inheritance/inheritance__main.ts +++ b/js/js.translator/testData/typescript-export/inheritance/inheritance__main.ts @@ -3,6 +3,13 @@ import AC = JS_TESTS.foo.AC; import FC = JS_TESTS.foo.FC; import O1 = JS_TESTS.foo.O1; import O2 = JS_TESTS.foo.O2; +import getI3 = JS_TESTS.foo.getI3; +import getA = JS_TESTS.foo.getA; +import getB = JS_TESTS.foo.getB; +import getC = JS_TESTS.foo.getC; +import B2 = JS_TESTS.foo.B2; +import C2 = JS_TESTS.foo.C2; +import EC = JS_TESTS.foo.EC; class Impl extends AC { z(z: number): void { @@ -12,6 +19,18 @@ class Impl extends AC { get y(): boolean { return true; } } +// TODO: Uncomment with fix of export open properties +// class A2Impl extends A2 { +// bar: string = "barA2" +// readonly baz: string = "bazA2" +// readonly foo: string = "fooA2" +// +// bay(): string { +// return "bayA2"; +// } +// +// } + function box(): string { const impl = new Impl(); if (impl.acProp !== "acProp") return "Fail 1"; @@ -36,5 +55,60 @@ function box(): string { if (O2.acAbstractProp != "O2") return "Fail 9"; if (O2.foo() != 10) return "Fail 10"; + if (getI3().foo != "fooI3") return "Fail 11" + if (getI3().bar != "barI3") return "Fail 12" + if (getI3().baz != "bazI3") return "Fail 13" + if (getI3().bay() != "bayI3") return "Fail 14" + + if (getA().foo != "fooA") return "Fail 15" + if (getA().bar != "barA") return "Fail 16" + if (getA().baz != "bazA") return "Fail 17" + if (getA().bay() != "bayA") return "Fail 18" + + if (getB().foo != "fooB") return "Fail 19" + if (getB().bar != "barB") return "Fail 20" + if (getB().baz != "bazB") return "Fail 21" + if (getB().bay() != "bayB") return "Fail 22" + + if (getC().foo != "fooC") return "Fail 23" + if (getC().bar != "barC") return "Fail 24" + if (getC().baz != "bazC") return "Fail 25" + if (getC().bay() != "bayC") return "Fail 26" + + // const a2Impl = new A2Impl() + // if (a2Impl.foo != "fooA2") return "Fail 27" + // if (a2Impl.bar != "barA2") return "Fail 28" + // if (a2Impl.baz != "bazA2") return "Fail 29" + // if (a2Impl.bay() != "bayA2") return "Fail 30" + + const b2 = new B2() + if (b2.foo != "fooB2") return "Fail 31" + if (b2.bar != "barB2") return "Fail 32" + if (b2.baz != "bazB2") return "Fail 33" + if (b2.bay() != "bayB2") return "Fail 34" + + const c2 = new C2() + if (c2.foo != "fooC2") return "Fail 35" + if (c2.bar != "barC2") return "Fail 36" + if (c2.baz != "bazC2") return "Fail 37" + c2.baz = "bazC2-2" + if (c2.baz != "bazC2-2") return "Fail 38" + if (c2.bay() != "bayC2") return "Fail 39" + + if (EC.EC1.foo != "foo") return "Fail 40" + if (EC.EC1.bar != "bar") return "Fail 41" + if (EC.EC1.baz != "ec1") return "Fail 42" + if (EC.EC1.bay() != "bay") return "Fail 43" + + if (EC.EC2.foo != "foo") return "Fail 44" + if (EC.EC2.bar != "bar") return "Fail 45" + if (EC.EC2.baz != "ec2") return "Fail 46" + if (EC.EC2.bay() != "bay") return "Fail 47" + + if (EC.EC3.foo != "foo") return "Fail 48" + if (EC.EC3.bar != "bar") return "Fail 49" + if (EC.EC3.baz != "ec3") return "Fail 50" + if (EC.EC3.bay() != "bay") return "Fail 51" + return "OK"; } \ No newline at end of file diff --git a/js/js.translator/testData/typescript-export/visibility/visibility.d.ts b/js/js.translator/testData/typescript-export/visibility/visibility.d.ts index ab35f3c44ed..78aeb0e8aff 100644 --- a/js/js.translator/testData/typescript-export/visibility/visibility.d.ts +++ b/js/js.translator/testData/typescript-export/visibility/visibility.d.ts @@ -33,4 +33,19 @@ declare namespace JS_TESTS { constructor(); } } + abstract class EnumClass { + private constructor(); + static readonly EC1: EnumClass & { + readonly name: "EC1"; + readonly ordinal: 0; + }; + static readonly EC2: EnumClass & { + readonly name: "EC2"; + readonly ordinal: 1; + }; + static values(): Array; + static valueOf(value: string): EnumClass; + readonly name: "EC1" | "EC2"; + readonly ordinal: 0 | 1; + } } diff --git a/js/js.translator/testData/typescript-export/visibility/visibility.kt b/js/js.translator/testData/typescript-export/visibility/visibility.kt index 221ac446282..b7b7a5d8934 100644 --- a/js/js.translator/testData/typescript-export/visibility/visibility.kt +++ b/js/js.translator/testData/typescript-export/visibility/visibility.kt @@ -54,4 +54,9 @@ open class Class { @JsName("publicFun") // TODO: Should work without JsName public fun publicFun() = 10 public class publicClass +} + +enum class EnumClass { + EC1, + EC2 } \ No newline at end of file