[JS IR BE] New name generator
This commit is contained in:
@@ -26,7 +26,7 @@ import java.util.*
|
||||
class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendContext) {
|
||||
|
||||
private val externalPackageFragmentSymbol = IrExternalPackageFragmentSymbolImpl(context.internalPackageFragmentDescriptor)
|
||||
private val externalPackageFragment = IrExternalPackageFragmentImpl(externalPackageFragmentSymbol)
|
||||
val externalPackageFragment = IrExternalPackageFragmentImpl(externalPackageFragmentSymbol)
|
||||
|
||||
// TODO: Should we drop operator intrinsics in favor of IrDynamicOperatorExpression?
|
||||
|
||||
|
||||
@@ -55,9 +55,12 @@ class JsIrBackendContext(
|
||||
|
||||
override var inVerbosePhase: Boolean = false
|
||||
|
||||
lateinit var externalPackageFragment: IrPackageFragment
|
||||
lateinit var bodilessBuiltInsPackageFragment: IrPackageFragment
|
||||
|
||||
val externalNestedClasses = mutableListOf<IrClass>()
|
||||
val packageLevelJsModules = mutableListOf<IrFile>()
|
||||
val declarationLevelJsModules = mutableListOf<IrDeclaration>()
|
||||
val declarationLevelJsModules = mutableListOf<IrDeclarationWithName>()
|
||||
|
||||
val internalPackageFragmentDescriptor = EmptyPackageFragmentDescriptor(builtIns.builtInsModule, FqName("kotlin.js.internal"))
|
||||
val implicitDeclarationFile by lazy {
|
||||
@@ -87,7 +90,7 @@ class JsIrBackendContext(
|
||||
|
||||
val hasTests get() = testContainerField != null
|
||||
|
||||
val testContainer
|
||||
val testContainer: IrSimpleFunction
|
||||
get() = testContainerField ?: JsIrBuilder.buildFunction("test fun", irBuiltIns.unitType, implicitDeclarationFile).apply {
|
||||
body = JsIrBuilder.buildBlockBody(emptyList())
|
||||
testContainerField = this
|
||||
@@ -117,7 +120,7 @@ class JsIrBackendContext(
|
||||
private val COROUTINE_PACKAGE_FQNAME = COROUTINE_PACKAGE_FQNAME_13
|
||||
private val COROUTINE_INTRINSICS_PACKAGE_FQNAME = COROUTINE_PACKAGE_FQNAME.child(INTRINSICS_PACKAGE_NAME)
|
||||
|
||||
// TODO: due to name clash those weird suffix is required, remove it once `NameGenerator` is implemented
|
||||
// TODO: due to name clash those weird suffix is required, remove it once `MemberNameGenerator` is implemented
|
||||
private val COROUTINE_SUSPEND_OR_RETURN_JS_NAME = "suspendCoroutineUninterceptedOrReturnJS"
|
||||
private val GET_COROUTINE_CONTEXT_NAME = "getCoroutineContext"
|
||||
|
||||
@@ -212,10 +215,10 @@ class JsIrBackendContext(
|
||||
|
||||
val coroutineSuspendOrReturn = symbolTable.referenceSimpleFunction(getJsInternalFunction(COROUTINE_SUSPEND_OR_RETURN_JS_NAME))
|
||||
val coroutineSuspendGetter = ir.symbols.coroutineSuspendedGetter
|
||||
val coroutineGetContext: IrFunctionSymbol
|
||||
val coroutineGetContext: IrSimpleFunctionSymbol
|
||||
get() {
|
||||
val contextGetter =
|
||||
continuationClass.owner.declarations.filterIsInstance<IrFunction>().atMostOne { it.name == CONTINUATION_CONTEXT_GETTER_NAME }
|
||||
continuationClass.owner.declarations.filterIsInstance<IrSimpleFunction>().atMostOne { it.name == CONTINUATION_CONTEXT_GETTER_NAME }
|
||||
?: continuationClass.owner.declarations.filterIsInstance<IrProperty>().atMostOne { it.name == CONTINUATION_CONTEXT_PROPERTY_NAME }?.getter!!
|
||||
return contextGetter.symbol
|
||||
}
|
||||
|
||||
+5
-1
@@ -60,11 +60,15 @@ fun moveBodilessDeclarationsToSeparatePlace(context: JsIrBackendContext, module:
|
||||
FqName.ROOT
|
||||
)
|
||||
|
||||
context.externalPackageFragment = externalPackageFragment
|
||||
|
||||
val bodilessBuiltInsPackageFragment = IrExternalPackageFragmentImpl(
|
||||
DescriptorlessExternalPackageFragmentSymbol(),
|
||||
FqName("kotlin")
|
||||
)
|
||||
|
||||
context.bodilessBuiltInsPackageFragment = bodilessBuiltInsPackageFragment
|
||||
|
||||
fun isBuiltInClass(declaration: IrDeclaration): Boolean =
|
||||
declaration is IrClass && declaration.fqNameWhenAvailable in BODILESS_BUILTIN_CLASSES
|
||||
|
||||
@@ -92,7 +96,7 @@ fun moveBodilessDeclarationsToSeparatePlace(context: JsIrBackendContext, module:
|
||||
val it = irFile.declarations.iterator()
|
||||
|
||||
while (it.hasNext()) {
|
||||
val d = it.next()
|
||||
val d = it.next() as? IrDeclarationWithName ?: continue
|
||||
|
||||
if (isBuiltInClass(d)) {
|
||||
it.remove()
|
||||
|
||||
+9
-3
@@ -37,14 +37,20 @@ class StaticMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
|
||||
staticDeclarationsInClasses.add(declaration)
|
||||
super.visitSimpleFunction(declaration)
|
||||
}
|
||||
|
||||
override fun visitVariable(declaration: IrVariable) {
|
||||
// TODO: Don't generate variables inside classes
|
||||
if (declaration.parent is IrClass)
|
||||
staticDeclarationsInClasses.add(declaration)
|
||||
super.visitVariable(declaration)
|
||||
}
|
||||
})
|
||||
|
||||
for (declaration in staticDeclarationsInClasses) {
|
||||
val klass = declaration.parentAsClass
|
||||
val fragment = klass.getPackageFragment()!!
|
||||
klass.declarations.remove(declaration)
|
||||
fragment.addChild(declaration)
|
||||
declaration.parent = fragment
|
||||
irFile.addChild(declaration)
|
||||
declaration.parent = irFile
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
|
||||
@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
|
||||
class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatement, JsGenerationContext> {
|
||||
|
||||
override fun visitSimpleFunction(declaration: IrSimpleFunction, context: JsGenerationContext): JsStatement {
|
||||
@@ -33,7 +34,7 @@ class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatemen
|
||||
}
|
||||
|
||||
override fun visitField(declaration: IrField, context: JsGenerationContext): JsStatement {
|
||||
val fieldName = context.getNameForSymbol(declaration.symbol)
|
||||
val fieldName = context.getNameForField(declaration)
|
||||
|
||||
if (declaration.isExternal) return JsEmpty
|
||||
|
||||
|
||||
+64
-33
@@ -6,10 +6,7 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsName
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
@@ -64,26 +61,38 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
}
|
||||
|
||||
override fun visitGetField(expression: IrGetField, context: JsGenerationContext): JsExpression {
|
||||
if (expression.symbol.isBound) {
|
||||
val fieldParent = expression.symbol.owner.parent
|
||||
if (fieldParent is IrClass && fieldParent.isInline) {
|
||||
return expression.receiver!!.accept(this, context)
|
||||
}
|
||||
val symbol = expression.symbol
|
||||
val field = symbol.owner
|
||||
|
||||
val fieldParent = field.parent
|
||||
|
||||
if (fieldParent is IrClass && field.isEffectivelyExternal()) {
|
||||
// External fields are only allowed in external enums
|
||||
assert(fieldParent.isEnumClass)
|
||||
return JsNameRef(
|
||||
field.getJsNameOrKotlinName().identifier,
|
||||
context.getNameForClass(fieldParent).makeRef()
|
||||
)
|
||||
}
|
||||
val fieldName = context.getNameForSymbol(expression.symbol)
|
||||
|
||||
if (fieldParent is IrClass && fieldParent.isInline) {
|
||||
return expression.receiver!!.accept(this, context)
|
||||
}
|
||||
val fieldName = context.getNameForField(field)
|
||||
return JsNameRef(fieldName, expression.receiver?.accept(this, context))
|
||||
}
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue, context: JsGenerationContext): JsExpression =
|
||||
context.getNameForSymbol(expression.symbol).makeRef()
|
||||
context.getNameForValueDeclaration(expression.symbol.owner).makeRef()
|
||||
|
||||
override fun visitGetObjectValue(expression: IrGetObjectValue, context: JsGenerationContext) = when (expression.symbol.owner.kind) {
|
||||
ClassKind.OBJECT -> {
|
||||
val obj = expression.symbol.owner
|
||||
val className = context.getNameForSymbol(expression.symbol)
|
||||
if (obj.isEffectivelyExternal()) {
|
||||
className.makeRef()
|
||||
context.getRefForExternalClass(obj)
|
||||
} else {
|
||||
val className = context.getNameForClass(expression.symbol.owner)
|
||||
// TODO: Don't use implicit naming
|
||||
val getInstanceName = className.ident + "_getInstance"
|
||||
JsInvocation(JsNameRef(getInstanceName))
|
||||
}
|
||||
@@ -93,24 +102,24 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
|
||||
|
||||
override fun visitSetField(expression: IrSetField, context: JsGenerationContext): JsExpression {
|
||||
val fieldName = context.getNameForSymbol(expression.symbol)
|
||||
val fieldName = context.getNameForField(expression.symbol.owner)
|
||||
val dest = JsNameRef(fieldName, expression.receiver?.accept(this, context))
|
||||
val source = expression.value.accept(this, context)
|
||||
return jsAssignment(dest, source)
|
||||
}
|
||||
|
||||
override fun visitSetVariable(expression: IrSetVariable, context: JsGenerationContext): JsExpression {
|
||||
val ref = JsNameRef(context.getNameForSymbol(expression.symbol))
|
||||
val ref = JsNameRef(context.getNameForValueDeclaration(expression.symbol.owner))
|
||||
val value = expression.value.accept(this, context)
|
||||
return JsBinaryOperation(JsBinaryOperator.ASG, ref, value)
|
||||
}
|
||||
|
||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, context: JsGenerationContext): JsExpression {
|
||||
val classNameRef = context.getNameForSymbol(expression.symbol).makeRef()
|
||||
val classNameRef = context.getNameForConstructor(expression.symbol.owner).makeRef()
|
||||
val callFuncRef = JsNameRef(Namer.CALL_FUNCTION, classNameRef)
|
||||
val fromPrimary = context.currentFunction is IrConstructor
|
||||
val thisRef =
|
||||
if (fromPrimary) JsThisRef() else context.getNameForSymbol(context.currentFunction!!.valueParameters.last().symbol).makeRef()
|
||||
if (fromPrimary) JsThisRef() else context.getNameForValueDeclaration(context.currentFunction!!.valueParameters.last()).makeRef()
|
||||
val arguments = translateCallArguments(expression, context)
|
||||
|
||||
val constructor = expression.symbol.owner
|
||||
@@ -139,9 +148,9 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
// Transform external property accessor call
|
||||
// @JsName-annotated external property accessors are translated as function calls
|
||||
if (function is IrSimpleFunction && function.getJsName() == null) {
|
||||
val property = function.correspondingProperty
|
||||
val property = function.correspondingPropertySymbol?.owner
|
||||
if (property != null && property.isEffectivelyExternal()) {
|
||||
val nameRef = JsNameRef(context.getNameForDeclaration(property), jsDispatchReceiver)
|
||||
val nameRef = JsNameRef(context.getNameForProperty(property), jsDispatchReceiver)
|
||||
return when (function) {
|
||||
property.getter -> nameRef
|
||||
property.setter -> jsAssignment(nameRef, arguments.single())
|
||||
@@ -154,13 +163,18 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
return JsInvocation(jsDispatchReceiver!!, arguments)
|
||||
}
|
||||
|
||||
expression.superQualifierSymbol?.let {
|
||||
val (target, owner) = if (it.owner.isInterface) {
|
||||
val impl = (symbol.owner as IrSimpleFunction).resolveFakeOverride()!!
|
||||
expression.superQualifierSymbol?.let { superQualifier ->
|
||||
require(function is IrSimpleFunction)
|
||||
|
||||
val (target, klass) = if (superQualifier.owner.isInterface) {
|
||||
val impl = function.resolveFakeOverride()!!
|
||||
Pair(impl, impl.parentAsClass)
|
||||
} else Pair(symbol.owner, it.owner)
|
||||
val qualifierName = context.getNameForSymbol(owner.symbol).makeRef()
|
||||
val targetName = context.getNameForSymbol(target.symbol)
|
||||
} else {
|
||||
Pair(function, superQualifier.owner)
|
||||
}
|
||||
|
||||
val qualifierName = context.getNameForClass(klass).makeRef()
|
||||
val targetName = context.getNameForMemberFunction(target)
|
||||
val qPrototype = JsNameRef(targetName, prototypeOf(qualifierName))
|
||||
val callRef = JsNameRef(Namer.CALL_FUNCTION, qPrototype)
|
||||
return JsInvocation(callRef, jsDispatchReceiver?.let { receiver -> listOf(receiver) + arguments } ?: arguments)
|
||||
@@ -169,26 +183,43 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
val varargParameterIndex = function.valueParameters.indexOfFirst { it.varargElementType != null }
|
||||
val isExternalVararg = function.isEffectivelyExternal() && varargParameterIndex != -1
|
||||
|
||||
val symbolName = context.getNameForSymbol(symbol)
|
||||
val ref = if (function is IrSimpleFunction && jsDispatchReceiver != null) JsNameRef(symbolName, jsDispatchReceiver) else JsNameRef(
|
||||
symbolName
|
||||
)
|
||||
|
||||
return if (function is IrConstructor) {
|
||||
if (function is IrConstructor) {
|
||||
// Inline class primary constructor takes a single value of to
|
||||
// initialize underlying property.
|
||||
// TODO: Support initialization block
|
||||
val klass = function.parentAsClass
|
||||
if (klass.isInline) {
|
||||
return if (klass.isInline) {
|
||||
assert(function.isPrimary) {
|
||||
"Inline class secondary constructors must be lowered into static methods"
|
||||
}
|
||||
// Argument value constructs unboxed inline class instance
|
||||
arguments.single()
|
||||
} else {
|
||||
val ref = when {
|
||||
klass.isEffectivelyExternal() ->
|
||||
context.getRefForExternalClass(klass)
|
||||
|
||||
else ->
|
||||
context.getNameForClass(klass).makeRef()
|
||||
}
|
||||
JsNew(ref, arguments)
|
||||
}
|
||||
} else if (isExternalVararg) {
|
||||
}
|
||||
|
||||
require(function is IrSimpleFunction)
|
||||
|
||||
val symbolName = when (jsDispatchReceiver) {
|
||||
null -> context.getNameForStaticFunction(function)
|
||||
else -> context.getNameForMemberFunction(function)
|
||||
}
|
||||
|
||||
val ref = when (jsDispatchReceiver) {
|
||||
null -> JsNameRef(symbolName)
|
||||
else -> JsNameRef(symbolName, jsDispatchReceiver)
|
||||
}
|
||||
|
||||
return if (isExternalVararg) {
|
||||
|
||||
// External vararg arguments should be represented in JS as multiple "plain" arguments (opposed to arrays in Kotlin)
|
||||
// We are using `Function.prototype.apply` function to pass all arguments as a single array.
|
||||
@@ -213,7 +244,7 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
}
|
||||
)
|
||||
|
||||
if (function is IrSimpleFunction && jsDispatchReceiver != null) {
|
||||
if (jsDispatchReceiver != null) {
|
||||
// TODO: Do not create IIFE when receiver expression is simple or has no side effects
|
||||
// TODO: Do not create IIFE at all? (Currently there is no reliable way to create temporary variable in current scope)
|
||||
val receiverName = context.currentScope.declareFreshName("\$externalVarargReceiverTmp")
|
||||
|
||||
+6
-6
@@ -43,11 +43,11 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
|
||||
}
|
||||
|
||||
override fun visitBreak(jump: IrBreak, context: JsGenerationContext): JsStatement {
|
||||
return JsBreak(context.getNameForLoop(jump.loop)?.makeRef())
|
||||
return JsBreak(context.getNameForLoop(jump.loop)?.let { JsNameRef(it) })
|
||||
}
|
||||
|
||||
override fun visitContinue(jump: IrContinue, context: JsGenerationContext): JsStatement {
|
||||
return JsContinue(context.getNameForLoop(jump.loop)?.makeRef())
|
||||
return JsContinue(context.getNameForLoop(jump.loop)?.let { JsNameRef(it) })
|
||||
}
|
||||
|
||||
override fun visitReturn(expression: IrReturn, context: JsGenerationContext): JsStatement {
|
||||
@@ -59,7 +59,7 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
|
||||
}
|
||||
|
||||
override fun visitVariable(declaration: IrVariable, context: JsGenerationContext): JsStatement {
|
||||
val varName = context.getNameForSymbol(declaration.symbol)
|
||||
val varName = context.getNameForValueDeclaration(declaration)
|
||||
return jsVar(varName, declaration.initializer, context)
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
|
||||
val jsTryBlock = aTry.tryResult.accept(this, context).asBlock()
|
||||
|
||||
val jsCatch = aTry.catches.singleOrNull()?.let {
|
||||
val name = context.getNameForSymbol(it.catchParameter.symbol)
|
||||
val name = context.getNameForValueDeclaration(it.catchParameter)
|
||||
val jsCatchBlock = it.result.accept(this, context)
|
||||
JsCatch(context.currentScope, name.ident, jsCatchBlock)
|
||||
}
|
||||
@@ -128,14 +128,14 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
|
||||
|
||||
override fun visitWhileLoop(loop: IrWhileLoop, context: JsGenerationContext): JsStatement {
|
||||
//TODO what if body null?
|
||||
val label = context.getNameForLoop(loop)
|
||||
val label = context.getNameForLoop(loop)?.let { context.staticContext.rootScope.declareName(it) }
|
||||
val loopStatement = JsWhile(loop.condition.accept(IrElementToJsExpressionTransformer(), context), loop.body?.accept(this, context))
|
||||
return label?.let { JsLabel(it, loopStatement) } ?: loopStatement
|
||||
}
|
||||
|
||||
override fun visitDoWhileLoop(loop: IrDoWhileLoop, context: JsGenerationContext): JsStatement {
|
||||
//TODO what if body null?
|
||||
val label = context.getNameForLoop(loop)
|
||||
val label = context.getNameForLoop(loop)?.let { context.staticContext.rootScope.declareName(it) }
|
||||
val loopStatement =
|
||||
JsDoWhile(loop.condition.accept(IrElementToJsExpressionTransformer(), context), loop.body?.accept(this, context))
|
||||
return label?.let { JsLabel(it, loopStatement) } ?: loopStatement
|
||||
|
||||
+8
-3
@@ -12,15 +12,20 @@ import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.util.isObject
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsFunction
|
||||
|
||||
open class IrFunctionToJsTransformer : BaseIrElementToJsNodeTransformer<JsFunction, JsGenerationContext> {
|
||||
@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
|
||||
class IrFunctionToJsTransformer : BaseIrElementToJsNodeTransformer<JsFunction, JsGenerationContext> {
|
||||
override fun visitSimpleFunction(declaration: IrSimpleFunction, context: JsGenerationContext): JsFunction {
|
||||
val funcName = context.getNameForSymbol(declaration.symbol)
|
||||
val funcName = if (declaration.dispatchReceiverParameter == null) {
|
||||
context.getNameForStaticFunction(declaration)
|
||||
} else {
|
||||
context.getNameForMemberFunction(declaration)
|
||||
}
|
||||
return translateFunction(declaration, funcName, false, context)
|
||||
}
|
||||
|
||||
override fun visitConstructor(declaration: IrConstructor, context: JsGenerationContext): JsFunction {
|
||||
assert(declaration.isPrimary)
|
||||
val funcName = context.getNameForSymbol(declaration.symbol)
|
||||
val funcName = context.getNameForConstructor(declaration)
|
||||
val constructedClass = declaration.parent as IrClass
|
||||
return translateFunction(declaration, funcName, constructedClass.isObject, context)
|
||||
}
|
||||
|
||||
+136
-79
@@ -9,18 +9,18 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithVisibility
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.ir.util.isObject
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
class IrModuleToJsTransformer(
|
||||
private val backendContext: JsIrBackendContext
|
||||
) : BaseIrElementToJsNodeTransformer<JsNode, Nothing?> {
|
||||
|
||||
class IrModuleToJsTransformer(private val backendContext: JsIrBackendContext) : BaseIrElementToJsNodeTransformer<JsNode, Nothing?> {
|
||||
val moduleName = backendContext.configuration[CommonConfigurationKeys.MODULE_NAME]!!
|
||||
private val moduleKind = backendContext.configuration[JSConfigurationKeys.MODULE_KIND]!!
|
||||
|
||||
@@ -28,11 +28,13 @@ class IrModuleToJsTransformer(private val backendContext: JsIrBackendContext) :
|
||||
val statements = mutableListOf<JsStatement>()
|
||||
|
||||
// TODO: fix it up with new name generator
|
||||
val anyName = context.getNameForSymbol(backendContext.irBuiltIns.anyClass)
|
||||
val throwableName = context.getNameForSymbol(backendContext.irBuiltIns.throwableClass)
|
||||
val anyName = context.getNameForClass(backendContext.irBuiltIns.anyClass.owner)
|
||||
val throwableName = context.getNameForClass(backendContext.irBuiltIns.throwableClass.owner)
|
||||
val stringName = context.getNameForClass(backendContext.irBuiltIns.stringClass.owner)
|
||||
|
||||
statements += JsVars(JsVars.JsVar(anyName, Namer.JS_OBJECT))
|
||||
statements += JsVars(JsVars.JsVar(throwableName, Namer.JS_ERROR))
|
||||
statements += JsVars(JsVars.JsVar(stringName, JsNameRef("String")))
|
||||
|
||||
val preDeclarationBlock = JsBlock()
|
||||
val postDeclarationBlock = JsBlock()
|
||||
@@ -50,7 +52,7 @@ class IrModuleToJsTransformer(private val backendContext: JsIrBackendContext) :
|
||||
statements += context.staticContext.initializerBlock
|
||||
|
||||
if (backendContext.hasTests) {
|
||||
statements += JsInvocation(context.getNameForSymbol(backendContext.testContainer.symbol).makeRef()).makeStmt()
|
||||
statements += JsInvocation(context.getNameForStaticFunction(backendContext.testContainer).makeRef()).makeStmt()
|
||||
}
|
||||
|
||||
return statements
|
||||
@@ -61,40 +63,132 @@ class IrModuleToJsTransformer(private val backendContext: JsIrBackendContext) :
|
||||
context: JsGenerationContext,
|
||||
internalModuleName: JsName
|
||||
): List<JsStatement> {
|
||||
return module.files
|
||||
.flatMap { it.declarations }
|
||||
.asSequence()
|
||||
.filterIsInstance<IrDeclarationWithVisibility>()
|
||||
.filter { it.visibility == Visibilities.PUBLIC }
|
||||
.filter { !it.isEffectivelyExternal() }
|
||||
.filterIsInstance<IrSymbolOwner>()
|
||||
.map { declaration ->
|
||||
val name = context.getNameForSymbol(declaration.symbol)
|
||||
val exports = mutableListOf<JsExpressionStatement>()
|
||||
|
||||
JsExpressionStatement(
|
||||
if (declaration is IrClass && declaration.isObject) {
|
||||
defineProperty(internalModuleName.makeRef(), name.ident, getter = JsNameRef("${name.ident}_getInstance"))
|
||||
} else {
|
||||
jsAssignment(JsNameRef(name, internalModuleName.makeRef()), name.makeRef())
|
||||
}
|
||||
for (file in module.files) {
|
||||
for (declaration in file.declarations) {
|
||||
exports.addIfNotNull(
|
||||
generateExportStatement(declaration, context, internalModuleName)
|
||||
)
|
||||
}
|
||||
.toList()
|
||||
}
|
||||
|
||||
return exports
|
||||
}
|
||||
|
||||
private fun generateExportStatement(
|
||||
declaration: IrDeclaration,
|
||||
context: JsGenerationContext,
|
||||
internalModuleName: JsName
|
||||
): JsExpressionStatement? {
|
||||
if (declaration !is IrDeclarationWithVisibility ||
|
||||
declaration !is IrDeclarationWithName ||
|
||||
declaration.visibility != Visibilities.PUBLIC) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (declaration.isEffectivelyExternal())
|
||||
return null
|
||||
|
||||
if (declaration is IrClass && declaration.isCompanion)
|
||||
return null
|
||||
|
||||
val name: JsName = when (declaration) {
|
||||
is IrSimpleFunction -> context.getNameForStaticFunction(declaration)
|
||||
is IrClass -> context.getNameForClass(declaration)
|
||||
// TODO: Fields must be exported as properties
|
||||
is IrField -> context.getNameForField(declaration)
|
||||
else -> return null
|
||||
}
|
||||
|
||||
val exportName = sanitizeName(declaration.getJsNameOrKotlinName().asString())
|
||||
|
||||
val expression =
|
||||
if (declaration is IrClass && declaration.isObject) {
|
||||
// TODO: Use export names for properties
|
||||
defineProperty(internalModuleName.makeRef(), name.ident, getter = JsNameRef("${name.ident}_getInstance"))
|
||||
} else {
|
||||
jsAssignment(JsNameRef(exportName, internalModuleName.makeRef()), name.makeRef())
|
||||
}
|
||||
|
||||
return JsExpressionStatement(expression)
|
||||
}
|
||||
|
||||
|
||||
|
||||
private fun generateModule(module: IrModuleFragment): JsProgram {
|
||||
val additionalPackages = with(backendContext) {
|
||||
listOf(
|
||||
externalPackageFragment,
|
||||
bodilessBuiltInsPackageFragment,
|
||||
intrinsics.externalPackageFragment
|
||||
) + packageLevelJsModules
|
||||
}
|
||||
|
||||
val namer = NameTables(module.files + additionalPackages)
|
||||
|
||||
val program = JsProgram()
|
||||
val rootContext = JsGenerationContext(JsRootScope(program), backendContext)
|
||||
|
||||
val nameGenerator = IrNamerImpl(
|
||||
memberNameGenerator = LegacyMemberNameGenerator(program.rootScope),
|
||||
newNameTables = namer,
|
||||
rootScope = program.rootScope
|
||||
)
|
||||
val staticContext = JsStaticContext(
|
||||
backendContext = backendContext,
|
||||
irNamer = nameGenerator,
|
||||
rootScope = program.rootScope
|
||||
)
|
||||
val rootContext = JsGenerationContext(
|
||||
parent = null,
|
||||
currentBlock = program.globalBlock,
|
||||
currentFunction = null,
|
||||
currentScope = program.rootScope,
|
||||
staticContext = staticContext
|
||||
)
|
||||
|
||||
val rootFunction = JsFunction(program.rootScope, JsBlock(), "root function")
|
||||
val internalModuleName = rootFunction.scope.declareName("_")
|
||||
|
||||
rootFunction.parameters += JsParameter(internalModuleName)
|
||||
val (importStatements, importedJsModules) =
|
||||
generateImportStatements(
|
||||
getNameForExternalDeclaration = { rootContext.getNameForStaticDeclaration(it) },
|
||||
declareFreshGlobal = { rootFunction.scope.declareFreshName(sanitizeName(it)) }
|
||||
)
|
||||
|
||||
val moduleBody = generateModuleBody(module, rootContext)
|
||||
val exportStatements = generateExportStatements(module, rootContext, internalModuleName)
|
||||
|
||||
with(rootFunction) {
|
||||
parameters += JsParameter(internalModuleName)
|
||||
parameters += importedJsModules.map { JsParameter(it.internalName) }
|
||||
with(body) {
|
||||
statements += importStatements
|
||||
statements += moduleBody
|
||||
statements += exportStatements
|
||||
statements += JsReturn(internalModuleName.makeRef())
|
||||
}
|
||||
}
|
||||
|
||||
program.globalBlock.statements += ModuleWrapperTranslation.wrap(
|
||||
moduleName,
|
||||
rootFunction,
|
||||
importedJsModules,
|
||||
program,
|
||||
kind = moduleKind
|
||||
)
|
||||
|
||||
return program
|
||||
}
|
||||
|
||||
private fun generateImportStatements(
|
||||
getNameForExternalDeclaration: (IrDeclarationWithName) -> JsName,
|
||||
declareFreshGlobal: (String) -> JsName
|
||||
): Pair<MutableList<JsStatement>, List<JsImportedModule>> {
|
||||
val declarationLevelJsModules =
|
||||
backendContext.declarationLevelJsModules.map { externalDeclaration ->
|
||||
val jsModule = externalDeclaration.getJsModule()!!
|
||||
val name = rootContext.getNameForDeclaration(externalDeclaration)
|
||||
val name = getNameForExternalDeclaration(externalDeclaration)
|
||||
JsImportedModule(jsModule, name, name.makeRef())
|
||||
}
|
||||
|
||||
@@ -110,7 +204,7 @@ class IrModuleToJsTransformer(private val backendContext: JsIrBackendContext) :
|
||||
val qualifiedReference: JsNameRef
|
||||
|
||||
if (jsModule != null) {
|
||||
val internalName = rootFunction.scope.declareFreshName(sanitizeName("\$module\$$jsModule"))
|
||||
val internalName = declareFreshGlobal("\$module\$$jsModule")
|
||||
packageLevelJsModules += JsImportedModule(jsModule, internalName, null)
|
||||
|
||||
qualifiedReference =
|
||||
@@ -122,61 +216,24 @@ class IrModuleToJsTransformer(private val backendContext: JsIrBackendContext) :
|
||||
qualifiedReference = JsNameRef(jsQualifier!!)
|
||||
}
|
||||
|
||||
file.declarations.forEach { declaration ->
|
||||
val declName = rootContext.getNameForDeclaration(declaration)
|
||||
importStatements.add(
|
||||
JsExpressionStatement(
|
||||
jsAssignment(
|
||||
declName.makeRef(),
|
||||
JsNameRef(declName, qualifiedReference)
|
||||
file.declarations
|
||||
.asSequence()
|
||||
.filterIsInstance<IrDeclarationWithName>()
|
||||
.forEach { declaration ->
|
||||
val declName = getNameForExternalDeclaration(declaration)
|
||||
importStatements.add(
|
||||
JsExpressionStatement(
|
||||
jsAssignment(
|
||||
declName.makeRef(),
|
||||
JsNameRef(declName, qualifiedReference)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
for (externalClass in backendContext.externalNestedClasses) {
|
||||
|
||||
// External companions are not "nested". Instead they use parent class name.
|
||||
if (externalClass.isCompanion)
|
||||
continue
|
||||
|
||||
val declName = rootContext.getNameForDeclaration(externalClass)
|
||||
val parentName = rootContext.getNameForDeclaration(externalClass.parentAsClass)
|
||||
importStatements.add(
|
||||
JsExpressionStatement(
|
||||
jsAssignment(
|
||||
declName.makeRef(),
|
||||
JsNameRef(externalClass.getJsNameOrKotlinName().identifier, parentName.makeRef())
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val importedJsModules = declarationLevelJsModules + packageLevelJsModules
|
||||
rootFunction.parameters += importedJsModules.map { JsParameter(it.internalName) }
|
||||
|
||||
rootFunction.body.statements += importStatements
|
||||
|
||||
val moduleBody = generateModuleBody(module, rootContext)
|
||||
|
||||
val exportStatements = generateExportStatements(module, rootContext, internalModuleName)
|
||||
|
||||
rootFunction.body.statements += moduleBody
|
||||
|
||||
rootFunction.body.statements += exportStatements
|
||||
|
||||
rootFunction.body.statements += JsReturn(internalModuleName.makeRef())
|
||||
|
||||
program.globalBlock.statements += ModuleWrapperTranslation.wrap(
|
||||
moduleName,
|
||||
rootFunction,
|
||||
importedJsModules,
|
||||
program,
|
||||
kind = moduleKind
|
||||
)
|
||||
|
||||
return program
|
||||
return Pair(importStatements, importedJsModules)
|
||||
}
|
||||
|
||||
override fun visitModuleFragment(declaration: IrModuleFragment, data: Nothing?): JsNode =
|
||||
|
||||
+14
-12
@@ -26,10 +26,12 @@ import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationContext) {
|
||||
|
||||
private val className = context.getNameForSymbol(irClass.symbol)
|
||||
private val className = context.getNameForClass(irClass)
|
||||
private val classNameRef = className.makeRef()
|
||||
private val baseClass = irClass.superTypes.firstOrNull { !it.classifierOrFail.isInterface }
|
||||
private val baseClassName = baseClass?.let { context.getNameForType(it) }
|
||||
private val baseClass: IrType? = irClass.superTypes.firstOrNull { !it.classifierOrFail.isInterface }
|
||||
private val baseClassName = baseClass?.let {
|
||||
context.getNameForClass(baseClass.classifierOrFail.owner as IrClass)
|
||||
}
|
||||
private val classPrototypeRef = prototypeOf(classNameRef)
|
||||
private val classBlock = JsGlobalBlock()
|
||||
private val classModel = JsClassModel(className, baseClassName)
|
||||
@@ -87,9 +89,9 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
classBlock.statements += JsExpressionStatement(
|
||||
defineProperty(
|
||||
classPrototypeRef,
|
||||
context.getNameForDeclaration(property).ident,
|
||||
getter = property.getter?.let { context.getNameForDeclaration(it) }?.let { JsNameRef(it, classPrototypeRef) },
|
||||
setter = property.setter?.let { context.getNameForDeclaration(it) }?.let { JsNameRef(it, classPrototypeRef) }
|
||||
context.getNameForProperty(property).ident,
|
||||
getter = property.getter?.let { JsNameRef(context.getNameForMemberFunction(it), classPrototypeRef) },
|
||||
setter = property.setter?.let { JsNameRef(context.getNameForMemberFunction(it), classPrototypeRef) }
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -115,7 +117,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
}
|
||||
|
||||
private fun buildGetterFunction(delegate: IrSimpleFunction): JsFunction {
|
||||
val getterName = context.getNameForSymbol(delegate.symbol)
|
||||
val getterName = context.getNameForMemberFunction(delegate)
|
||||
val returnStatement = JsReturn(JsInvocation(JsNameRef(getterName, JsThisRef())))
|
||||
|
||||
return JsFunction(JsFunctionScope(context.currentScope, ""), JsBlock(returnStatement), "")
|
||||
@@ -128,7 +130,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
return translatedFunction?.makeStmt()
|
||||
}
|
||||
|
||||
val memberName = context.getNameForSymbol(declaration.realOverrideTarget.symbol)
|
||||
val memberName = context.getNameForMemberFunction(declaration.realOverrideTarget)
|
||||
val memberRef = JsNameRef(memberName, classPrototypeRef)
|
||||
|
||||
translatedFunction?.let { return jsAssignment(memberRef, it.apply { name = null }).makeStmt() }
|
||||
@@ -147,8 +149,8 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
}
|
||||
|
||||
if (!implClassDeclaration.defaultType.isAny() && !it.isEffectivelyExternal()) {
|
||||
val implMethodName = context.getNameForSymbol(it.symbol)
|
||||
val implClassName = context.getNameForSymbol(implClassDeclaration.symbol)
|
||||
val implMethodName = context.getNameForMemberFunction(it)
|
||||
val implClassName = context.getNameForClass(implClassDeclaration)
|
||||
|
||||
val implClassPrototype = prototypeOf(implClassName.makeRef())
|
||||
val implMemberRef = JsNameRef(implMethodName, implClassPrototype)
|
||||
@@ -247,10 +249,10 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
JsNameRef(Namer.METADATA_INTERFACES),
|
||||
JsArrayLiteral(
|
||||
irClass.superTypes.mapNotNull {
|
||||
val symbol = it.classifierOrFail
|
||||
val symbol = it.classifierOrFail as IrClassSymbol
|
||||
// TODO: make sure that there is a test which breaks when isExternal is used here instead of isEffectivelyExternal
|
||||
if (symbol.isInterface && !functionTypeOrSubtype && !symbol.isEffectivelyExternal) {
|
||||
JsNameRef(context.getNameForSymbol(symbol))
|
||||
JsNameRef(context.getNameForClass(symbol.owner))
|
||||
} else null
|
||||
}
|
||||
)
|
||||
|
||||
+24
-11
@@ -8,15 +8,16 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.util.getInlineClassBackingField
|
||||
import org.jetbrains.kotlin.ir.util.getInlinedClass
|
||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
|
||||
typealias IrCallTransformer = (IrCall, context: JsGenerationContext) -> JsExpression
|
||||
@@ -78,8 +79,8 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
prefixOp(intrinsics.jsTypeOf, JsUnaryOperator.TYPEOF)
|
||||
|
||||
add(intrinsics.jsObjectCreate) { call, context ->
|
||||
val classToCreate = call.getTypeArgument(0)!!
|
||||
val className = context.getNameForSymbol(classToCreate.classifierOrFail)
|
||||
val classToCreate = call.getTypeArgument(0)!!.classifierOrFail.owner as IrClass
|
||||
val className = context.getNameForClass(classToCreate)
|
||||
val prototype = prototypeOf(className.makeRef())
|
||||
JsInvocation(Namer.JS_OBJECT_CREATE_FUNCTION, prototype)
|
||||
}
|
||||
@@ -106,8 +107,16 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
}
|
||||
|
||||
add(intrinsics.jsClass) { call, context ->
|
||||
val typeName = context.getNameForSymbol(call.getTypeArgument(0)!!.classifierOrFail)
|
||||
typeName.makeRef()
|
||||
val classifier: IrClassifierSymbol = call.getTypeArgument(0)!!.classifierOrFail
|
||||
val owner = classifier.owner
|
||||
|
||||
when {
|
||||
owner is IrClass && owner.isEffectivelyExternal() ->
|
||||
context.getRefForExternalClass(owner)
|
||||
|
||||
else ->
|
||||
context.getNameForStaticDeclaration(owner as IrDeclarationWithName).makeRef()
|
||||
}
|
||||
}
|
||||
|
||||
addIfNotNull(intrinsics.jsCode) { call, context ->
|
||||
@@ -147,7 +156,7 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
|
||||
add(intrinsics.jsCoroutineContext) { _, context: JsGenerationContext ->
|
||||
val contextGetter = backendContext.coroutineGetContext
|
||||
val getterName = context.getNameForSymbol(contextGetter)
|
||||
val getterName = context.getNameForStaticFunction(contextGetter.owner)
|
||||
val continuation = context.continuation
|
||||
JsInvocation(JsNameRef(getterName, continuation))
|
||||
}
|
||||
@@ -193,14 +202,14 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
val arg = translateCallArguments(call, context).single()
|
||||
val inlineClass = call.getTypeArgument(0)!!.getInlinedClass()!!
|
||||
val constructor = inlineClass.declarations.filterIsInstance<IrConstructor>().single { it.isPrimary }
|
||||
JsNew(context.getNameForSymbol(constructor.symbol).makeRef(), listOf(arg))
|
||||
JsNew(context.getNameForConstructor(constructor).makeRef(), listOf(arg))
|
||||
}
|
||||
|
||||
add(intrinsics.jsUnboxIntrinsic) { call: IrCall, context ->
|
||||
val arg = translateCallArguments(call, context).single()
|
||||
val inlineClass = call.getTypeArgument(1)!!.getInlinedClass()!!
|
||||
val field = getInlineClassBackingField(inlineClass)
|
||||
val fieldName = context.getNameForSymbol(field.symbol)
|
||||
val fieldName = context.getNameForField(field)
|
||||
JsNameRef(fieldName, arg)
|
||||
}
|
||||
|
||||
@@ -210,13 +219,17 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
val superClass = call.superQualifierSymbol!!
|
||||
|
||||
val jsReceiver = receiver.accept(IrElementToJsExpressionTransformer(), context)
|
||||
val functionName = context.getNameForSymbol(reference.symbol)
|
||||
val superName = context.getNameForSymbol(superClass).makeRef()
|
||||
val functionName = context.getNameForMemberFunction(reference.symbol.owner as IrSimpleFunction)
|
||||
val superName = context.getNameForClass(superClass.owner).makeRef()
|
||||
val qPrototype = JsNameRef(functionName, prototypeOf(superName))
|
||||
val bindRef = JsNameRef(Namer.BIND_FUNCTION, qPrototype)
|
||||
|
||||
JsInvocation(bindRef, jsReceiver)
|
||||
}
|
||||
|
||||
add(intrinsics.unreachable) { _, _ ->
|
||||
JsInvocation(JsNameRef(Namer.UNREACHABLE_NAME))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -39,7 +39,7 @@ fun prototypeOf(classNameRef: JsExpression) = JsNameRef(Namer.PROTOTYPE_NAME, cl
|
||||
fun translateFunction(declaration: IrFunction, name: JsName?, isObjectConstructor: Boolean, context: JsGenerationContext): JsFunction {
|
||||
val functionScope = JsFunctionScope(context.currentScope, "scope for ${name ?: "annon"}")
|
||||
val functionContext = context.newDeclaration(functionScope, declaration)
|
||||
val functionParams = declaration.valueParameters.map { functionContext.getNameForSymbol(it.symbol) }
|
||||
val functionParams = declaration.valueParameters.map { functionContext.getNameForValueDeclaration(it) }
|
||||
val body = declaration.body?.accept(IrElementToJsStatementTransformer(), functionContext) as? JsBlock ?: JsBlock()
|
||||
|
||||
val functionBody = if (isObjectConstructor) {
|
||||
@@ -56,7 +56,7 @@ fun translateFunction(declaration: IrFunction, name: JsName?, isObjectConstructo
|
||||
parameters.add(JsParameter(parameter))
|
||||
}
|
||||
|
||||
declaration.extensionReceiverParameter?.let { function.addParameter(functionContext.getNameForSymbol(it.symbol)) }
|
||||
declaration.extensionReceiverParameter?.let { function.addParameter(functionContext.getNameForValueDeclaration(it)) }
|
||||
functionParams.forEach { function.addParameter(it) }
|
||||
if (declaration.descriptor.isSuspend) {
|
||||
function.addParameter(context.currentScope.declareName(Namer.CONTINUATION))
|
||||
@@ -82,6 +82,7 @@ fun translateCallArguments(expression: IrMemberAccessExpression, context: JsGene
|
||||
|
||||
fun JsStatement.asBlock() = this as? JsBlock ?: JsBlock(this)
|
||||
|
||||
// TODO: Don't use implicit name conventions
|
||||
fun JsName.objectInstanceName() = "${ident}_instance"
|
||||
|
||||
fun defineProperty(receiver: JsExpression, name: String, value: () -> JsExpression): JsInvocation {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.utils
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsName
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsNameRef
|
||||
|
||||
interface IrNamer {
|
||||
fun getNameForConstructor(constructor: IrConstructor): JsName
|
||||
fun getNameForMemberFunction(function: IrSimpleFunction): JsName
|
||||
fun getNameForMemberField(field: IrField): JsName
|
||||
fun getNameForField(field: IrField): JsName
|
||||
fun getNameForValueDeclaration(declaration: IrValueDeclaration): JsName
|
||||
fun getNameForClass(klass: IrClass): JsName
|
||||
fun getNameForStaticFunction(function: IrSimpleFunction): JsName
|
||||
fun getNameForStaticDeclaration(declaration: IrDeclarationWithName): JsName
|
||||
fun getNameForProperty(property: IrProperty): JsName
|
||||
fun getRefForExternalClass(klass: IrClass): JsNameRef
|
||||
fun getNameForLoop(loop: IrLoop): String?
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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.utils
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsName
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsNameRef
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsRootScope
|
||||
|
||||
class IrNamerImpl(
|
||||
private val memberNameGenerator: LegacyMemberNameGenerator,
|
||||
private val newNameTables: NameTables,
|
||||
private val rootScope: JsRootScope // TODO: Don't use scopes
|
||||
) : IrNamer {
|
||||
|
||||
override fun getNameForStaticDeclaration(declaration: IrDeclarationWithName): JsName {
|
||||
val name = newNameTables.getNameForStaticDeclaration(declaration)
|
||||
return rootScope.declareName(name)
|
||||
}
|
||||
|
||||
override fun getNameForLoop(loop: IrLoop): String? =
|
||||
newNameTables.getNameForLoop(loop)
|
||||
|
||||
override fun getNameForConstructor(constructor: IrConstructor): JsName {
|
||||
return getNameForStaticDeclaration(constructor.parentAsClass)
|
||||
}
|
||||
|
||||
override fun getNameForMemberFunction(function: IrSimpleFunction): JsName {
|
||||
require(function.dispatchReceiverParameter != null)
|
||||
return memberNameGenerator.getNameForMemberFunction(function)
|
||||
}
|
||||
|
||||
override fun getNameForMemberField(field: IrField): JsName {
|
||||
require(!field.isStatic)
|
||||
return memberNameGenerator.getNameForMemberField(field)
|
||||
}
|
||||
|
||||
override fun getNameForField(field: IrField): JsName {
|
||||
return if (field.isStatic) {
|
||||
getNameForStaticDeclaration(field)
|
||||
} else {
|
||||
getNameForMemberField(field)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getNameForValueDeclaration(declaration: IrValueDeclaration): JsName =
|
||||
getNameForStaticDeclaration(declaration)
|
||||
|
||||
override fun getNameForClass(klass: IrClass): JsName =
|
||||
getNameForStaticDeclaration(klass)
|
||||
|
||||
override fun getNameForStaticFunction(function: IrSimpleFunction): JsName =
|
||||
getNameForStaticDeclaration(function)
|
||||
|
||||
override fun getNameForProperty(property: IrProperty): JsName {
|
||||
return rootScope.declareName(property.getJsNameOrKotlinName().asString())
|
||||
}
|
||||
|
||||
override fun getRefForExternalClass(klass: IrClass): JsNameRef {
|
||||
val parent = klass.parent
|
||||
if (klass.isCompanion)
|
||||
return getRefForExternalClass(parent as IrClass)
|
||||
|
||||
val currentClassName = klass.getJsNameOrKotlinName().identifier
|
||||
return when (parent) {
|
||||
is IrClass ->
|
||||
JsNameRef(currentClassName, getRefForExternalClass(parent))
|
||||
|
||||
is IrPackageFragment ->
|
||||
JsNameRef(currentClassName)
|
||||
|
||||
else ->
|
||||
error("Unsupported external class parent $parent")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,11 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.utils
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.serialization.fqNameSafe
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.fqNameSafe
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
||||
|
||||
|
||||
+17
-44
@@ -5,54 +5,27 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.utils
|
||||
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
|
||||
class JsGenerationContext {
|
||||
fun newDeclaration(scope: JsScope, func: IrFunction? = null): JsGenerationContext {
|
||||
return JsGenerationContext(this, if (func != null) JsBlock() else JsGlobalBlock(), scope, func)
|
||||
}
|
||||
|
||||
val currentBlock: JsBlock
|
||||
val currentScope: JsScope
|
||||
val currentFunction: IrFunction?
|
||||
val parent: JsGenerationContext?
|
||||
class JsGenerationContext(
|
||||
val parent: JsGenerationContext?,
|
||||
val currentBlock: JsBlock,
|
||||
val currentScope: JsScope,
|
||||
val currentFunction: IrFunction?,
|
||||
val staticContext: JsStaticContext
|
||||
private val program: JsProgram
|
||||
|
||||
constructor(rootScope: JsRootScope, backendContext: JsIrBackendContext) {
|
||||
|
||||
this.parent = null
|
||||
this.program = rootScope.program
|
||||
this.staticContext = JsStaticContext(rootScope, program.globalBlock, SimpleNameGenerator(), backendContext)
|
||||
this.currentScope = rootScope
|
||||
this.currentBlock = program.globalBlock
|
||||
this.currentFunction = null
|
||||
): IrNamer by staticContext {
|
||||
fun newDeclaration(scope: JsScope, func: IrFunction? = null): JsGenerationContext {
|
||||
return JsGenerationContext(
|
||||
parent = this,
|
||||
currentBlock = if (func != null) JsBlock() else JsGlobalBlock(),
|
||||
currentScope = scope,
|
||||
currentFunction = func,
|
||||
staticContext = staticContext
|
||||
)
|
||||
}
|
||||
|
||||
constructor(parent: JsGenerationContext, block: JsBlock, scope: JsScope, func: IrFunction?) {
|
||||
this.parent = parent
|
||||
this.program = parent.program
|
||||
this.staticContext = parent.staticContext
|
||||
this.currentBlock = block
|
||||
this.currentScope = scope
|
||||
this.currentFunction = func
|
||||
}
|
||||
|
||||
fun getNameForDeclaration(declaration: IrDeclaration): JsName =
|
||||
if (declaration is IrSymbolOwner)
|
||||
getNameForSymbol(declaration.symbol)
|
||||
else
|
||||
error("Unsupported")
|
||||
|
||||
fun getNameForSymbol(symbol: IrSymbol): JsName = staticContext.getNameForSymbol(symbol, this)
|
||||
fun getNameForType(type: IrType): JsName = staticContext.getNameForType(type, this)
|
||||
fun getNameForLoop(loop: IrLoop): JsName? = staticContext.getNameForLoop(loop, this)
|
||||
|
||||
val continuation
|
||||
get() = if (isCoroutineDoResume()) {
|
||||
JsThisRef()
|
||||
@@ -60,7 +33,7 @@ class JsGenerationContext {
|
||||
if (currentFunction!!.descriptor.isSuspend) {
|
||||
JsNameRef(currentScope.declareName(Namer.CONTINUATION))
|
||||
} else {
|
||||
getNameForSymbol(currentFunction.valueParameters.last().symbol).makeRef()
|
||||
getNameForValueDeclaration(currentFunction.valueParameters.last()).makeRef()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-11
@@ -8,9 +8,6 @@ package org.jetbrains.kotlin.ir.backend.js.utils
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIntrinsicTransformers
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsClassModel
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsGlobalBlock
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsName
|
||||
@@ -19,10 +16,10 @@ import org.jetbrains.kotlin.js.backend.ast.JsRootScope
|
||||
|
||||
class JsStaticContext(
|
||||
val rootScope: JsRootScope,
|
||||
private val globalBlock: JsGlobalBlock,
|
||||
private val nameGenerator: NameGenerator,
|
||||
val backendContext: JsIrBackendContext
|
||||
) {
|
||||
val backendContext: JsIrBackendContext,
|
||||
private val irNamer: IrNamer
|
||||
) : IrNamer by irNamer {
|
||||
|
||||
val intrinsics = JsIntrinsicTransformers(backendContext)
|
||||
// TODO: use IrSymbol instead of JsName
|
||||
val classModels = mutableMapOf<JsName, JsClassModel>()
|
||||
@@ -31,8 +28,4 @@ class JsStaticContext(
|
||||
.filterIsInstance<IrSimpleFunction>().single { it.name.asString() == "doResume" }.symbol
|
||||
|
||||
val initializerBlock = JsGlobalBlock()
|
||||
|
||||
fun getNameForSymbol(irSymbol: IrSymbol, context: JsGenerationContext) = nameGenerator.getNameForSymbol(irSymbol, context)
|
||||
fun getNameForType(type: IrType, context: JsGenerationContext) = nameGenerator.getNameForType(type, context)
|
||||
fun getNameForLoop(loop: IrLoop, context: JsGenerationContext) = nameGenerator.getNameForLoop(loop, context)
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.utils
|
||||
|
||||
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsName
|
||||
|
||||
interface NameGenerator {
|
||||
fun getNameForSymbol(symbol: IrSymbol, context: JsGenerationContext): JsName
|
||||
fun getNameForType(type: IrType, context: JsGenerationContext): JsName
|
||||
fun getNameForLoop(loop: IrLoop, context: JsGenerationContext): JsName?
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.utils
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ir.isTopLevel
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.ir.util.isInlined
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
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.isES5IdentifierStart
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
||||
|
||||
class NameTable<T>(
|
||||
val parent: NameTable<T>? = null,
|
||||
private val reserved: MutableSet<String> = mutableSetOf()
|
||||
) {
|
||||
var finished = false
|
||||
val names = mutableMapOf<T, String>()
|
||||
|
||||
private fun isReserved(name: String): Boolean {
|
||||
if (parent != null && parent.isReserved(name))
|
||||
return true
|
||||
return name in reserved
|
||||
}
|
||||
|
||||
fun declareStableName(declaration: T, name: String) {
|
||||
if (parent != null) assert(parent.finished)
|
||||
assert(!finished)
|
||||
names[declaration] = name
|
||||
reserved.add(name)
|
||||
}
|
||||
|
||||
fun declareFreshName(declaration: T, suggestedName: String) {
|
||||
val freshName = findFreshName(sanitizeName(suggestedName))
|
||||
declareStableName(declaration, freshName)
|
||||
}
|
||||
|
||||
private fun findFreshName(suggestedName: String): String {
|
||||
if (!isReserved(suggestedName))
|
||||
return suggestedName
|
||||
|
||||
var i = 0
|
||||
|
||||
fun freshName() =
|
||||
suggestedName + "_" + i
|
||||
|
||||
while (isReserved(freshName())) {
|
||||
i++
|
||||
}
|
||||
return freshName()
|
||||
}
|
||||
}
|
||||
|
||||
fun NameTable<IrDeclaration>.dump(): String =
|
||||
"Names: \n" + names.toList().joinToString("\n") { (declaration, name) ->
|
||||
val decl: FqName? = (declaration as IrDeclarationWithName).fqNameWhenAvailable
|
||||
val declRef = decl ?: declaration
|
||||
"--- $declRef => $name"
|
||||
}
|
||||
|
||||
|
||||
class NameTables(packages: List<IrPackageFragment>) {
|
||||
private val globalNames: NameTable<IrDeclaration>
|
||||
private val memberNames: NameTable<IrDeclaration>
|
||||
private val localNames = mutableMapOf<IrDeclaration, NameTable<IrDeclaration>>()
|
||||
private val loopNames = mutableMapOf<IrLoop, String>()
|
||||
|
||||
init {
|
||||
val stableNamesCollector = StableNamesCollector()
|
||||
packages.forEach { it.acceptChildrenVoid(stableNamesCollector) }
|
||||
|
||||
globalNames = NameTable(reserved = stableNamesCollector.staticNames)
|
||||
memberNames = NameTable(reserved = stableNamesCollector.memberNames)
|
||||
|
||||
for (p in packages) {
|
||||
for (declaration in p.declarations) {
|
||||
generateNamesForTopLevelDecl(declaration)
|
||||
}
|
||||
}
|
||||
|
||||
globalNames.finished = true
|
||||
|
||||
for (p in packages) {
|
||||
for (declaration in p.declarations) {
|
||||
if (declaration.isEffectivelyExternal())
|
||||
continue
|
||||
|
||||
val localNameGenerator = LocalNameGenerator(declaration)
|
||||
|
||||
if (declaration is IrClass) {
|
||||
declaration.thisReceiver!!.acceptVoid(localNameGenerator)
|
||||
for (memberDecl in declaration.declarations) {
|
||||
memberDecl.acceptChildrenVoid(LocalNameGenerator(memberDecl))
|
||||
}
|
||||
} else {
|
||||
declaration.acceptChildrenVoid(localNameGenerator)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun dump(): String {
|
||||
val local = localNames.toList().joinToString("\n") { (decl, table) ->
|
||||
val declRef = (decl as? IrDeclarationWithName)?.fqNameWhenAvailable ?: decl
|
||||
"\nLocal names for $declRef:\n${table.dump()}\n"
|
||||
}
|
||||
return "Global names:\n${globalNames.dump()}" +
|
||||
"\nMember names:\n${memberNames.dump()}" +
|
||||
"\nLocal names:\n$local\n"
|
||||
}
|
||||
|
||||
fun getNameForStaticDeclaration(declaration: IrDeclarationWithName): String {
|
||||
val global: String? = globalNames.names[declaration]
|
||||
if (global != null) return global
|
||||
|
||||
if (declaration is IrTypeParameter) {
|
||||
// TODO: Fix type parameters
|
||||
return declaration.name.identifier
|
||||
}
|
||||
|
||||
var parent: IrDeclarationParent = declaration.parent
|
||||
while (parent is IrDeclaration) {
|
||||
val parentLocalNames = localNames[parent]
|
||||
if (parentLocalNames != null) {
|
||||
val localName = parentLocalNames.names[declaration]
|
||||
if (localName != null)
|
||||
return localName
|
||||
}
|
||||
parent = parent.parent
|
||||
}
|
||||
|
||||
error("Can't find name for declaration $declaration")
|
||||
}
|
||||
|
||||
|
||||
private fun generateNamesForTopLevelDecl(declaration: IrDeclaration) {
|
||||
when {
|
||||
declaration !is IrDeclarationWithName ->
|
||||
return
|
||||
|
||||
declaration.isEffectivelyExternal() ->
|
||||
globalNames.declareStableName(declaration, declaration.getJsNameOrKotlinName().identifier)
|
||||
|
||||
else ->
|
||||
globalNames.declareFreshName(declaration, declaration.name.asString())
|
||||
}
|
||||
}
|
||||
|
||||
inner class LocalNameGenerator(parentDeclaration: IrDeclaration) : IrElementVisitorVoid {
|
||||
val table = NameTable(globalNames)
|
||||
|
||||
init {
|
||||
localNames[parentDeclaration] = table
|
||||
}
|
||||
|
||||
private val localLoopNames = NameTable<IrLoop>()
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitValueParameter(declaration: IrValueParameter) {
|
||||
val parentFunction = declaration.parent as? IrFunction
|
||||
if ((declaration.origin == IrDeclarationOrigin.INSTANCE_RECEIVER && declaration.name.isSpecial) ||
|
||||
(parentFunction != null && declaration == parentFunction.dispatchReceiverParameter)
|
||||
)
|
||||
table.declareStableName(declaration, Namer.IMPLICIT_RECEIVER_NAME)
|
||||
else
|
||||
super.visitValueParameter(declaration)
|
||||
}
|
||||
|
||||
override fun visitDeclaration(declaration: IrDeclaration) {
|
||||
if (declaration is IrDeclarationWithName && declaration is IrSymbolOwner) {
|
||||
table.declareFreshName(declaration, declaration.name.asString())
|
||||
}
|
||||
super.visitDeclaration(declaration)
|
||||
}
|
||||
|
||||
override fun visitLoop(loop: IrLoop) {
|
||||
val label = loop.label
|
||||
if (label != null) {
|
||||
localLoopNames.declareFreshName(loop, label)
|
||||
loopNames[loop] = localLoopNames.names[loop]!!
|
||||
}
|
||||
super.visitLoop(loop)
|
||||
}
|
||||
}
|
||||
|
||||
fun getNameForLoop(loop: IrLoop): String? =
|
||||
if (loop.label == null)
|
||||
null
|
||||
else
|
||||
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.isEqualsInheritedFromAny()) {
|
||||
return scope.declareName("equals")
|
||||
}
|
||||
|
||||
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 types because
|
||||
// they are binary incompatible with supertypes.
|
||||
if (it.isInlined()) {
|
||||
nameBuilder.append("_ret$${it.asString()}")
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Check reserved names
|
||||
|
||||
return scope.declareName(sanitizeName(nameBuilder.toString()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun sanitizeName(name: String): String {
|
||||
if (name.isEmpty()) return "_"
|
||||
|
||||
val first = name.first().let { if (it.isES5IdentifierStart()) it else '_' }
|
||||
return first.toString() + name.drop(1).map { if (it.isES5IdentifierPart()) it else '_' }.joinToString("")
|
||||
}
|
||||
@@ -9,57 +9,20 @@ import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsNameRef
|
||||
|
||||
object Namer {
|
||||
val KOTLIN_NAME = KotlinLanguage.NAME
|
||||
val KOTLIN_LOWER_NAME = KOTLIN_NAME.toLowerCase()
|
||||
|
||||
// val EQUALS_METHOD_NAME = getStableMangledNameForDescriptor(JsPlatform.INSTANCE.getBuiltIns().getAny(), "equals")
|
||||
// val COMPARE_TO_METHOD_NAME = getStableMangledNameForDescriptor(JsPlatform.INSTANCE.getBuiltIns().getComparable(), "compareTo")
|
||||
val LONG_FROM_NUMBER = "fromNumber"
|
||||
val LONG_TO_NUMBER = "toNumber"
|
||||
val LONG_FROM_INT = "fromInt"
|
||||
val LONG_ZERO = "ZERO"
|
||||
val LONG_ONE = "ONE"
|
||||
val LONG_NEG_ONE = "NEG_ONE"
|
||||
val LONG_MAX_VALUE = "MAX_VALUE"
|
||||
val LONG_MIN_VALUE = "MIN_VALUE"
|
||||
val PRIMITIVE_COMPARE_TO = "primitiveCompareTo"
|
||||
val IS_CHAR = "isChar"
|
||||
val IS_NUMBER = "isNumber"
|
||||
val IS_CHAR_SEQUENCE = "isCharSequence"
|
||||
val GET_KCLASS = "getKClass"
|
||||
val GET_KCLASS_FROM_EXPRESSION = "getKClassFromExpression"
|
||||
|
||||
val CALLEE_NAME = "\$fun"
|
||||
|
||||
val CALL_FUNCTION = "call"
|
||||
val APPLY_FUNCTION = "apply"
|
||||
val BIND_FUNCTION = "bind"
|
||||
|
||||
val SLICE_FUNCTION = "slice"
|
||||
val CONCAT_FUNCTION = "concat"
|
||||
|
||||
val OUTER_NAME = "\$outer"
|
||||
val UNREACHABLE_NAME = "\$unreachable"
|
||||
|
||||
val DELEGATE = "\$delegate"
|
||||
|
||||
val ROOT_PACKAGE = "_"
|
||||
|
||||
val EXTENSION_RECEIVER_NAME = "\$receiver"
|
||||
val IMPLICIT_RECEIVER_NAME = "this"
|
||||
val ANOTHER_THIS_PARAMETER_NAME = "\$this"
|
||||
|
||||
val THROW_CLASS_CAST_EXCEPTION_FUN_NAME = "throwCCE"
|
||||
val THROW_ILLEGAL_STATE_EXCEPTION_FUN_NAME = "throwISE"
|
||||
val THROW_UNINITIALIZED_PROPERTY_ACCESS_EXCEPTION = "throwUPAE"
|
||||
val NULL_CHECK_INTRINSIC_NAME = "ensureNotNull"
|
||||
val PROTOTYPE_NAME = "prototype"
|
||||
val CONSTRUCTOR_NAME = "constructor"
|
||||
val CAPTURED_VAR_FIELD = "v"
|
||||
|
||||
val IS_ARRAY_FUN_REF = JsNameRef("isArray", "Array")
|
||||
val DEFINE_INLINE_FUNCTION = "defineInlineFunction"
|
||||
val DEFAULT_PARAMETER_IMPLEMENTOR_SUFFIX = "\$default"
|
||||
|
||||
val CONTINUATION = "\$cont"
|
||||
|
||||
@@ -68,35 +31,14 @@ object Namer {
|
||||
val JS_OBJECT = JsNameRef("Object")
|
||||
val JS_OBJECT_CREATE_FUNCTION = JsNameRef("create", JS_OBJECT)
|
||||
|
||||
val LOCAL_MODULE_PREFIX = "\$module\$"
|
||||
val METADATA = "\$metadata\$"
|
||||
val METADATA_INTERFACES = "interfaces"
|
||||
val METADATA_SIMPLE_NAME = "simpleName"
|
||||
val METADATA_CLASS_KIND = "kind"
|
||||
val CLASS_KIND_ENUM = "Kind"
|
||||
val CLASS_KIND_CLASS = "CLASS"
|
||||
val CLASS_KIND_INTERFACE = "INTERFACE"
|
||||
val CLASS_KIND_OBJECT = "OBJECT"
|
||||
|
||||
val OBJECT_INSTANCE_VAR_SUFFIX = "_instance"
|
||||
val OBJECT_INSTANCE_FUNCTION_SUFFIX = "_getInstance"
|
||||
|
||||
val ENUM_NAME_FIELD = "name\$"
|
||||
val ENUM_ORDINAL_FIELD = "ordinal\$"
|
||||
|
||||
val IMPORTS_FOR_INLINE_PROPERTY = "\$\$importsForInline\$\$"
|
||||
|
||||
val GETTER_PREFIX = "get_"
|
||||
val SETTER_PREFIX = "set_"
|
||||
|
||||
val KCALLABLE_GET_NAME = "<get-name>"
|
||||
val KCALLABLE_NAME = "callableName"
|
||||
val KPROPERTY_GET = "get"
|
||||
val KPROPERTY_SET = "set"
|
||||
val KCALLABLE_CACHE_SUFFIX = "\$cache"
|
||||
|
||||
val SETTER_ARGUMENT = "\$setValue"
|
||||
|
||||
val THIS_SPECIAL_NAME = "<this>"
|
||||
val SET_SPECIAL_NAME = "<set-?>"
|
||||
}
|
||||
-228
@@ -1,228 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.utils
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ir.isTopLevel
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.ir.util.isInlined
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsName
|
||||
import org.jetbrains.kotlin.js.naming.isES5IdentifierPart
|
||||
import org.jetbrains.kotlin.js.naming.isES5IdentifierStart
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
||||
|
||||
// TODO: this class has to be reimplemented soon
|
||||
class SimpleNameGenerator : NameGenerator {
|
||||
|
||||
private val nameCache = mutableMapOf<IrDeclaration, JsName>()
|
||||
private val loopCache = mutableMapOf<IrLoop, JsName>()
|
||||
|
||||
override fun getNameForSymbol(symbol: IrSymbol, context: JsGenerationContext): JsName =
|
||||
getNameForDeclaration(symbol.owner as IrDeclarationWithName, context)
|
||||
|
||||
override fun getNameForLoop(loop: IrLoop, context: JsGenerationContext): JsName? = loop.label?.let {
|
||||
loopCache.getOrPut(loop) { context.currentScope.declareFreshName(sanitizeName(loop.label!!)) }
|
||||
}
|
||||
|
||||
override fun getNameForType(type: IrType, context: JsGenerationContext) =
|
||||
getNameForDeclaration(type.classifierOrFail.owner as IrDeclarationWithName, context)
|
||||
|
||||
private fun getNameForDeclaration(declaration: IrDeclarationWithName, context: JsGenerationContext): JsName {
|
||||
return nameCache.getOrPut(declaration) { getNewNameForDeclaration(declaration, context) }
|
||||
}
|
||||
|
||||
private fun getNewNameForDeclaration(declaration: IrDeclarationWithName, context: JsGenerationContext): JsName {
|
||||
var nameDeclarator: (String) -> JsName = context.currentScope::declareName
|
||||
|
||||
val declarationName = declaration.getJsNameOrKotlinName().asString()
|
||||
|
||||
if (declaration is IrProperty) {
|
||||
return context.currentScope.declareName(declaration.getJsNameOrKotlinName().asString())
|
||||
}
|
||||
|
||||
if (declaration is IrSimpleFunction && declaration.origin == JsLoweredDeclarationOrigin.BRIDGE_TO_EXTERNAL_FUNCTION) {
|
||||
return nameDeclarator(declarationName)
|
||||
}
|
||||
|
||||
if (declaration.isEffectivelyExternal()) {
|
||||
if (declaration is IrConstructor)
|
||||
return getNameForDeclaration(declaration.parentAsClass, context)
|
||||
|
||||
if (declaration is IrClass && declaration.parent is IrClass) {
|
||||
val parentName = getNameForDeclaration(declaration.parentAsClass, context)
|
||||
if (declaration.isCompanion) {
|
||||
// External companions are class references
|
||||
return parentName
|
||||
}
|
||||
return context.currentScope.declareFreshName(parentName.ident + "$" + declarationName)
|
||||
}
|
||||
return nameDeclarator(declarationName)
|
||||
}
|
||||
|
||||
val jsName = declaration.getJsName()
|
||||
if (jsName != null) {
|
||||
return context.currentScope.declareName(jsName)
|
||||
}
|
||||
|
||||
val nameBuilder = StringBuilder()
|
||||
when (declaration) {
|
||||
is IrValueParameter -> {
|
||||
if ((context.currentFunction is IrConstructor && declaration.origin == IrDeclarationOrigin.INSTANCE_RECEIVER && declaration.name.isSpecial) ||
|
||||
declaration == context.currentFunction?.dispatchReceiverParameter
|
||||
)
|
||||
nameBuilder.append(Namer.IMPLICIT_RECEIVER_NAME)
|
||||
else if (declaration == context.currentFunction?.extensionReceiverParameter) {
|
||||
nameBuilder.append(Namer.EXTENSION_RECEIVER_NAME)
|
||||
} else {
|
||||
val declaredName = declarationName
|
||||
nameBuilder.append(declaredName)
|
||||
if (declaredName.startsWith("\$")) {
|
||||
nameBuilder.append('.')
|
||||
nameBuilder.append(declaration.index)
|
||||
}
|
||||
nameDeclarator = context.currentScope::declareFreshName
|
||||
}
|
||||
}
|
||||
is IrField -> {
|
||||
nameBuilder.append(declarationName)
|
||||
if (declaration.isTopLevel) {
|
||||
nameDeclarator = context.staticContext.rootScope::declareFreshName
|
||||
} else {
|
||||
nameBuilder.append('.')
|
||||
nameBuilder.append(getNameForDeclaration(declaration.parent as IrDeclarationWithName, context))
|
||||
if (declaration.visibility == Visibilities.PRIVATE) nameDeclarator = context.currentScope::declareFreshName
|
||||
}
|
||||
}
|
||||
is IrClass -> {
|
||||
if (declaration.isCompanion) {
|
||||
nameBuilder.append(getNameForDeclaration(declaration.parent as IrDeclarationWithName, context))
|
||||
nameBuilder.append('.')
|
||||
}
|
||||
|
||||
nameBuilder.append(declarationName)
|
||||
|
||||
(declaration.parent as? IrClass)?.let {
|
||||
nameBuilder.append("$")
|
||||
nameBuilder.append(getNameForDeclaration(it, context))
|
||||
}
|
||||
|
||||
|
||||
nameDeclarator = context.staticContext.rootScope::declareFreshName
|
||||
if (declaration.kind == ClassKind.OBJECT || declaration.name.isSpecial || declaration.visibility == Visibilities.LOCAL) {
|
||||
val parent = declaration.parent
|
||||
when (parent) {
|
||||
is IrDeclarationWithName -> nameBuilder.append(getNameForDeclaration(parent, context))
|
||||
is IrPackageFragment -> nameBuilder.append(parent.fqName.asString())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove asap `NameGenerator` is implemented
|
||||
(declaration.parent as? IrPackageFragment)?.let {
|
||||
if (declaration.isInline && it.fqName.asString() != "kotlin") {
|
||||
nameBuilder.append("_FIX")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
is IrConstructor -> {
|
||||
nameBuilder.append(getNameForDeclaration(declaration.parent as IrClass, context))
|
||||
}
|
||||
is IrVariable -> {
|
||||
nameBuilder.append(declaration.name.identifier)
|
||||
nameDeclarator = context.currentScope::declareFreshName
|
||||
}
|
||||
is IrSimpleFunction -> {
|
||||
|
||||
// Handle names for special functions
|
||||
if (declaration.isEqualsInheritedFromAny()) {
|
||||
return context.staticContext.rootScope.declareName("equals")
|
||||
}
|
||||
|
||||
if (declaration.isStaticMethodOfClass) {
|
||||
nameBuilder.append(getNameForDeclaration(declaration.parent as IrClass, context))
|
||||
nameBuilder.append('.')
|
||||
}
|
||||
if (declaration.dispatchReceiverParameter == null) {
|
||||
nameDeclarator = context.staticContext.rootScope::declareFreshName
|
||||
}
|
||||
|
||||
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 types because
|
||||
// they are binary incompatible with supertypes.
|
||||
if (it.isInlined()) {
|
||||
nameBuilder.append("_ret$${it.asString()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nameBuilder.toString() in RESERVED_IDENTIFIERS) {
|
||||
nameBuilder.append(0)
|
||||
nameDeclarator = context.currentScope::declareFreshName
|
||||
}
|
||||
|
||||
return nameDeclarator(sanitizeName(nameBuilder.toString()))
|
||||
}
|
||||
}
|
||||
|
||||
private val RESERVED_IDENTIFIERS = setOf(
|
||||
// keywords
|
||||
"await", "break", "case", "catch", "continue", "debugger", "default", "delete", "do", "else", "finally", "for", "function", "if",
|
||||
"in", "instanceof", "new", "return", "switch", "throw", "try", "typeof", "var", "void", "while", "with",
|
||||
|
||||
// future reserved words
|
||||
"class", "const", "enum", "export", "extends", "import", "super",
|
||||
|
||||
// as future reserved words in strict mode
|
||||
"implements", "interface", "let", "package", "private", "protected", "public", "static", "yield",
|
||||
|
||||
// additional reserved words
|
||||
// "null", "true", "false",
|
||||
|
||||
// disallowed as variable names in strict mode
|
||||
"eval", "arguments",
|
||||
|
||||
// global identifiers usually declared in a typical JS interpreter
|
||||
"NaN", "isNaN", "Infinity", "undefined",
|
||||
|
||||
"Error", "Object", "Number",
|
||||
|
||||
// "Math", "String", "Boolean", "Date", "Array", "RegExp", "JSON",
|
||||
|
||||
// global identifiers usually declared in know environments (node.js, browser, require.js, WebWorkers, etc)
|
||||
// "require", "define", "module", "window", "self",
|
||||
|
||||
// the special Kotlin object
|
||||
"Kotlin"
|
||||
)
|
||||
|
||||
|
||||
fun sanitizeName(name: String): String {
|
||||
if (name.isEmpty()) return "_"
|
||||
|
||||
val first = name.first().let { if (it.isES5IdentifierStart()) it else '_' }
|
||||
return first.toString() + name.drop(1).map { if (it.isES5IdentifierPart()) it else '_' }.joinToString("")
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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.utils
|
||||
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName
|
||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.ir.util.isPropertyAccessor
|
||||
import org.jetbrains.kotlin.ir.util.isPropertyField
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
class StableNamesCollector : IrElementVisitorVoid {
|
||||
val staticNames = mutableSetOf<String>()
|
||||
val memberNames = mutableSetOf<String>()
|
||||
|
||||
init {
|
||||
staticNames.addAll(RESERVED_IDENTIFIERS)
|
||||
staticNames.add(Namer.IMPLICIT_RECEIVER_NAME)
|
||||
}
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitDeclaration(declaration: IrDeclaration) {
|
||||
super.visitDeclaration(declaration)
|
||||
|
||||
if (declaration !is IrDeclarationWithName)
|
||||
return
|
||||
|
||||
val scope =
|
||||
if (declaration.hasStaticDispatch())
|
||||
staticNames
|
||||
else
|
||||
memberNames
|
||||
|
||||
val stableName =
|
||||
if (declaration.isEffectivelyExternal())
|
||||
stableNameForExternalDeclaration(declaration)
|
||||
else
|
||||
stableNameForNonExternalDeclaration(declaration)
|
||||
|
||||
scope.addIfNotNull(stableName)
|
||||
}
|
||||
|
||||
private fun stableNameForNonExternalDeclaration(declaration: IrDeclarationWithName): String? =
|
||||
declaration.getJsName()
|
||||
|
||||
private fun stableNameForExternalDeclaration(declaration: IrDeclarationWithName): String? {
|
||||
if (declaration.isPropertyAccessor ||
|
||||
declaration.isPropertyField ||
|
||||
declaration is IrConstructor
|
||||
) {
|
||||
return null
|
||||
}
|
||||
|
||||
val importedFromModuleOnly =
|
||||
declaration.getJsModule() != null && !declaration.isJsNonModule()
|
||||
|
||||
val jsName = declaration.getJsName()
|
||||
val jsQualifier = declaration.getJsQualifier()
|
||||
|
||||
return when {
|
||||
importedFromModuleOnly ->
|
||||
null
|
||||
|
||||
jsQualifier != null ->
|
||||
jsQualifier.split('1')[0]
|
||||
|
||||
jsName != null ->
|
||||
jsName
|
||||
|
||||
else ->
|
||||
declaration.name.identifier
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val RESERVED_IDENTIFIERS = setOf(
|
||||
// keywords
|
||||
"await", "break", "case", "catch", "continue", "debugger", "default", "delete", "do", "else", "finally", "for", "function", "if",
|
||||
"in", "instanceof", "new", "return", "switch", "throw", "try", "typeof", "var", "void", "while", "with",
|
||||
|
||||
// future reserved words
|
||||
"class", "const", "enum", "export", "extends", "import", "super",
|
||||
|
||||
// as future reserved words in strict mode
|
||||
"implements", "interface", "let", "package", "private", "protected", "public", "static", "yield",
|
||||
|
||||
// additional reserved words
|
||||
"null", "true", "false",
|
||||
|
||||
// disallowed as variable names in strict mode
|
||||
"eval", "arguments",
|
||||
|
||||
// global identifiers usually declared in a typical JS interpreter
|
||||
"NaN", "isNaN", "Infinity", "undefined",
|
||||
|
||||
"Error", "Object", "Number",
|
||||
|
||||
"Math", "String", "Boolean", "Date", "Array", "RegExp", "JSON",
|
||||
|
||||
// global identifiers usually declared in know environments (node.js, browser, require.js, WebWorkers, etc)
|
||||
"require", "define", "module", "window", "self"
|
||||
)
|
||||
@@ -6,8 +6,9 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js.utils
|
||||
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.types.isNullableAny
|
||||
import org.jetbrains.kotlin.ir.util.isTopLevelDeclaration
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
fun TODO(element: IrElement): Nothing = TODO(element::class.java.simpleName + " is not supported yet here")
|
||||
@@ -17,3 +18,10 @@ fun IrFunction.isEqualsInheritedFromAny() =
|
||||
dispatchReceiverParameter != null &&
|
||||
valueParameters.size == 1 &&
|
||||
valueParameters[0].type.isNullableAny()
|
||||
|
||||
fun IrDeclaration.hasStaticDispatch() = when (this) {
|
||||
is IrSimpleFunction -> dispatchReceiverParameter == null
|
||||
is IrProperty -> isTopLevelDeclaration
|
||||
is IrField -> isStatic
|
||||
else -> true
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1288
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// FILE: foo.kt
|
||||
|
||||
package foo
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1294
|
||||
|
||||
@JsName("AA") object A {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1285
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
package foo
|
||||
|
||||
external class A {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
// EXPECTED_REACHABLE_NODES: 1819
|
||||
// MODULE: lib1
|
||||
// FILE: lib1.kt
|
||||
@@ -43,8 +43,10 @@ fun box(): String {
|
||||
val b = Derived2()
|
||||
if (b.bar() != "B.foo") return "fail2: ${b.bar()}"
|
||||
|
||||
checkJsNames("foo", a)
|
||||
checkJsNames("foo", b)
|
||||
if (testUtils.isLegacyBackend()) {
|
||||
checkJsNames("foo", a)
|
||||
checkJsNames("foo", b)
|
||||
}
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1805
|
||||
// MODULE: lib
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1284
|
||||
package foo
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1282
|
||||
package test
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1282
|
||||
package test
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1285
|
||||
// MODULE: lib
|
||||
// FILE: lib.kt
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1221
|
||||
external class A
|
||||
|
||||
|
||||
@@ -19,11 +19,11 @@ internal interface InternalMap<K, V> : MutableIterable<MutableMap.MutableEntry<K
|
||||
fun clear(): Unit
|
||||
|
||||
fun createJsMap(): dynamic {
|
||||
val result = js("Object.create(null)")
|
||||
val newJsMap = js("Object.create(null)")
|
||||
// force to switch object representation to dictionary mode
|
||||
// Using js-function due to JS_IR limitations
|
||||
js("result[\"foo\"] = 1")
|
||||
js("delete result[\"foo\"]")
|
||||
return result
|
||||
js("newJsMap[\"foo\"] = 1")
|
||||
js("delete newJsMap[\"foo\"]")
|
||||
return newJsMap
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user