diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
index 952c7141716..b7c117d82c0 100644
--- a/.idea/kotlinc.xml
+++ b/.idea/kotlinc.xml
@@ -8,7 +8,4 @@
-
-
-
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 9e08f8566b0..b0515b65302 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
@@ -70,7 +70,7 @@ sealed class ExportedClass : ExportedDeclaration() {
abstract val name: String
abstract val ir: IrClass
abstract val members: List
- abstract val superClass: ExportedType?
+ abstract val superClasses: List
abstract val superInterfaces: List
abstract val nestedClasses: List
}
@@ -79,7 +79,7 @@ data class ExportedRegularClass(
override val name: String,
val isInterface: Boolean = false,
val isAbstract: Boolean = false,
- override val superClass: ExportedType? = null,
+ override val superClasses: List = emptyList(),
override val superInterfaces: List = emptyList(),
val typeParameters: List,
override val members: List,
@@ -89,7 +89,7 @@ data class ExportedRegularClass(
data class ExportedObject(
override val name: String,
- override val superClass: ExportedType? = null,
+ override val superClasses: List = emptyList(),
override val superInterfaces: List = emptyList(),
override val members: List,
override val nestedClasses: List,
@@ -115,6 +115,7 @@ sealed class ExportedType {
object String : Primitive("string")
object Throwable : Primitive("Error")
object Any : Primitive("any")
+ object Unknown : Primitive("unknown")
object Unit : Primitive("void")
object Nothing : Primitive("never")
object UniqueSymbol : Primitive("unique symbol")
@@ -147,16 +148,16 @@ sealed class ExportedType {
class PropertyType(val container: ExportedType, val propertyName: ExportedType) : ExportedType()
- class ImplicitlyExportedType(val type: ExportedType) : ExportedType() {
+ data class ImplicitlyExportedType(val type: ExportedType, val exportedSupertype: ExportedType) : ExportedType() {
override fun withNullability(nullable: Boolean) =
- ImplicitlyExportedType(type.withNullability(nullable))
+ ImplicitlyExportedType(type.withNullability(nullable), exportedSupertype.withNullability(nullable))
}
open fun withNullability(nullable: Boolean) =
if (nullable) Nullable(this) else this
- fun withImplicitlyExported(implicitlyExportedType: Boolean) =
- if (implicitlyExportedType) ImplicitlyExportedType(this) else this
+ fun withImplicitlyExported(implicitlyExportedType: Boolean, exportedSupertype: ExportedType) =
+ if (implicitlyExportedType) ImplicitlyExportedType(this, exportedSupertype) else this
}
enum class ExportedVisibility(val keyword: String) {
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 1c36ea1bd83..e87cabca115 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
@@ -24,14 +24,14 @@ import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.serialization.js.ModuleKind
import org.jetbrains.kotlin.utils.addIfNotNull
+import org.jetbrains.kotlin.utils.addToStdlib.runIf
import org.jetbrains.kotlin.utils.keysToMap
private const val magicPropertyName = "__doNotUseOrImplementIt"
-class ExportModelGenerator(
- val context: JsIrBackendContext,
- val generateNamespacesForPackages: Boolean
-) {
+class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespacesForPackages: Boolean) {
+ private val transitiveExportCollector = TransitiveExportCollector(context)
+
fun generateExport(file: IrPackageFragment): List {
val namespaceFqName = file.fqName
val exports = file.declarations.flatMap { declaration -> listOfNotNull(exportDeclaration(declaration)) }
@@ -64,10 +64,14 @@ class ExportModelGenerator(
}
}
- private fun exportClass(candidate: IrClass) = if (candidate.isEnumClass) {
- exportEnumClass(candidate)
- } else {
- exportOrdinaryClass(candidate)
+ private fun exportClass(candidate: IrClass): ExportedDeclaration? {
+ val superTypes = candidate.defaultType.collectSuperTransitiveHierarchy() + candidate.superTypes
+
+ return if (candidate.isEnumClass) {
+ exportEnumClass(candidate, superTypes)
+ } else {
+ exportOrdinaryClass(candidate, superTypes)
+ }
}
private fun exportFunction(function: IrSimpleFunction): ExportedDeclaration? {
@@ -203,9 +207,7 @@ class ExportModelGenerator(
return Exportability.Allowed
}
- private fun exportOrdinaryClass(
- klass: IrClass
- ): ExportedDeclaration? {
+ private fun exportOrdinaryClass(klass: IrClass, superTypes: Iterable): ExportedDeclaration? {
when (val exportability = classExportability(klass)) {
is Exportability.Prohibited -> error(exportability.reason)
is Exportability.NotNeeded -> return null
@@ -213,18 +215,17 @@ class ExportModelGenerator(
}
}
- val (members, nestedClasses) = exportClassDeclarations(klass)
+ val (members, nestedClasses) = exportClassDeclarations(klass, superTypes)
return exportClass(
klass,
+ superTypes,
members,
nestedClasses
)
}
- private fun exportEnumClass(
- klass: IrClass
- ): ExportedDeclaration? {
+ private fun exportEnumClass(klass: IrClass, superTypes: Iterable): ExportedDeclaration? {
when (val exportability = classExportability(klass)) {
is Exportability.Prohibited -> error(exportability.reason)
is Exportability.NotNeeded -> return null
@@ -241,7 +242,7 @@ class ExportModelGenerator(
enumEntries
.keysToMap(enumEntries::indexOf)
- val (members, nestedClasses) = exportClassDeclarations(klass) { candidate ->
+ val (members, nestedClasses) = exportClassDeclarations(klass, superTypes) { candidate ->
val enumExportedMember = exportAsEnumMember(candidate, enumEntriesToOrdinal)
enumExportedMember
}
@@ -253,15 +254,15 @@ class ExportModelGenerator(
return exportClass(
klass,
+ superTypes,
listOf(privateConstructor) + members,
nestedClasses
- ).let {
- (it as ExportedRegularClass).copy(isAbstract = true)
- }
+ )
}
private fun exportClassDeclarations(
klass: IrClass,
+ superTypes: Iterable,
specialProcessing: (IrDeclarationWithName) -> ExportedDeclaration? = { null }
): ExportedClassDeclarationsInfo {
val members = mutableListOf()
@@ -310,8 +311,8 @@ class ExportModelGenerator(
}
}
- if (klass.shouldContainImplementationOfMagicProperty()) {
- members.addMagicPropertyForInterfaceImplementation(klass)
+ if (klass.shouldContainImplementationOfMagicProperty(superTypes)) {
+ members.addMagicPropertyForInterfaceImplementation(klass, superTypes)
} else if (klass.shouldNotBeImplemented()) {
members.addMagicInterfaceProperty(klass)
}
@@ -326,7 +327,7 @@ class ExportModelGenerator(
return isInterface && !isExternal
}
- private fun IrClass.shouldContainImplementationOfMagicProperty(): Boolean {
+ private fun IrClass.shouldContainImplementationOfMagicProperty(superTypes: Iterable): Boolean {
return !isExternal && superTypes.any {
val superClass = it.classOrNull?.owner ?: return@any false
superClass.isInterface && superClass.isExported(context)
@@ -337,8 +338,8 @@ class ExportModelGenerator(
add(ExportedProperty(name = magicPropertyName, type = klass.generateTagType(), mutable = false, isMember = true, isField = true))
}
- private fun MutableList.addMagicPropertyForInterfaceImplementation(klass: IrClass) {
- val superTypesToInheritanceMagicProperty = klass.superTypes.filter { it.shouldAddMagicPropertyOfSuper() }
+ private fun MutableList.addMagicPropertyForInterfaceImplementation(klass: IrClass, superTypes: Iterable) {
+ val superTypesToInheritanceMagicProperty = superTypes.filter { it.shouldAddMagicPropertyOfSuper() }
if (superTypesToInheritanceMagicProperty.isEmpty()) return
@@ -375,20 +376,20 @@ class ExportModelGenerator(
private fun exportClass(
klass: IrClass,
+ superTypes: Iterable,
members: List,
- nestedClasses: List
+ nestedClasses: List,
): ExportedDeclaration {
val typeParameters = klass.typeParameters.map(::exportTypeParameter)
- // TODO: Handle non-exported super types
+ val superClasses = superTypes
+ .filter { !it.classifierOrFail.isInterface && it.canBeUsedAsSuperTypeOfExportedClasses() }
+ .map { exportType(it, false) }
+ .filter { it !is ExportedType.ErrorType }
- val superType = klass.superTypes
- .firstOrNull { !it.classifierOrFail.isInterface && it.canBeUsedAsSuperTypeOfExportedClasses() }
- ?.let { exportType(it).takeIf { it !is ExportedType.ErrorType } }
-
- val superInterfaces = klass.superTypes
+ val superInterfaces = superTypes
.filter { it.classifierOrFail.isInterface }
- .map { exportType(it) }
+ .map { exportType(it, false) }
.filter { it !is ExportedType.ErrorType }
val name = klass.getExportedIdentifier()
@@ -398,7 +399,7 @@ class ExportModelGenerator(
ir = klass,
name = name,
members = members,
- superClass = superType,
+ superClasses = superClasses,
nestedClasses = nestedClasses,
superInterfaces = superInterfaces,
irGetter = context.mapping.objectToGetInstanceFunction[klass]!!
@@ -407,8 +408,8 @@ class ExportModelGenerator(
ExportedRegularClass(
name = name,
isInterface = klass.isInterface,
- isAbstract = klass.modality == Modality.ABSTRACT || klass.modality == Modality.SEALED,
- superClass = superType,
+ isAbstract = klass.modality == Modality.ABSTRACT || klass.modality == Modality.SEALED || klass.isEnumClass,
+ superClasses = superClasses,
superInterfaces = superInterfaces,
typeParameters = typeParameters,
members = members,
@@ -418,6 +419,9 @@ class ExportModelGenerator(
}
}
+ private fun IrSimpleType.collectSuperTransitiveHierarchy() =
+ transitiveExportCollector.collectSuperTypesTransitiveHierarchyFor(this)
+
private fun exportAsEnumMember(
candidate: IrDeclarationWithName,
enumEntriesToOrdinal: Map
@@ -471,8 +475,15 @@ class ExportModelGenerator(
private fun exportTypeParameter(typeParameter: IrTypeParameter): ExportedType.TypeParameter {
val constraint = typeParameter.superTypes.asSequence()
.filter { it != context.irBuiltIns.anyNType }
- .map(::exportType)
- .filter { it !is ExportedType.ErrorType && it !is ExportedType.ImplicitlyExportedType }
+ .map {
+ val exportedType = exportType(it)
+ if (exportedType is ExportedType.ImplicitlyExportedType && exportedType.exportedSupertype == ExportedType.Primitive.Any) {
+ exportedType.copy(exportedSupertype = ExportedType.Primitive.Unknown)
+ } else {
+ exportedType
+ }
+ }
+ .filter { it !is ExportedType.ErrorType }
.toList()
return ExportedType.TypeParameter(
@@ -487,7 +498,7 @@ class ExportModelGenerator(
)
}
- private fun exportType(type: IrType): ExportedType {
+ private fun exportType(type: IrType, shouldCalculateExportedSupertypeForImplicit: Boolean = true): ExportedType {
if (type is IrDynamicType)
return ExportedType.Primitive.Any
@@ -535,6 +546,12 @@ class ExportModelGenerator(
val isNonExportedExternal = klass.isExternal && !isExported
val name = klass.getFqNameWithJsNameWhenAvailable(!isNonExportedExternal && generateNamespacesForPackages).asString()
+ val exportedSupertype = runIf(shouldCalculateExportedSupertypeForImplicit && isImplicitlyExported) {
+ val transitiveExportedType = nonNullType.collectSuperTransitiveHierarchy()
+ if (transitiveExportedType.isEmpty()) return@runIf null
+ transitiveExportedType.map(::exportType).reduce(ExportedType::IntersectionType)
+ } ?: ExportedType.Primitive.Any
+
when (klass.kind) {
ClassKind.ANNOTATION_CLASS,
ClassKind.ENUM_ENTRY ->
@@ -550,7 +567,7 @@ class ExportModelGenerator(
type.arguments.map { exportTypeArgument(it) },
klass
)
- }.withImplicitlyExported(isImplicitlyExported)
+ }.withImplicitlyExported(isImplicitlyExported, exportedSupertype)
}
else -> error("Unexpected classifier $classifier")
@@ -683,7 +700,11 @@ private fun shouldDeclarationBeExported(declaration: IrDeclarationWithName, cont
}
fun IrOverridableDeclaration<*>.isAllowedFakeOverriddenDeclaration(context: JsIrBackendContext): Boolean {
- if (this.resolveFakeOverride(allowAbstract = true)?.parentClassOrNull.isExportedInterface(context)) {
+ val firstExportedRealOverride = runIf(isFakeOverride) {
+ resolveFakeOverrideOrNull(allowAbstract = true) { it === this || it.parentClassOrNull?.isExported(context) != true }
+ }
+
+ if (firstExportedRealOverride?.parentClassOrNull.isExportedInterface(context)) {
return true
}
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 93fb3476f9b..d36d55771e2 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
@@ -14,6 +14,9 @@ import org.jetbrains.kotlin.ir.util.isObject
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.js.common.isValidES5Identifier
import org.jetbrains.kotlin.serialization.js.ModuleKind
+import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
+import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
+import javax.lang.model.type.IntersectionType
private const val Nullable = "Nullable"
private const val objects = "_objects_"
@@ -176,10 +179,7 @@ class ExportModelToTsDeclarations {
var t: ExportedType = ExportedType.InlineInterfaceType(members)
- if (superClass != null)
- t = ExportedType.IntersectionType(t, superClass)
-
- for (superInterface in superInterfaces) {
+ for (superInterface in superClasses + superInterfaces) {
t = ExportedType.IntersectionType(t, superInterface)
}
@@ -210,13 +210,13 @@ class ExportModelToTsDeclarations {
property.generateTypeScriptString(indent, prefix)
} else {
val propertyRef = "$objects.$propertyName"
- val shouldCreateExtraProperty = members.isNotEmpty() || superInterfaces.isNotEmpty() || superClass != null
+ val shouldCreateExtraProperty = members.isNotEmpty() || superInterfaces.isNotEmpty() || superClasses.isNotEmpty()
val newSuperClass = ExportedType.ClassType(propertyRef, emptyList(), ir).takeIf { shouldCreateExtraProperty }
ExportedRegularClass(
name = name,
isInterface = false,
isAbstract = true,
- superClass = newSuperClass,
+ superClasses = listOfNotNull(newSuperClass),
superInterfaces = superInterfaces,
typeParameters = emptyList(),
members = listOf(ExportedConstructor(emptyList(), ExportedVisibility.PRIVATE)),
@@ -232,7 +232,7 @@ class ExportModelToTsDeclarations {
val keyword = if (isInterface) "interface" else "class"
val superInterfacesKeyword = if (isInterface) "extends" else "implements"
- val superClassClause = superClass?.let { it.toExtendsClause(indent) } ?: ""
+ val superClassClause = superClasses.toExtendsClause(indent)
val superInterfacesClause = superInterfaces.toImplementsClause(superInterfacesKeyword, indent)
val (memberObjects, nestedDeclarations) = nestedClasses.partition { it.couldBeProperty() }
@@ -279,12 +279,18 @@ class ExportModelToTsDeclarations {
return if (name.isValidES5Identifier()) klassExport + staticsExport else ""
}
- private fun ExportedType.toExtendsClause(indent: String): String {
- val isImplicitlyExportedType = this is ExportedType.ImplicitlyExportedType
- val extendsClause = " extends ${toTypeScript(indent, isImplicitlyExportedType)}"
- return when {
- isImplicitlyExportedType -> " /*$extendsClause */"
- else -> extendsClause
+ private fun List.toExtendsClause(indent: String): String {
+ if (isEmpty()) return ""
+
+ val implicitlyExportedClasses = filterIsInstance()
+ val implicitlyExportedClassesString = implicitlyExportedClasses.joinToString(", ") { it.toTypeScript(indent, true) }
+
+ return if (implicitlyExportedClasses.count() == count()) {
+ " /* extends $implicitlyExportedClassesString */"
+ } else {
+ val originallyDefinedSuperClass = implicitlyExportedClassesString.takeIf { it.isNotEmpty() }?.let { "/* $it */ " }.orEmpty()
+ val transitivelyDefinedSuperClass = firstIsInstance().toTypeScript(indent, false)
+ " extends $originallyDefinedSuperClass$transitivelyDefinedSuperClass"
}
}
@@ -383,7 +389,12 @@ class ExportModelToTsDeclarations {
is ExportedType.LiteralType.NumberLiteralType -> value.toString()
is ExportedType.ImplicitlyExportedType -> {
val typeString = type.toTypeScript("", true)
- if (isInCommentContext) typeString else ExportedType.Primitive.Any.toTypeScript(indent) + "/* $typeString */"
+ if (isInCommentContext) {
+ typeString
+ } else {
+ val superTypeString = exportedSupertype.toTypeScript(indent)
+ superTypeString.let { if (exportedSupertype is ExportedType.IntersectionType) "($it)" else it } + "/* $typeString */"
+ }
}
is ExportedType.PropertyType -> "${container.toTypeScript(indent, isInCommentContext)}[${
diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/TransitiveExportCollector.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/TransitiveExportCollector.kt
new file mode 100644
index 00000000000..636a974c2e2
--- /dev/null
+++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/TransitiveExportCollector.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.ir.backend.js.export
+
+import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
+import org.jetbrains.kotlin.ir.backend.js.lower.isBuiltInClass
+import org.jetbrains.kotlin.ir.backend.js.lower.isStdLibClass
+import org.jetbrains.kotlin.ir.declarations.*
+import org.jetbrains.kotlin.ir.symbols.*
+import org.jetbrains.kotlin.ir.types.*
+import org.jetbrains.kotlin.ir.util.*
+
+private typealias SubstitutionMap = Map
+
+class TransitiveExportCollector(val context: JsIrBackendContext) {
+ private val typesCaches = hashMapOf>()
+
+ fun collectSuperTypesTransitiveHierarchyFor(type: IrSimpleType): Set {
+ val classSymbol = type.classOrNull ?: return emptySet()
+
+ return typesCaches.getOrPut(ClassWithAppliedArguments(classSymbol, type.arguments)) {
+ type.collectSuperTypesTransitiveHierarchy(type.calculateTypeSubstitutionMap(emptyMap()))
+ }
+ }
+
+ private fun IrSimpleType.collectSuperTypesTransitiveHierarchy(typeSubstitutionMap: SubstitutionMap): Set {
+ val classifier = classOrNull ?: return emptySet()
+
+ return classifier.superTypes()
+ .flatMap { (it as? IrSimpleType)?.collectTransitiveHierarchy(typeSubstitutionMap) ?: emptySet() }
+ .toSet()
+ }
+
+ private fun IrSimpleType.collectTransitiveHierarchy(typeSubstitutionMap: SubstitutionMap): Set {
+ val owner = classifier.owner as? IrClass ?: return emptySet()
+ val substitutionMap = calculateTypeSubstitutionMap(typeSubstitutionMap)
+
+ return when {
+ isBuiltInClass(owner) || isStdLibClass(owner) -> emptySet()
+ owner.isExported(context) -> setOf(substitute(typeSubstitutionMap))
+ else -> collectSuperTypesTransitiveHierarchy(substitutionMap)
+ }
+ }
+
+ private fun IrTypeArgument.getSubstitution(typeSubstitutionMap: SubstitutionMap): IrType {
+ return when (this) {
+ is IrType -> substitute(typeSubstitutionMap)
+ is IrTypeProjection -> type.substitute(typeSubstitutionMap)
+ else -> error("Unexpected ir type argument")
+ }
+ }
+
+ private fun IrSimpleType.calculateTypeSubstitutionMap(typeSubstitutionMap: SubstitutionMap): SubstitutionMap {
+ val classifier = classOrNull ?: error("Unexpected classifier $classifier for collecting transitive hierarchy")
+
+ return typeSubstitutionMap + classifier.owner.typeParameters.zip(arguments).associate {
+ it.first.symbol to it.second.getSubstitution(typeSubstitutionMap)
+ }
+ }
+
+ private data class ClassWithAppliedArguments(val classSymbol: IrClassSymbol, val appliedArguments: List)
+}
\ No newline at end of file
diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/MoveBodilessDeclarationsToSeparatePlace.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/MoveBodilessDeclarationsToSeparatePlace.kt
index a57c57432bc..39aded1478d 100644
--- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/MoveBodilessDeclarationsToSeparatePlace.kt
+++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/MoveBodilessDeclarationsToSeparatePlace.kt
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.name.isChildOf
private val BODILESS_BUILTIN_CLASSES = listOf(
"kotlin.String",
@@ -44,6 +45,9 @@ private val BODILESS_BUILTIN_CLASSES = listOf(
fun isBuiltInClass(declaration: IrDeclaration): Boolean =
declaration is IrClass && declaration.fqNameWhenAvailable in BODILESS_BUILTIN_CLASSES
+fun isStdLibClass(declaration: IrDeclaration): Boolean =
+ declaration is IrClass && declaration.fqNameWhenAvailable?.isChildOf(JsPackage) != false
+
private val JsPackage = FqName("kotlin.js")
private val JsIntrinsicFqName = FqName("kotlin.js.JsIntrinsic")
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrFakeOverrideUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrFakeOverrideUtils.kt
index 2a2d96cc400..b7d263d9c21 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrFakeOverrideUtils.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrFakeOverrideUtils.kt
@@ -93,16 +93,24 @@ fun Collection.collectAndFilterRealOverrides(): Set error("all members should be of the same kind, got ${map { it.render() }}")
}
-// TODO: use this implementation instead of any other
fun > T.resolveFakeOverride(
allowAbstract: Boolean = false,
toSkip: (T) -> Boolean = { false }
+): T? =
+ resolveFakeOverrideOrNull(allowAbstract, toSkip).also {
+ if (allowAbstract && it == null) {
+ error("No real overrides for ${this.render()}")
+ }
+ }
+
+// TODO: use this implementation instead of any other
+fun > T.resolveFakeOverrideOrNull(
+ allowAbstract: Boolean = false,
+ toSkip: (T) -> Boolean = { false }
): T? {
if (!isFakeOverride && !toSkip(this)) return this
return if (allowAbstract) {
- val reals = collectRealOverrides(toSkip)
- if (reals.isEmpty()) error("No real overrides for ${this.render()}")
- reals.first()
+ collectRealOverrides(toSkip).firstOrNull()
} else {
collectRealOverrides(toSkip, { it.modality == Modality.ABSTRACT })
.let { realOverrides ->
diff --git a/js/js.translator/testData/typescript-export/functions/functions.d.ts b/js/js.translator/testData/typescript-export/functions/functions.d.ts
index 86d3764e475..9324dbe0ad9 100644
--- a/js/js.translator/testData/typescript-export/functions/functions.d.ts
+++ b/js/js.translator/testData/typescript-export/functions/functions.d.ts
@@ -11,8 +11,8 @@ declare namespace JS_TESTS {
function generic1(x: T): T;
function generic2(x: Nullable): boolean;
function genericWithConstraint(x: T): T;
- function genericWithMultipleConstraints(x: T): T;
+ function genericWithMultipleConstraints */ & RegExpMatchArray & Error>(x: T): T;
function generic3(a: A, b: B, c: C, d: D): Nullable;
function inlineFun(x: number, callback: (p0: number) => void): void;
}
-}
\ No newline at end of file
+}
diff --git a/js/js.translator/testData/typescript-export/implicit-export/implicit-export.d.ts b/js/js.translator/testData/typescript-export/implicit-export/implicit-export.d.ts
index 15ef3f460fc..b76bd976d26 100644
--- a/js/js.translator/testData/typescript-export/implicit-export/implicit-export.d.ts
+++ b/js/js.translator/testData/typescript-export/implicit-export/implicit-export.d.ts
@@ -12,7 +12,7 @@ declare namespace JS_TESTS {
constructor(value: any/* foo.NonExportedType */);
get value(): any/* foo.NonExportedType */;
set value(value: any/* foo.NonExportedType */);
- increment(t: T): any/* foo.NonExportedType */;
+ increment(t: T): any/* foo.NonExportedType */;
}
class B /* extends foo.NonExportedType */ {
constructor(v: number);
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 c2b160dfc80..65c6c307d22 100644
--- a/js/js.translator/testData/typescript-export/inheritance/inheritance.d.ts
+++ b/js/js.translator/testData/typescript-export/inheritance/inheritance.d.ts
@@ -13,6 +13,7 @@ declare namespace JS_TESTS {
}
}
namespace foo {
+ const fifth: (foo.Third & foo.IA & foo.IG)/* foo.Fifth */;
abstract class AC implements foo.I2 {
constructor();
get x(): string;
@@ -100,5 +101,31 @@ declare namespace JS_TESTS {
abstract get baz(): string;
readonly __doNotUseOrImplementIt: foo.I3["__doNotUseOrImplementIt"];
}
+ interface IA {
+ readonly foo: any;
+ readonly __doNotUseOrImplementIt: {
+ readonly "foo.IA": unique symbol;
+ };
+ }
+ interface IG {
+ process(value: T): void;
+ readonly __doNotUseOrImplementIt: {
+ readonly "foo.IG": unique symbol;
+ };
+ }
+ class Third extends /* foo.Second */ foo.First {
+ constructor();
+ }
+ class Sixth extends /* foo.Fifth */ foo.Third implements foo.IA, foo.IG/*, foo.IC */ {
+ constructor();
+ process(value: number): void;
+ get foo(): number;
+ readonly __doNotUseOrImplementIt: foo.IA["__doNotUseOrImplementIt"] & foo.IG["__doNotUseOrImplementIt"];
+ }
+ class First {
+ constructor();
+ }
+ function acceptForthLike & foo.IA)/* foo.Forth */>(forth: T): void;
+ function acceptMoreGenericForthLike(forth: T): void;
}
}
diff --git a/js/js.translator/testData/typescript-export/inheritance/inheritance.kt b/js/js.translator/testData/typescript-export/inheritance/inheritance.kt
index cd484e10328..4d65427d92e 100644
--- a/js/js.translator/testData/typescript-export/inheritance/inheritance.kt
+++ b/js/js.translator/testData/typescript-export/inheritance/inheritance.kt
@@ -163,3 +163,53 @@ enum class EC : I3 {
override fun bay(): String = "bay"
}
+
+// Save hierarhy
+
+@JsExport
+interface IA {
+ val foo: Any
+}
+
+@JsExport
+interface IG {
+ fun process(value: T): Unit
+}
+
+interface IB : IA
+
+interface IC : IB {
+ override val foo: Any
+}
+
+interface ID : IC {
+ override val foo: Int
+}
+
+@JsExport
+open class Third: Second()
+
+open class Forth: Third(), IB, ID {
+ override val foo: Int = 42
+}
+
+open class Fifth: Forth(), IG {
+ override fun process(value: B) {}
+}
+
+@JsExport
+class Sixth: Fifth(), IC
+
+@JsExport
+open class First
+
+open class Second: First()
+
+@JsExport
+fun > acceptForthLike(forth: T) {}
+
+@JsExport
+fun acceptMoreGenericForthLike(forth: T) where T: IB, T: IC, T: Second {}
+
+@JsExport
+val fifth = Fifth()
diff --git a/js/js.translator/testData/typescript-export/methods/methods.d.ts b/js/js.translator/testData/typescript-export/methods/methods.d.ts
index 98791c2670f..d2264326123 100644
--- a/js/js.translator/testData/typescript-export/methods/methods.d.ts
+++ b/js/js.translator/testData/typescript-export/methods/methods.d.ts
@@ -13,7 +13,7 @@ declare namespace JS_TESTS {
generic1(x: T): T;
generic2(x: Nullable): boolean;
genericWithConstraint(x: T): T;
- genericWithMultipleConstraints(x: T): T;
+ genericWithMultipleConstraints */ & RegExpMatchArray & Error>(x: T): T;
generic3(a: A, b: B, c: C, d: D): Nullable;
inlineFun(x: number, callback: (p0: number) => void): void;
}