[JS IR BE] Initial version of member namer
This commit is contained in:
+3
-23
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.descriptors.Modality
|
|||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.asString
|
import org.jetbrains.kotlin.ir.backend.js.utils.functionSignature
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsName
|
import org.jetbrains.kotlin.ir.backend.js.utils.getJsName
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
@@ -28,7 +28,6 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
|||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||||
import org.jetbrains.kotlin.ir.types.isUnit
|
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
|
|
||||||
// Constructs bridges for inherited generic functions
|
// Constructs bridges for inherited generic functions
|
||||||
@@ -114,7 +113,7 @@ class BridgesConstruction(val context: JsIrBackendContext) : ClassLoweringPass {
|
|||||||
): IrFunction {
|
): IrFunction {
|
||||||
|
|
||||||
val origin =
|
val origin =
|
||||||
if (bridge.isEffectivelyExternal())
|
if (bridge.isEffectivelyExternal() || bridge.getJsName() != null)
|
||||||
JsLoweredDeclarationOrigin.BRIDGE_TO_EXTERNAL_FUNCTION
|
JsLoweredDeclarationOrigin.BRIDGE_TO_EXTERNAL_FUNCTION
|
||||||
else
|
else
|
||||||
IrDeclarationOrigin.BRIDGE
|
IrDeclarationOrigin.BRIDGE
|
||||||
@@ -200,26 +199,7 @@ class FunctionAndSignature(val function: IrSimpleFunction) {
|
|||||||
// TODO: Use type-upper-bound-based signature instead of Strings
|
// TODO: Use type-upper-bound-based signature instead of Strings
|
||||||
// Currently strings are used for compatibility with a hack-based name generator
|
// Currently strings are used for compatibility with a hack-based name generator
|
||||||
|
|
||||||
private data class Signature(
|
private val signature = functionSignature(function)
|
||||||
val name: String,
|
|
||||||
val extensionReceiverType: String? = null,
|
|
||||||
val valueParameters: List<String?> = emptyList(),
|
|
||||||
val returnType: String? = null
|
|
||||||
)
|
|
||||||
|
|
||||||
private val jsName = function.getJsName()
|
|
||||||
private val signature = when {
|
|
||||||
jsName != null -> Signature(jsName)
|
|
||||||
function.isEffectivelyExternal() -> Signature(function.name.asString())
|
|
||||||
else -> Signature(
|
|
||||||
function.name.asString(),
|
|
||||||
function.extensionReceiverParameter?.type?.asString(),
|
|
||||||
function.valueParameters.map { it.type.asString() },
|
|
||||||
// Return type used in signature for inline classes and Unit because
|
|
||||||
// they are binary incompatible with supertypes and require bridges.
|
|
||||||
function.returnType.run { if (isInlined() || isUnit()) asString() else null }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
|
|||||||
+2
-3
@@ -48,7 +48,7 @@ class PrimitiveCompanionLowering(val context: JsIrBackendContext) : FileLowering
|
|||||||
val actualFunction =
|
val actualFunction =
|
||||||
actualCompanion.declarations
|
actualCompanion.declarations
|
||||||
.filterIsInstance<IrSimpleFunction>()
|
.filterIsInstance<IrSimpleFunction>()
|
||||||
.find { it.name == function.name }
|
.single { it.name == function.name }
|
||||||
|
|
||||||
return actualFunction!!
|
return actualFunction!!
|
||||||
}
|
}
|
||||||
@@ -69,8 +69,7 @@ class PrimitiveCompanionLowering(val context: JsIrBackendContext) : FileLowering
|
|||||||
override fun visitCall(expression: IrCall): IrExpression {
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
val newCall = super.visitCall(expression) as IrCall
|
val newCall = super.visitCall(expression) as IrCall
|
||||||
|
|
||||||
val function = expression.symbol.owner as? IrSimpleFunction
|
val function = expression.symbol.owner as IrSimpleFunction
|
||||||
?: return newCall
|
|
||||||
|
|
||||||
val actualFunction = getActualPrimitiveCompanionPropertyAccessor(function)
|
val actualFunction = getActualPrimitiveCompanionPropertyAccessor(function)
|
||||||
?: return newCall
|
?: return newCall
|
||||||
|
|||||||
-1
@@ -135,7 +135,6 @@ class IrModuleToJsTransformer(
|
|||||||
val program = JsProgram()
|
val program = JsProgram()
|
||||||
|
|
||||||
val nameGenerator = IrNamerImpl(
|
val nameGenerator = IrNamerImpl(
|
||||||
memberNameGenerator = LegacyMemberNameGenerator(program.rootScope),
|
|
||||||
newNameTables = namer,
|
newNameTables = namer,
|
||||||
rootScope = program.rootScope
|
rootScope = program.rootScope
|
||||||
)
|
)
|
||||||
|
|||||||
+14
-5
@@ -81,12 +81,23 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
if (property.origin == IrDeclarationOrigin.FAKE_OVERRIDE)
|
if (property.origin == IrDeclarationOrigin.FAKE_OVERRIDE)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
fun IrSimpleFunction.accessorRef(): JsNameRef? =
|
||||||
|
when (visibility) {
|
||||||
|
Visibilities.PRIVATE -> null
|
||||||
|
else -> JsNameRef(
|
||||||
|
context.getNameForMemberFunction(this),
|
||||||
|
classPrototypeRef
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val getterRef = property.getter?.accessorRef()
|
||||||
|
val setterRef = property.setter?.accessorRef()
|
||||||
classBlock.statements += JsExpressionStatement(
|
classBlock.statements += JsExpressionStatement(
|
||||||
defineProperty(
|
defineProperty(
|
||||||
classPrototypeRef,
|
classPrototypeRef,
|
||||||
context.getNameForProperty(property).ident,
|
context.getNameForProperty(property).ident,
|
||||||
getter = property.getter?.let { JsNameRef(context.getNameForMemberFunction(it), classPrototypeRef) },
|
getter = getterRef,
|
||||||
setter = property.setter?.let { JsNameRef(context.getNameForMemberFunction(it), classPrototypeRef) }
|
setter = setterRef
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -121,9 +132,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
private fun generateMemberFunction(declaration: IrSimpleFunction): JsStatement? {
|
private fun generateMemberFunction(declaration: IrSimpleFunction): JsStatement? {
|
||||||
|
|
||||||
val translatedFunction = declaration.run { if (isReal) accept(IrFunctionToJsTransformer(), context) else null }
|
val translatedFunction = declaration.run { if (isReal) accept(IrFunctionToJsTransformer(), context) else null }
|
||||||
if (declaration.isStaticMethodOfClass) {
|
assert(!declaration.isStaticMethodOfClass)
|
||||||
return translatedFunction?.makeStmt()
|
|
||||||
}
|
|
||||||
|
|
||||||
val memberName = context.getNameForMemberFunction(declaration.realOverrideTarget)
|
val memberName = context.getNameForMemberFunction(declaration.realOverrideTarget)
|
||||||
val memberRef = JsNameRef(memberName, classPrototypeRef)
|
val memberRef = JsNameRef(memberName, classPrototypeRef)
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.js.backend.ast.JsNameRef
|
|||||||
import org.jetbrains.kotlin.js.backend.ast.JsRootScope
|
import org.jetbrains.kotlin.js.backend.ast.JsRootScope
|
||||||
|
|
||||||
class IrNamerImpl(
|
class IrNamerImpl(
|
||||||
private val memberNameGenerator: LegacyMemberNameGenerator,
|
|
||||||
private val newNameTables: NameTables,
|
private val newNameTables: NameTables,
|
||||||
private val rootScope: JsRootScope // TODO: Don't use scopes
|
private val rootScope: JsRootScope // TODO: Don't use scopes
|
||||||
) : IrNamer {
|
) : IrNamer {
|
||||||
@@ -32,12 +31,12 @@ class IrNamerImpl(
|
|||||||
|
|
||||||
override fun getNameForMemberFunction(function: IrSimpleFunction): JsName {
|
override fun getNameForMemberFunction(function: IrSimpleFunction): JsName {
|
||||||
require(function.dispatchReceiverParameter != null)
|
require(function.dispatchReceiverParameter != null)
|
||||||
return memberNameGenerator.getNameForMemberFunction(function)
|
return rootScope.declareName(newNameTables.getNameForMemberFunction(function))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getNameForMemberField(field: IrField): JsName {
|
override fun getNameForMemberField(field: IrField): JsName {
|
||||||
require(!field.isStatic)
|
require(!field.isStatic)
|
||||||
return memberNameGenerator.getNameForMemberField(field)
|
return rootScope.declareName(newNameTables.getNameForMemberField(field))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getNameForField(field: IrField): JsName {
|
override fun getNameForField(field: IrField): JsName {
|
||||||
|
|||||||
+145
-89
@@ -14,12 +14,11 @@ import org.jetbrains.kotlin.ir.expressions.IrLoop
|
|||||||
import org.jetbrains.kotlin.ir.types.isUnit
|
import org.jetbrains.kotlin.ir.types.isUnit
|
||||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||||
|
import org.jetbrains.kotlin.ir.util.isEnumClass
|
||||||
import org.jetbrains.kotlin.ir.util.isInlined
|
import org.jetbrains.kotlin.ir.util.isInlined
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsName
|
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsScope
|
|
||||||
import org.jetbrains.kotlin.js.naming.isES5IdentifierPart
|
import org.jetbrains.kotlin.js.naming.isES5IdentifierPart
|
||||||
import org.jetbrains.kotlin.js.naming.isES5IdentifierStart
|
import org.jetbrains.kotlin.js.naming.isES5IdentifierStart
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
@@ -73,10 +72,72 @@ fun NameTable<IrDeclaration>.dump(): String =
|
|||||||
"--- $declRef => $name"
|
"--- $declRef => $name"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sealed class Signature
|
||||||
|
data class StableNameSignature(val name: String) : Signature()
|
||||||
|
data class BackingFieldSignature(val field: IrField) : Signature()
|
||||||
|
data class ParameterTypeBasedSignature(val mangledName: String, val suggestedName: String) : Signature()
|
||||||
|
|
||||||
|
fun fieldSignature(field: IrField): Signature {
|
||||||
|
if (field.isEffectivelyExternal()) {
|
||||||
|
return StableNameSignature(field.name.identifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
return BackingFieldSignature(field)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun functionSignature(declaration: IrFunction): Signature {
|
||||||
|
require(!declaration.isStaticMethodOfClass)
|
||||||
|
require(declaration.dispatchReceiverParameter != null)
|
||||||
|
|
||||||
|
val declarationName = declaration.getJsNameOrKotlinName().asString()
|
||||||
|
val stableName = StableNameSignature(declarationName)
|
||||||
|
|
||||||
|
if (declaration.origin == JsLoweredDeclarationOrigin.BRIDGE_TO_EXTERNAL_FUNCTION) {
|
||||||
|
return stableName
|
||||||
|
}
|
||||||
|
if (declaration.isEffectivelyExternal()) {
|
||||||
|
return stableName
|
||||||
|
}
|
||||||
|
if (declaration.getJsName() != null) {
|
||||||
|
return stableName
|
||||||
|
}
|
||||||
|
// Handle names for special functions
|
||||||
|
if (declaration is IrSimpleFunction && declaration.isMethodOfAny()) {
|
||||||
|
return stableName
|
||||||
|
}
|
||||||
|
|
||||||
|
val nameBuilder = StringBuilder()
|
||||||
|
|
||||||
|
nameBuilder.append(declarationName)
|
||||||
|
|
||||||
|
// TODO should we skip type parameters and use upper bound of type parameter when print type of value parameters?
|
||||||
|
declaration.typeParameters.ifNotEmpty {
|
||||||
|
nameBuilder.append("_\$t")
|
||||||
|
joinTo(nameBuilder, "") { "_${it.name.asString()}" }
|
||||||
|
}
|
||||||
|
declaration.extensionReceiverParameter?.let {
|
||||||
|
nameBuilder.append("_r$${it.type.asString()}")
|
||||||
|
}
|
||||||
|
declaration.valueParameters.ifNotEmpty {
|
||||||
|
joinTo(nameBuilder, "") { "_${it.type.asString()}" }
|
||||||
|
}
|
||||||
|
declaration.returnType.let {
|
||||||
|
// Return type is only used in signature for inline class and Unit types because
|
||||||
|
// they are binary incompatible with supertypes.
|
||||||
|
if (it.isInlined() || it.isUnit()) {
|
||||||
|
nameBuilder.append("_ret$${it.asString()}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val signature = nameBuilder.toString()
|
||||||
|
|
||||||
|
// TODO: Check reserved names
|
||||||
|
return ParameterTypeBasedSignature(signature, declarationName)
|
||||||
|
}
|
||||||
|
|
||||||
class NameTables(packages: List<IrPackageFragment>) {
|
class NameTables(packages: List<IrPackageFragment>) {
|
||||||
private val globalNames: NameTable<IrDeclaration>
|
private val globalNames: NameTable<IrDeclaration>
|
||||||
private val memberNames: NameTable<IrDeclaration>
|
private val memberNames: NameTable<Signature>
|
||||||
private val localNames = mutableMapOf<IrDeclaration, NameTable<IrDeclaration>>()
|
private val localNames = mutableMapOf<IrDeclaration, NameTable<IrDeclaration>>()
|
||||||
private val loopNames = mutableMapOf<IrLoop, String>()
|
private val loopNames = mutableMapOf<IrLoop, String>()
|
||||||
|
|
||||||
@@ -97,15 +158,40 @@ class NameTables(packages: List<IrPackageFragment>) {
|
|||||||
|
|
||||||
for (p in packages) {
|
for (p in packages) {
|
||||||
for (declaration in p.declarations) {
|
for (declaration in p.declarations) {
|
||||||
if (declaration.isEffectivelyExternal())
|
|
||||||
continue
|
|
||||||
|
|
||||||
val localNameGenerator = LocalNameGenerator(declaration)
|
val localNameGenerator = LocalNameGenerator(declaration)
|
||||||
|
|
||||||
if (declaration is IrClass) {
|
if (declaration is IrClass) {
|
||||||
declaration.thisReceiver!!.acceptVoid(localNameGenerator)
|
if (declaration.isEffectivelyExternal()) {
|
||||||
for (memberDecl in declaration.declarations) {
|
declaration.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||||
memberDecl.acceptChildrenVoid(LocalNameGenerator(memberDecl))
|
override fun visitElement(element: IrElement) {
|
||||||
|
element.acceptChildrenVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitSimpleFunction(declaration: IrSimpleFunction) {
|
||||||
|
val parent = declaration.parent
|
||||||
|
if (parent is IrClass && !parent.isEnumClass) {
|
||||||
|
generateNameForMemberFunction(declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitField(declaration: IrField) {
|
||||||
|
val parent = declaration.parent
|
||||||
|
if (parent is IrClass && !parent.isEnumClass) {
|
||||||
|
generateNameForMemberField(declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
declaration.thisReceiver!!.acceptVoid(localNameGenerator)
|
||||||
|
for (memberDecl in declaration.declarations) {
|
||||||
|
memberDecl.acceptChildrenVoid(LocalNameGenerator(memberDecl))
|
||||||
|
when (memberDecl) {
|
||||||
|
is IrSimpleFunction ->
|
||||||
|
generateNameForMemberFunction(memberDecl)
|
||||||
|
is IrField ->
|
||||||
|
generateNameForMemberField(memberDecl)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
declaration.acceptChildrenVoid(localNameGenerator)
|
declaration.acceptChildrenVoid(localNameGenerator)
|
||||||
@@ -114,6 +200,33 @@ class NameTables(packages: List<IrPackageFragment>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun generateNameForMemberField(field: IrField) {
|
||||||
|
require(!field.isTopLevel)
|
||||||
|
require(!field.isStatic)
|
||||||
|
val signature = fieldSignature(field)
|
||||||
|
|
||||||
|
if (field.isEffectivelyExternal()) {
|
||||||
|
memberNames.declareStableName(signature, field.name.identifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
memberNames.declareFreshName(signature, "_" + sanitizeName(field.name.asString()))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateNameForMemberFunction(declaration: IrSimpleFunction) {
|
||||||
|
when (val signature = functionSignature(declaration)) {
|
||||||
|
is StableNameSignature -> memberNames.declareStableName(signature, signature.name)
|
||||||
|
is ParameterTypeBasedSignature -> {
|
||||||
|
// TODO: Fix hack: Coroutines runtime currently relies on stable names
|
||||||
|
// of `invoke` functions in FunctionN interfaces
|
||||||
|
if (declaration.name.asString().startsWith("invoke")) {
|
||||||
|
memberNames.declareStableName(signature, sanitizeName(signature.mangledName))
|
||||||
|
} else {
|
||||||
|
memberNames.declareFreshName(signature, signature.suggestedName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun dump(): String {
|
fun dump(): String {
|
||||||
val local = localNames.toList().joinToString("\n") { (decl, table) ->
|
val local = localNames.toList().joinToString("\n") { (decl, table) ->
|
||||||
@@ -121,7 +234,7 @@ class NameTables(packages: List<IrPackageFragment>) {
|
|||||||
"\nLocal names for $declRef:\n${table.dump()}\n"
|
"\nLocal names for $declRef:\n${table.dump()}\n"
|
||||||
}
|
}
|
||||||
return "Global names:\n${globalNames.dump()}" +
|
return "Global names:\n${globalNames.dump()}" +
|
||||||
"\nMember names:\n${memberNames.dump()}" +
|
// "\nMember names:\n${memberNames.dump()}" +
|
||||||
"\nLocal names:\n$local\n"
|
"\nLocal names:\n$local\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,6 +261,28 @@ class NameTables(packages: List<IrPackageFragment>) {
|
|||||||
error("Can't find name for declaration ${declaration.fqNameWhenAvailable}")
|
error("Can't find name for declaration ${declaration.fqNameWhenAvailable}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getNameForMemberField(field: IrField): String {
|
||||||
|
val signature = fieldSignature(field)
|
||||||
|
val name = memberNames.names[signature]
|
||||||
|
require(name != null) {
|
||||||
|
"Can't find name for member field $field"
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getNameForMemberFunction(function: IrSimpleFunction): String {
|
||||||
|
val signature = functionSignature(function)
|
||||||
|
val name = memberNames.names[signature]
|
||||||
|
|
||||||
|
// TODO: Fix hack: Coroutines runtime currently relies on stable names
|
||||||
|
// of `invoke` functions in FunctionN interfaces
|
||||||
|
if (name == null && signature is ParameterTypeBasedSignature && signature.suggestedName.startsWith("invoke"))
|
||||||
|
return signature.suggestedName
|
||||||
|
require(name != null) {
|
||||||
|
"Can't find name for member function $function"
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
private fun generateNamesForTopLevelDecl(declaration: IrDeclaration) {
|
private fun generateNamesForTopLevelDecl(declaration: IrDeclaration) {
|
||||||
when {
|
when {
|
||||||
@@ -208,85 +343,6 @@ class NameTables(packages: List<IrPackageFragment>) {
|
|||||||
loopNames[loop]!!
|
loopNames[loop]!!
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement without JsScope
|
|
||||||
class LegacyMemberNameGenerator(val scope: JsScope) {
|
|
||||||
|
|
||||||
private val fieldCache = mutableMapOf<IrField, JsName>()
|
|
||||||
private val functionCache = mutableMapOf<IrFunction, JsName>()
|
|
||||||
|
|
||||||
fun getNameForMemberField(field: IrField): JsName {
|
|
||||||
return fieldCache.getOrPut(field) { getNewNameForField(field) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getNameForMemberFunction(function: IrSimpleFunction): JsName {
|
|
||||||
return functionCache.getOrPut(function) { getNewNameForFunction(function) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getNewNameForField(f: IrField): JsName {
|
|
||||||
require(!f.isTopLevel)
|
|
||||||
require(!f.isStatic)
|
|
||||||
|
|
||||||
if (f.isEffectivelyExternal()) {
|
|
||||||
return scope.declareName(f.name.identifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
val parentName = (f.parent as IrDeclarationWithName).name.asString()
|
|
||||||
val name = "${f.name.asString()}_$parentName"
|
|
||||||
|
|
||||||
return scope.declareFreshName(sanitizeName(name))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getNewNameForFunction(declaration: IrSimpleFunction): JsName {
|
|
||||||
require(!declaration.isStaticMethodOfClass)
|
|
||||||
require(declaration.dispatchReceiverParameter != null)
|
|
||||||
|
|
||||||
val declarationName = declaration.getJsNameOrKotlinName().asString()
|
|
||||||
|
|
||||||
if (declaration.origin == JsLoweredDeclarationOrigin.BRIDGE_TO_EXTERNAL_FUNCTION) {
|
|
||||||
return scope.declareName(declarationName)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (declaration.isEffectivelyExternal()) {
|
|
||||||
return scope.declareName(declarationName)
|
|
||||||
}
|
|
||||||
declaration.getJsName()?.let { jsName ->
|
|
||||||
return scope.declareName(jsName)
|
|
||||||
}
|
|
||||||
|
|
||||||
val nameBuilder = StringBuilder()
|
|
||||||
|
|
||||||
// Handle names for special functions
|
|
||||||
if (declaration.isMethodOfAny()) {
|
|
||||||
return scope.declareName(declarationName)
|
|
||||||
}
|
|
||||||
|
|
||||||
nameBuilder.append(declarationName)
|
|
||||||
|
|
||||||
// TODO should we skip type parameters and use upper bound of type parameter when print type of value parameters?
|
|
||||||
declaration.typeParameters.ifNotEmpty {
|
|
||||||
nameBuilder.append("_\$t")
|
|
||||||
joinTo(nameBuilder, "") { "_${it.name.asString()}" }
|
|
||||||
}
|
|
||||||
declaration.extensionReceiverParameter?.let {
|
|
||||||
nameBuilder.append("_r$${it.type.asString()}")
|
|
||||||
}
|
|
||||||
declaration.valueParameters.ifNotEmpty {
|
|
||||||
joinTo(nameBuilder, "") { "_${it.type.asString()}" }
|
|
||||||
}
|
|
||||||
declaration.returnType.let {
|
|
||||||
// Return type is only used in signature for inline class and Unit types because
|
|
||||||
// they are binary incompatible with supertypes.
|
|
||||||
if (it.isInlined() || it.isUnit()) {
|
|
||||||
nameBuilder.append("_ret$${it.asString()}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Check reserved names
|
|
||||||
|
|
||||||
return scope.declareName(sanitizeName(nameBuilder.toString()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun sanitizeName(name: String): String {
|
fun sanitizeName(name: String): String {
|
||||||
if (name.isEmpty()) return "_"
|
if (name.isEmpty()) return "_"
|
||||||
|
|||||||
+1
-1
@@ -103,7 +103,7 @@ val RESERVED_IDENTIFIERS = setOf(
|
|||||||
// global identifiers usually declared in a typical JS interpreter
|
// global identifiers usually declared in a typical JS interpreter
|
||||||
"NaN", "isNaN", "Infinity", "undefined",
|
"NaN", "isNaN", "Infinity", "undefined",
|
||||||
|
|
||||||
"Error", "Object", "Number",
|
"Error", "Object", "Number", "String",
|
||||||
|
|
||||||
"Math", "String", "Boolean", "Date", "Array", "RegExp", "JSON", "Map",
|
"Math", "String", "Boolean", "Date", "Array", "RegExp", "JSON", "Map",
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// Name clashes
|
||||||
|
// IGNORE_BACKEND: JS_IR
|
||||||
|
|
||||||
class A (val p: String, p1: String, p2: String) {
|
class A (val p: String, p1: String, p2: String) {
|
||||||
|
|
||||||
var cond1 :String = ""
|
var cond1 :String = ""
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// Name clashes
|
||||||
|
// IGNORE_BACKEND: JS_IR
|
||||||
|
|
||||||
class A (val p: String, p1: String, p2: String) {
|
class A (val p: String, p1: String, p2: String) {
|
||||||
|
|
||||||
var cond1: String = ""
|
var cond1: String = ""
|
||||||
|
|||||||
+5
@@ -6754,6 +6754,11 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
|
|||||||
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
|
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("abstractCollectionToArray.kt")
|
||||||
|
public void testAbstractCollectionToArray() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/regression/stdlibTestSnippets/abstractCollectionToArray.kt");
|
||||||
|
}
|
||||||
|
|
||||||
public void testAllFilesPresentInStdlibTestSnippets() throws Exception {
|
public void testAllFilesPresentInStdlibTestSnippets() throws Exception {
|
||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/box/regression/stdlibTestSnippets"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS_IR, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/box/regression/stdlibTestSnippets"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS_IR, true);
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -6789,6 +6789,11 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
|||||||
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
|
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("abstractCollectionToArray.kt")
|
||||||
|
public void testAbstractCollectionToArray() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/regression/stdlibTestSnippets/abstractCollectionToArray.kt");
|
||||||
|
}
|
||||||
|
|
||||||
public void testAllFilesPresentInStdlibTestSnippets() throws Exception {
|
public void testAllFilesPresentInStdlibTestSnippets() throws Exception {
|
||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/box/regression/stdlibTestSnippets"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/box/regression/stdlibTestSnippets"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// Name clashes
|
||||||
|
// IGNORE_BACKEND: JS_IR
|
||||||
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1295
|
// EXPECTED_REACHABLE_NODES: 1295
|
||||||
package foo
|
package foo
|
||||||
|
|
||||||
|
|||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
// EXPECTED_REACHABLE_NODES: 1750
|
||||||
|
// KJS_WITH_FULL_RUNTIME
|
||||||
|
|
||||||
|
fun abstractCollectionToArray() {
|
||||||
|
class TestCollection<out E>(val data: Collection<E>) : AbstractCollection<E>() {
|
||||||
|
val invocations = mutableListOf<String>()
|
||||||
|
override val size get() = data.size
|
||||||
|
override fun iterator() = data.iterator()
|
||||||
|
|
||||||
|
override fun toArray(): Array<Any?> {
|
||||||
|
invocations += "toArray1"
|
||||||
|
return data.toTypedArray()
|
||||||
|
}
|
||||||
|
public override fun <T> toArray(array: Array<T>): Array<T> {
|
||||||
|
invocations += "toArray2"
|
||||||
|
return super.toArray(array)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val data = listOf("abc", "def")
|
||||||
|
val coll = TestCollection(data)
|
||||||
|
|
||||||
|
val arr1 = coll.toTypedArray()
|
||||||
|
assertEquals(data, arr1.asList())
|
||||||
|
assertTrue("toArray1" in coll.invocations || "toArray2" in coll.invocations)
|
||||||
|
|
||||||
|
val arr2: Array<String> = coll.toArray(Array(coll.size + 1) { "" })
|
||||||
|
assertEquals(data + listOf(null), arr2.asList())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
abstractCollectionToArray()
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -4,6 +4,8 @@
|
|||||||
*/
|
*/
|
||||||
package kotlin.collections
|
package kotlin.collections
|
||||||
|
|
||||||
|
import kotlin.js.JsName
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a skeletal implementation of the read-only [Collection] interface.
|
* Provides a skeletal implementation of the read-only [Collection] interface.
|
||||||
*
|
*
|
||||||
@@ -28,6 +30,7 @@ public abstract class AbstractCollection<out E> protected constructor() : Collec
|
|||||||
/**
|
/**
|
||||||
* Returns new array of type `Array<Any?>` with the elements of this collection.
|
* Returns new array of type `Array<Any?>` with the elements of this collection.
|
||||||
*/
|
*/
|
||||||
|
@JsName("toArray")
|
||||||
protected open fun toArray(): Array<Any?> = copyToArrayImpl(this)
|
protected open fun toArray(): Array<Any?> = copyToArrayImpl(this)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user