[Wasm] IDL: Generate overloads for functions with union-typed arguments

This commit is contained in:
Svyatoslav Kuzmich
2023-05-05 12:00:21 +02:00
committed by Space Team
parent 24656b1576
commit 2fd77d0925
14 changed files with 311 additions and 131 deletions
@@ -0,0 +1,73 @@
/*
* Copyright 2010-2023 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.tools.dukat.wasm
import org.jetbrains.dukat.idlDeclarations.*
import org.jetbrains.dukat.idlLowerings.IDLLowering
class UnionParametersOverloadsLowering : IDLLowering {
// Types that are present as union components, but somehow missing IDL declarations. Should be ignored.
private val typesMissingFromIDL: Set<String> =
setOf("CSSPseudoElement", "BufferSource")
override fun lowerInterfaceDeclaration(declaration: IDLInterfaceDeclaration, owner: IDLFileDeclaration): IDLInterfaceDeclaration {
return declaration.copy(
operations = declaration.operations.flatMap(::generateOverloads)
)
}
private fun generateOverloads(op: IDLOperationDeclaration): List<IDLOperationDeclaration> {
val numUnionTypes = op.arguments.count { it.type is IDLUnionTypeDeclaration }
if (numUnionTypes == 0)
return listOf(op)
if (numUnionTypes > 1)
TODO(
"""
Not supported in current implementation to keep it simple.
If updated IDL contains multiple union arguments and this check fails,
consider updating the algorithm or return listOf(op) as a fallback.
"""
)
val unionTypedArgumentIndex = op.arguments.indexOfFirst { it.type is IDLUnionTypeDeclaration }
val unionTypedArgument = op.arguments[unionTypedArgumentIndex]
val unionType = unionTypedArgument.type as IDLUnionTypeDeclaration
var unionMembersFlattened = unionType.unionMembers
while (unionMembersFlattened.any { it is IDLUnionTypeDeclaration }) {
unionMembersFlattened = unionMembersFlattened.flatMap {
if (it is IDLUnionTypeDeclaration) it.unionMembers else listOf(it)
}
}
val result = unionMembersFlattened.mapNotNull { unionMember ->
if (unionMember.name in typesMissingFromIDL)
return@mapNotNull null
op.copy(
arguments = op.arguments.mapIndexed { argumentIndex, argument: IDLArgumentDeclaration ->
if (argumentIndex == unionTypedArgumentIndex) {
argument.copy(type = unionMember, defaultValue = null, optional = false)
} else {
argument.copy()
}
}
)
}
// If union typed argument is optional - create an overload without union argument.
if (unionTypedArgument.optional || unionTypedArgument.defaultValue != null) {
return result + op.copy(arguments = op.arguments.subList(0, unionTypedArgumentIndex))
}
return result
}
}
fun IDLSourceSetDeclaration.addOverloadsForUnions(): IDLSourceSetDeclaration {
return UnionParametersOverloadsLowering().lowerSourceSetDeclaration(this)
}
@@ -50,6 +50,7 @@ import org.jetbrains.dukat.panic.raiseConcern
import org.jetbrains.dukat.stdlib.TSLIBROOT
import org.jetbrains.dukat.stdlib.isTsStdlibPrefixed
import org.jetbrains.dukat.translator.ROOT_PACKAGENAME
import org.jetbrains.dukat.translatorString.translate
import java.io.File
private val jsAnyHeritageModel: HeritageModel = HeritageModel(
@@ -224,6 +225,13 @@ private class IdlFileConverter(
return when (this) {
is IDLSingleTypeDeclaration -> convertToModel(isTypeParameter)
is IDLFunctionTypeDeclaration -> convertToModel()
is IDLUnionTypeDeclaration -> TypeValueModel(
IdentifierEntity("JsAny"),
listOf(),
metaDescription = this.unionMembers.joinToString("|") { it.convertToModel(false).translate() },
null,
nullable = true,
)
//there shouldn't be any UnionTypeDeclarations at this stage
else -> raiseConcern("unprocessed type declaration: ${this}") {
TypeValueModel(
@@ -98,12 +98,8 @@ private class TypeResolver : IDLLowering {
nullable = declaration.nullable,
comment = declaration.comment
)
in failedToResolveUnionTypes -> IDLSingleTypeDeclaration(
name = "\$dynamic",
typeParameter = null,
nullable = false,
comment = declaration.comment
)
// Keeping unresolved union types as-is to process later
in failedToResolveUnionTypes -> declaration
else -> raiseConcern("unprocessed UnionTypeDeclaration: $this") { declaration }
}
}
@@ -203,7 +199,7 @@ private class DependencyResolver(val typeResolver: TypeResolver) : IDLLowering {
}
}
fun IDLSourceSetDeclaration.resolveTypes(): IDLSourceSetDeclaration {
fun IDLSourceSetDeclaration.resolveTypesKeepingUnions(): IDLSourceSetDeclaration {
val typeResolver = TypeResolver()
val dependencyResolver = DependencyResolver(typeResolver)
val declarationAdder = DeclarationAdder(typeResolver)
@@ -27,7 +27,8 @@ fun translateIdlToSourceSet(fileName: String): SourceSetModel {
.resolveImplementsStatements()
.resolveMixins()
.addItemArrayLike()
.resolveTypes()
.resolveTypesKeepingUnions()
.addOverloadsForUnions()
.markAbstractOrOpen()
.addMissingMembers()
.addOverloadsForCallbacks()