[K/JS] Use only single variant of default arguments function wrapper for exported and not-exported functions
This commit is contained in:
+209
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
abstract class DefaultArgumentFunctionFactory(open val context: CommonBackendContext) {
|
||||
protected fun IrFunction.generateDefaultArgumentsFunctionName() =
|
||||
Name.identifier("${name}\$default")
|
||||
|
||||
protected abstract fun IrFunction.generateDefaultArgumentStubFrom(original: IrFunction, useConstructorMarker: Boolean)
|
||||
|
||||
protected fun IrFunction.copyAttributesFrom(original: IrFunction) {
|
||||
(this as? IrAttributeContainer)?.copyAttributes(original as? IrAttributeContainer)
|
||||
}
|
||||
|
||||
protected fun IrFunction.copyReturnTypeFrom(original: IrFunction) {
|
||||
returnType = original.returnType.remapTypeParameters(original.classIfConstructor, classIfConstructor)
|
||||
}
|
||||
|
||||
protected fun IrFunction.copyReceiversFrom(original: IrFunction) {
|
||||
dispatchReceiverParameter = original.dispatchReceiverParameter?.copyTo(this)
|
||||
extensionReceiverParameter = original.extensionReceiverParameter?.copyTo(this)
|
||||
contextReceiverParametersCount = original.contextReceiverParametersCount
|
||||
}
|
||||
|
||||
protected fun IrFunction.copyValueParametersFrom(original: IrFunction, wrapWithNullable: Boolean = true) {
|
||||
valueParameters = original.valueParameters.map {
|
||||
val newType = it.type.remapTypeParameters(original.classIfConstructor, classIfConstructor)
|
||||
val makeNullable = wrapWithNullable && it.defaultValue != null &&
|
||||
(context.ir.unfoldInlineClassType(it.type) ?: it.type) !in context.irBuiltIns.primitiveIrTypes
|
||||
it.copyTo(
|
||||
this,
|
||||
type = if (makeNullable) newType.makeNullable() else newType,
|
||||
defaultValue = if (it.defaultValue != null) {
|
||||
original.factory.createExpressionBody(
|
||||
IrErrorExpressionImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
it.type,
|
||||
"Default Stub"
|
||||
)
|
||||
)
|
||||
} else null,
|
||||
isAssignable = it.defaultValue != null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun findBaseFunctionWithDefaultArgumentsFor(
|
||||
declaration: IrFunction,
|
||||
skipInlineMethods: Boolean,
|
||||
skipExternalMethods: Boolean
|
||||
): IrFunction? {
|
||||
val visited = mutableSetOf<IrFunction>()
|
||||
|
||||
fun IrFunction.dfsImpl(): IrFunction? {
|
||||
visited += this
|
||||
|
||||
if (isInline && skipInlineMethods) return null
|
||||
if (skipExternalMethods && isExternalOrInheritedFromExternal()) return null
|
||||
|
||||
if (this is IrSimpleFunction) {
|
||||
overriddenSymbols.forEach { overridden ->
|
||||
val base = overridden.owner
|
||||
if (base !in visited) base.dfsImpl()?.let { return it }
|
||||
}
|
||||
}
|
||||
|
||||
if (valueParameters.any { it.defaultValue != null }) return this
|
||||
|
||||
return null
|
||||
}
|
||||
return declaration.dfsImpl()
|
||||
}
|
||||
|
||||
|
||||
fun generateDefaultsFunction(
|
||||
declaration: IrFunction,
|
||||
skipInlineMethods: Boolean,
|
||||
skipExternalMethods: Boolean,
|
||||
forceSetOverrideSymbols: Boolean,
|
||||
visibility: DescriptorVisibility,
|
||||
useConstructorMarker: Boolean,
|
||||
copiedAnnotations: List<IrConstructorCall>,
|
||||
): IrFunction? {
|
||||
if (skipInlineMethods && declaration.isInline) return null
|
||||
if (skipExternalMethods && declaration.isExternalOrInheritedFromExternal()) return null
|
||||
if (context.mapping.defaultArgumentsOriginalFunction[declaration] != null) return null
|
||||
context.mapping.defaultArgumentsDispatchFunction[declaration]?.let { return it }
|
||||
if (declaration is IrSimpleFunction) {
|
||||
// If this is an override of a function with default arguments, produce a fake override of a default stub.
|
||||
if (declaration.overriddenSymbols.any {
|
||||
findBaseFunctionWithDefaultArgumentsFor(
|
||||
it.owner,
|
||||
skipInlineMethods,
|
||||
skipExternalMethods
|
||||
) != null
|
||||
})
|
||||
return generateDefaultsFunctionImpl(
|
||||
declaration,
|
||||
IrDeclarationOrigin.FAKE_OVERRIDE,
|
||||
visibility,
|
||||
copiedAnnotations,
|
||||
true,
|
||||
useConstructorMarker,
|
||||
).also { defaultsFunction ->
|
||||
context.mapping.defaultArgumentsDispatchFunction[declaration] = defaultsFunction
|
||||
context.mapping.defaultArgumentsOriginalFunction[defaultsFunction] = declaration
|
||||
|
||||
if (forceSetOverrideSymbols) {
|
||||
(defaultsFunction as IrSimpleFunction).overriddenSymbols += declaration.overriddenSymbols.mapNotNull {
|
||||
generateDefaultsFunction(
|
||||
it.owner,
|
||||
skipInlineMethods,
|
||||
skipExternalMethods,
|
||||
forceSetOverrideSymbols,
|
||||
visibility,
|
||||
useConstructorMarker,
|
||||
it.owner.copyAnnotations(),
|
||||
)?.symbol as IrSimpleFunctionSymbol?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Note: this is intentionally done *after* checking for overrides. While normally `override fun`s
|
||||
// have no default parameters, there is an exception in case of interface delegation:
|
||||
// interface I {
|
||||
// fun f(x: Int = 1)
|
||||
// }
|
||||
// class C(val y: I) : I by y {
|
||||
// // implicit `override fun f(x: Int) = y.f(x)` has a default value for `x`
|
||||
// }
|
||||
// Since this bug causes the metadata serializer to write the "has default value" flag into compiled
|
||||
// binaries, it's way too late to fix it. Hence the workaround.
|
||||
if (declaration.valueParameters.any { it.defaultValue != null }) {
|
||||
return generateDefaultsFunctionImpl(
|
||||
declaration,
|
||||
IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER,
|
||||
visibility,
|
||||
copiedAnnotations,
|
||||
false,
|
||||
useConstructorMarker,
|
||||
).also {
|
||||
context.mapping.defaultArgumentsDispatchFunction[declaration] = it
|
||||
context.mapping.defaultArgumentsOriginalFunction[it] = declaration
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
private fun generateDefaultsFunctionImpl(
|
||||
declaration: IrFunction,
|
||||
newOrigin: IrDeclarationOrigin,
|
||||
newVisibility: DescriptorVisibility,
|
||||
copiedAnnotations: List<IrConstructorCall>,
|
||||
isFakeOverride: Boolean,
|
||||
useConstructorMarker: Boolean,
|
||||
): IrFunction {
|
||||
val newFunction = when (declaration) {
|
||||
is IrConstructor ->
|
||||
declaration.factory.buildConstructor {
|
||||
updateFrom(declaration)
|
||||
origin = newOrigin
|
||||
isExternal = false
|
||||
isPrimary = false
|
||||
isExpect = false
|
||||
visibility = newVisibility
|
||||
}
|
||||
|
||||
is IrSimpleFunction ->
|
||||
declaration.factory.buildFun {
|
||||
updateFrom(declaration)
|
||||
name = declaration.generateDefaultArgumentsFunctionName()
|
||||
origin = newOrigin
|
||||
this.isFakeOverride = isFakeOverride
|
||||
modality = Modality.FINAL
|
||||
isExternal = false
|
||||
isTailrec = false
|
||||
visibility = newVisibility
|
||||
}
|
||||
|
||||
else -> throw IllegalStateException("Unknown function type")
|
||||
}
|
||||
|
||||
return newFunction.apply {
|
||||
parent = declaration.parent
|
||||
generateDefaultArgumentStubFrom(declaration, useConstructorMarker)
|
||||
// TODO some annotations are needed (e.g. @JvmStatic), others need different values (e.g. @JvmName), the rest are redundant.
|
||||
annotations += copiedAnnotations
|
||||
}
|
||||
}
|
||||
}
|
||||
+88
-193
@@ -41,7 +41,8 @@ open class DefaultArgumentStubGenerator(
|
||||
open val context: CommonBackendContext,
|
||||
private val skipInlineMethods: Boolean = true,
|
||||
private val skipExternalMethods: Boolean = false,
|
||||
private val forceSetOverrideSymbols: Boolean = true
|
||||
private val forceSetOverrideSymbols: Boolean = true,
|
||||
private val factory: DefaultArgumentFunctionFactory = MaskedDefaultArgumentFunctionFactory(context)
|
||||
) : DeclarationTransformer {
|
||||
override val withLocalDeclarations: Boolean get() = true
|
||||
|
||||
@@ -55,34 +56,21 @@ open class DefaultArgumentStubGenerator(
|
||||
|
||||
protected open fun IrFunction.resolveAnnotations(): List<IrConstructorCall> = copyAnnotations()
|
||||
|
||||
private fun lower(irFunction: IrFunction): List<IrFunction>? {
|
||||
val newIrFunction =
|
||||
irFunction.generateDefaultsFunction(
|
||||
context,
|
||||
skipInlineMethods,
|
||||
skipExternalMethods,
|
||||
forceSetOverrideSymbols,
|
||||
defaultArgumentStubVisibility(irFunction),
|
||||
useConstructorMarker(irFunction),
|
||||
irFunction.resolveAnnotations()
|
||||
) ?: return null
|
||||
if (newIrFunction.isFakeOverride) {
|
||||
return listOf(irFunction, newIrFunction)
|
||||
}
|
||||
|
||||
log { "$irFunction -> $newIrFunction" }
|
||||
protected open fun IrFunction.generateDefaultStubBody(originalDeclaration: IrFunction): IrBody {
|
||||
val newIrFunction = this
|
||||
val builder = context.createIrBuilder(newIrFunction.symbol)
|
||||
log { "$originalDeclaration -> $newIrFunction" }
|
||||
|
||||
newIrFunction.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||
return context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||
statements += builder.irBlockBody(newIrFunction) {
|
||||
val params = mutableListOf<IrValueDeclaration>()
|
||||
val variables = mutableMapOf<IrValueSymbol, IrValueSymbol>()
|
||||
|
||||
irFunction.dispatchReceiverParameter?.let {
|
||||
originalDeclaration.dispatchReceiverParameter?.let {
|
||||
variables[it.symbol] = newIrFunction.dispatchReceiverParameter?.symbol!!
|
||||
}
|
||||
|
||||
irFunction.extensionReceiverParameter?.let {
|
||||
originalDeclaration.extensionReceiverParameter?.let {
|
||||
variables[it.symbol] = newIrFunction.extensionReceiverParameter?.symbol!!
|
||||
}
|
||||
|
||||
@@ -96,23 +84,23 @@ open class DefaultArgumentStubGenerator(
|
||||
//
|
||||
// works correctly so that `f() { "OK" }` returns "OK" and
|
||||
// `f()` throws a NullPointerException.
|
||||
irFunction.valueParameters.forEach {
|
||||
originalDeclaration.valueParameters.forEach {
|
||||
variables[it.symbol] = newIrFunction.valueParameters[it.index].symbol
|
||||
}
|
||||
|
||||
generateSuperCallHandlerCheckIfNeeded(irFunction, newIrFunction)
|
||||
generateSuperCallHandlerCheckIfNeeded(originalDeclaration, newIrFunction)
|
||||
|
||||
val intAnd = this@DefaultArgumentStubGenerator.context.ir.symbols.getBinaryOperator(
|
||||
OperatorNameConventions.AND, context.irBuiltIns.intType, context.irBuiltIns.intType
|
||||
)
|
||||
var sourceParameterIndex = -1
|
||||
for (valueParameter in irFunction.valueParameters) {
|
||||
for (valueParameter in originalDeclaration.valueParameters) {
|
||||
if (!valueParameter.isMovedReceiver()) {
|
||||
++sourceParameterIndex
|
||||
}
|
||||
val parameter = newIrFunction.valueParameters[valueParameter.index]
|
||||
val remapped = valueParameter.defaultValue?.let { defaultValue ->
|
||||
val mask = irGet(newIrFunction.valueParameters[irFunction.valueParameters.size + valueParameter.index / 32])
|
||||
val mask = irGet(newIrFunction.valueParameters[originalDeclaration.valueParameters.size + valueParameter.index / 32])
|
||||
val bit = irInt(1 shl (sourceParameterIndex % 32))
|
||||
val defaultFlag =
|
||||
irCallOp(intAnd, context.irBuiltIns.intType, mask, bit)
|
||||
@@ -128,8 +116,8 @@ open class DefaultArgumentStubGenerator(
|
||||
variables[valueParameter.symbol] = remapped.symbol
|
||||
}
|
||||
|
||||
when (irFunction) {
|
||||
is IrConstructor -> +irDelegatingConstructorCall(irFunction).apply {
|
||||
when (originalDeclaration) {
|
||||
is IrConstructor -> +irDelegatingConstructorCall(originalDeclaration).apply {
|
||||
passTypeArgumentsFrom(newIrFunction.parentAsClass)
|
||||
// This is for Kotlin/Native, which differs from the other backends in that constructors
|
||||
// apparently do have dispatch receivers (though *probably* not type arguments, but copy
|
||||
@@ -138,12 +126,30 @@ open class DefaultArgumentStubGenerator(
|
||||
dispatchReceiver = newIrFunction.dispatchReceiverParameter?.let { irGet(it) }
|
||||
params.forEachIndexed { i, variable -> putValueArgument(i, irGet(variable)) }
|
||||
}
|
||||
is IrSimpleFunction -> +irReturn(dispatchToImplementation(irFunction, newIrFunction, params))
|
||||
is IrSimpleFunction -> +irReturn(dispatchToImplementation(originalDeclaration, newIrFunction, params))
|
||||
else -> error("Unknown function declaration")
|
||||
}
|
||||
}.statements
|
||||
}
|
||||
return listOf(irFunction, newIrFunction)
|
||||
}
|
||||
|
||||
private fun lower(irFunction: IrFunction): List<IrFunction>? {
|
||||
val newIrFunction =
|
||||
factory.generateDefaultsFunction(
|
||||
irFunction,
|
||||
skipInlineMethods,
|
||||
skipExternalMethods,
|
||||
forceSetOverrideSymbols,
|
||||
defaultArgumentStubVisibility(irFunction),
|
||||
useConstructorMarker(irFunction),
|
||||
irFunction.resolveAnnotations(),
|
||||
) ?: return null
|
||||
|
||||
return listOf(irFunction, newIrFunction).also {
|
||||
if (!newIrFunction.isFakeOverride) {
|
||||
newIrFunction.body = newIrFunction.generateDefaultStubBody(irFunction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -253,45 +259,24 @@ open class DefaultArgumentStubGenerator(
|
||||
private fun log(msg: () -> String) = context.log { "DEFAULT-REPLACER: ${msg()}" }
|
||||
}
|
||||
|
||||
private fun IrFunction.findBaseFunctionWithDefaultArguments(skipInlineMethods: Boolean, skipExternalMethods: Boolean): IrFunction? {
|
||||
|
||||
val visited = mutableSetOf<IrFunction>()
|
||||
|
||||
fun IrFunction.dfsImpl(): IrFunction? {
|
||||
visited += this
|
||||
|
||||
if (isInline && skipInlineMethods) return null
|
||||
if (skipExternalMethods && isExternalOrInheritedFromExternal()) return null
|
||||
|
||||
if (this is IrSimpleFunction) {
|
||||
overriddenSymbols.forEach { overridden ->
|
||||
val base = overridden.owner
|
||||
if (base !in visited) base.dfsImpl()?.let { return it }
|
||||
}
|
||||
}
|
||||
|
||||
if (valueParameters.any { it.defaultValue != null }) return this
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
return dfsImpl()
|
||||
}
|
||||
|
||||
open class DefaultParameterInjector(
|
||||
open val context: CommonBackendContext,
|
||||
private val skipInline: Boolean = true,
|
||||
private val skipExternalMethods: Boolean = false,
|
||||
private val forceSetOverrideSymbols: Boolean = true
|
||||
protected val skipInline: Boolean = true,
|
||||
protected val skipExternalMethods: Boolean = false,
|
||||
protected val forceSetOverrideSymbols: Boolean = true,
|
||||
protected val factory: DefaultArgumentFunctionFactory = MaskedDefaultArgumentFunctionFactory(context),
|
||||
) : IrElementTransformerVoid(), BodyLoweringPass {
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildrenVoid(this)
|
||||
}
|
||||
|
||||
protected open fun shouldReplaceWithSyntheticFunction(functionAccess: IrFunctionAccessExpression): Boolean {
|
||||
return (0 until functionAccess.valueArgumentsCount).count { functionAccess.getValueArgument(it) != null } != functionAccess.symbol.owner.valueParameters.size
|
||||
}
|
||||
|
||||
private fun <T : IrFunctionAccessExpression> visitFunctionAccessExpression(expression: T, builder: (IrFunctionSymbol) -> T): T {
|
||||
val argumentsCount = (0 until expression.valueArgumentsCount).count { expression.getValueArgument(it) != null }
|
||||
if (argumentsCount == expression.symbol.owner.valueParameters.size)
|
||||
if (!shouldReplaceWithSyntheticFunction(expression))
|
||||
return expression
|
||||
|
||||
val (symbol, params) = parametersForCall(expression) ?: return expression
|
||||
@@ -346,7 +331,13 @@ open class DefaultParameterInjector(
|
||||
expression.transformChildrenVoid()
|
||||
return visitFunctionAccessExpression(expression) {
|
||||
with(expression) {
|
||||
IrConstructorCallImpl.fromSymbolOwner(startOffset, endOffset, type, it as IrConstructorSymbol, LoweredStatementOrigins.DEFAULT_DISPATCH_CALL)
|
||||
IrConstructorCallImpl.fromSymbolOwner(
|
||||
startOffset,
|
||||
endOffset,
|
||||
type,
|
||||
it as IrConstructorSymbol,
|
||||
LoweredStatementOrigins.DEFAULT_DISPATCH_CALL
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -379,7 +370,7 @@ open class DefaultParameterInjector(
|
||||
}
|
||||
}
|
||||
|
||||
private fun parametersForCall(expression: IrFunctionAccessExpression): Pair<IrFunctionSymbol, List<IrExpression?>>? {
|
||||
open protected fun parametersForCall(expression: IrFunctionAccessExpression): Pair<IrFunctionSymbol, List<IrExpression?>>? {
|
||||
val startOffset = expression.startOffset
|
||||
val endOffset = expression.endOffset
|
||||
val declaration = expression.symbol.owner
|
||||
@@ -388,21 +379,24 @@ open class DefaultParameterInjector(
|
||||
// in an interface does not leave an abstract method after being moved to DefaultImpls (see InterfaceLowering).
|
||||
// Calling the fake override on an implementation of that interface would then result in a call to a method
|
||||
// that does not actually exist as DefaultImpls is not part of the inheritance hierarchy.
|
||||
val baseFunction = declaration.findBaseFunctionWithDefaultArguments(skipInline, skipExternalMethods)
|
||||
val stubFunction = baseFunction?.generateDefaultsFunction(
|
||||
context,
|
||||
skipInline,
|
||||
skipExternalMethods,
|
||||
forceSetOverrideSymbols,
|
||||
defaultArgumentStubVisibility(declaration),
|
||||
useConstructorMarker(declaration),
|
||||
baseFunction.copyAnnotations()
|
||||
) ?: return null
|
||||
val baseFunction = factory.findBaseFunctionWithDefaultArgumentsFor(declaration, skipInline, skipExternalMethods)
|
||||
val stubFunction = baseFunction?.let {
|
||||
factory.generateDefaultsFunction(
|
||||
it,
|
||||
skipInline,
|
||||
skipExternalMethods,
|
||||
forceSetOverrideSymbols,
|
||||
defaultArgumentStubVisibility(declaration),
|
||||
useConstructorMarker(declaration),
|
||||
baseFunction.copyAnnotations(),
|
||||
)
|
||||
} ?: return null
|
||||
|
||||
log { "$declaration -> $stubFunction" }
|
||||
|
||||
val realArgumentsNumber = declaration.valueParameters.size
|
||||
val maskValues = IntArray((declaration.valueParameters.size + 31) / 32)
|
||||
|
||||
assert(
|
||||
((if (isStatic(expression.symbol.owner) && stubFunction.extensionReceiverParameter != null) 1 else 0) +
|
||||
stubFunction.valueParameters.size - realArgumentsNumber - maskValues.size) in listOf(0, 1)
|
||||
@@ -410,6 +404,7 @@ open class DefaultParameterInjector(
|
||||
"argument count mismatch: expected $realArgumentsNumber arguments + ${maskValues.size} masks + optional handler/marker, " +
|
||||
"got ${stubFunction.valueParameters.size} total in ${stubFunction.render()}"
|
||||
}
|
||||
|
||||
var sourceParameterIndex = -1
|
||||
val valueParametersPrefix =
|
||||
if (isStatic(expression.symbol.owner))
|
||||
@@ -500,134 +495,34 @@ class DefaultParameterPatchOverridenSymbolsLowering(
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrFunction.generateDefaultsFunction(
|
||||
context: CommonBackendContext,
|
||||
skipInlineMethods: Boolean,
|
||||
skipExternalMethods: Boolean,
|
||||
forceSetOverrideSymbols: Boolean,
|
||||
visibility: DescriptorVisibility,
|
||||
useConstructorMarker: Boolean,
|
||||
copiedAnnotations: List<IrConstructorCall>
|
||||
): IrFunction? {
|
||||
if (skipInlineMethods && isInline) return null
|
||||
if (skipExternalMethods && isExternalOrInheritedFromExternal()) return null
|
||||
if (context.mapping.defaultArgumentsOriginalFunction[this] != null) return null
|
||||
context.mapping.defaultArgumentsDispatchFunction[this]?.let { return it }
|
||||
if (this is IrSimpleFunction) {
|
||||
// If this is an override of a function with default arguments, produce a fake override of a default stub.
|
||||
if (overriddenSymbols.any { it.owner.findBaseFunctionWithDefaultArguments(skipInlineMethods, skipExternalMethods) != null })
|
||||
return generateDefaultsFunctionImpl(
|
||||
context, IrDeclarationOrigin.FAKE_OVERRIDE, visibility, copiedAnnotations, true, useConstructorMarker
|
||||
).also { defaultsFunction ->
|
||||
context.mapping.defaultArgumentsDispatchFunction[this] = defaultsFunction
|
||||
context.mapping.defaultArgumentsOriginalFunction[defaultsFunction] = this
|
||||
private class MaskedDefaultArgumentFunctionFactory(context: CommonBackendContext) : DefaultArgumentFunctionFactory(context) {
|
||||
override fun IrFunction.generateDefaultArgumentStubFrom(original: IrFunction, useConstructorMarker: Boolean) {
|
||||
copyAttributesFrom(original)
|
||||
copyTypeParametersFrom(original)
|
||||
copyReturnTypeFrom(original)
|
||||
copyReceiversFrom(original)
|
||||
copyValueParametersFrom(original)
|
||||
|
||||
if (forceSetOverrideSymbols) {
|
||||
(defaultsFunction as IrSimpleFunction).overriddenSymbols += overriddenSymbols.mapNotNull {
|
||||
it.owner.generateDefaultsFunction(
|
||||
context,
|
||||
skipInlineMethods,
|
||||
skipExternalMethods,
|
||||
forceSetOverrideSymbols,
|
||||
visibility,
|
||||
useConstructorMarker,
|
||||
it.owner.copyAnnotations()
|
||||
)?.symbol as IrSimpleFunctionSymbol?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Note: this is intentionally done *after* checking for overrides. While normally `override fun`s
|
||||
// have no default parameters, there is an exception in case of interface delegation:
|
||||
// interface I {
|
||||
// fun f(x: Int = 1)
|
||||
// }
|
||||
// class C(val y: I) : I by y {
|
||||
// // implicit `override fun f(x: Int) = y.f(x)` has a default value for `x`
|
||||
// }
|
||||
// Since this bug causes the metadata serializer to write the "has default value" flag into compiled
|
||||
// binaries, it's way too late to fix it. Hence the workaround.
|
||||
if (valueParameters.any { it.defaultValue != null }) {
|
||||
return generateDefaultsFunctionImpl(
|
||||
context, IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER, visibility, copiedAnnotations, false, useConstructorMarker
|
||||
).also {
|
||||
context.mapping.defaultArgumentsDispatchFunction[this] = it
|
||||
context.mapping.defaultArgumentsOriginalFunction[it] = this
|
||||
for (i in 0 until (original.valueParameters.size + 31) / 32) {
|
||||
addValueParameter(
|
||||
"mask$i".synthesizedString,
|
||||
context.irBuiltIns.intType,
|
||||
IrDeclarationOrigin.MASK_FOR_DEFAULT_FUNCTION
|
||||
)
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun IrFunction.generateDefaultsFunctionImpl(
|
||||
context: CommonBackendContext,
|
||||
newOrigin: IrDeclarationOrigin,
|
||||
newVisibility: DescriptorVisibility,
|
||||
copiedAnnotations: List<IrConstructorCall>,
|
||||
isFakeOverride: Boolean,
|
||||
useConstructorMarker: Boolean
|
||||
): IrFunction {
|
||||
val newFunction = when (this) {
|
||||
is IrConstructor ->
|
||||
factory.buildConstructor {
|
||||
updateFrom(this@generateDefaultsFunctionImpl)
|
||||
origin = newOrigin
|
||||
isExternal = false
|
||||
isPrimary = false
|
||||
isExpect = false
|
||||
visibility = newVisibility
|
||||
}
|
||||
is IrSimpleFunction ->
|
||||
factory.buildFun {
|
||||
updateFrom(this@generateDefaultsFunctionImpl)
|
||||
name = Name.identifier("${this@generateDefaultsFunctionImpl.name}\$default")
|
||||
origin = newOrigin
|
||||
this.isFakeOverride = isFakeOverride
|
||||
modality = Modality.FINAL
|
||||
isExternal = false
|
||||
isTailrec = false
|
||||
visibility = newVisibility
|
||||
}
|
||||
else -> throw IllegalStateException("Unknown function type")
|
||||
}
|
||||
(newFunction as? IrAttributeContainer)?.copyAttributes(this@generateDefaultsFunctionImpl as? IrAttributeContainer)
|
||||
newFunction.copyTypeParametersFrom(this)
|
||||
newFunction.parent = parent
|
||||
newFunction.returnType = returnType.remapTypeParameters(classIfConstructor, newFunction.classIfConstructor)
|
||||
newFunction.dispatchReceiverParameter = dispatchReceiverParameter?.copyTo(newFunction)
|
||||
newFunction.extensionReceiverParameter = extensionReceiverParameter?.copyTo(newFunction)
|
||||
newFunction.contextReceiverParametersCount = contextReceiverParametersCount
|
||||
if (useConstructorMarker) {
|
||||
val markerType = context.ir.symbols.defaultConstructorMarker.defaultType.makeNullable()
|
||||
addValueParameter("marker".synthesizedString, markerType, IrDeclarationOrigin.DEFAULT_CONSTRUCTOR_MARKER)
|
||||
} else if (context.ir.shouldGenerateHandlerParameterForDefaultBodyFun()) {
|
||||
addValueParameter(
|
||||
"handler".synthesizedString,
|
||||
context.irBuiltIns.anyNType,
|
||||
IrDeclarationOrigin.METHOD_HANDLER_IN_DEFAULT_FUNCTION
|
||||
)
|
||||
}
|
||||
|
||||
newFunction.valueParameters = valueParameters.map {
|
||||
val newType = it.type.remapTypeParameters(classIfConstructor, newFunction.classIfConstructor)
|
||||
val makeNullable = it.defaultValue != null &&
|
||||
(context.ir.unfoldInlineClassType(it.type) ?: it.type) !in context.irBuiltIns.primitiveIrTypes
|
||||
it.copyTo(
|
||||
newFunction,
|
||||
type = if (makeNullable) newType.makeNullable() else newType,
|
||||
defaultValue = if (it.defaultValue != null) {
|
||||
factory.createExpressionBody(IrErrorExpressionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it.type, "Default Stub"))
|
||||
} else null,
|
||||
isAssignable = it.defaultValue != null
|
||||
)
|
||||
}
|
||||
|
||||
for (i in 0 until (valueParameters.size + 31) / 32) {
|
||||
newFunction.addValueParameter("mask$i".synthesizedString, context.irBuiltIns.intType, IrDeclarationOrigin.MASK_FOR_DEFAULT_FUNCTION)
|
||||
}
|
||||
if (useConstructorMarker) {
|
||||
val markerType = context.ir.symbols.defaultConstructorMarker.defaultType.makeNullable()
|
||||
newFunction.addValueParameter("marker".synthesizedString, markerType, IrDeclarationOrigin.DEFAULT_CONSTRUCTOR_MARKER)
|
||||
} else if (context.ir.shouldGenerateHandlerParameterForDefaultBodyFun()) {
|
||||
newFunction.addValueParameter(
|
||||
"handler".synthesizedString,
|
||||
context.irBuiltIns.anyNType,
|
||||
IrDeclarationOrigin.METHOD_HANDLER_IN_DEFAULT_FUNCTION
|
||||
)
|
||||
}
|
||||
|
||||
// TODO some annotations are needed (e.g. @JvmStatic), others need different values (e.g. @JvmName), the rest are redundant.
|
||||
newFunction.annotations += copiedAnnotations
|
||||
return newFunction
|
||||
}
|
||||
|
||||
private fun IrValueParameter.isMovedReceiver() =
|
||||
|
||||
@@ -16,6 +16,7 @@ object JsLoweredDeclarationOrigin : IrDeclarationOrigin {
|
||||
object BRIDGE_PROPERTY_ACCESSOR : IrDeclarationOriginImpl("BRIDGE_PROPERTY_ACCESSOR")
|
||||
object OBJECT_GET_INSTANCE_FUNCTION : IrDeclarationOriginImpl("OBJECT_GET_INSTANCE_FUNCTION")
|
||||
object JS_SHADOWED_EXPORT : IrDeclarationOriginImpl("JS_SHADOWED_EXPORT")
|
||||
object JS_SUPER_CONTEXT_PARAMETER : IrDeclarationOriginImpl("JS_SUPER_CONTEXT_PARAMETER")
|
||||
object JS_SHADOWED_DEFAULT_PARAMETER : IrDeclarationOriginImpl("JS_SHADOWED_DEFAULT_PARAMETER")
|
||||
object ENUM_GET_INSTANCE_FUNCTION : IrDeclarationOriginImpl("ENUM_GET_INSTANCE_FUNCTION")
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
// TODO: Should we drop operator intrinsics in favor of IrDynamicOperatorExpression?
|
||||
|
||||
// Global variables
|
||||
val void = getInternalProperty("VOID")
|
||||
val globalThis = getInternalProperty("globalThis")
|
||||
|
||||
// Equality operations:
|
||||
@@ -140,7 +141,6 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
|
||||
// Other:
|
||||
|
||||
val jsObjectCreate = getInternalFunction("objectCreate") // Object.create
|
||||
val jsCode = getInternalFunction("js") // js("<code>")
|
||||
val jsHashCode = getInternalFunction("hashCode")
|
||||
val jsGetNumberHashCode = getInternalFunction("getNumberHashCode")
|
||||
@@ -313,11 +313,13 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
|
||||
val jsArraySlice = getInternalFunction("slice")
|
||||
|
||||
val jsCall = getInternalFunction("jsCall")
|
||||
val jsBind = getInternalFunction("jsBind")
|
||||
|
||||
// TODO move to IntrinsifyCallsLowering
|
||||
val doNotIntrinsifyAnnotationSymbol = context.symbolTable.referenceClass(context.getJsInternalClass("DoNotIntrinsify"))
|
||||
val jsFunAnnotationSymbol = context.symbolTable.referenceClass(context.getJsInternalClass("JsFun"))
|
||||
val jsNameAnnotationSymbol = context.symbolTable.referenceClass(context.getJsInternalClass("JsName"))
|
||||
|
||||
val jsImplicitExportAnnotationSymbol = context.symbolTable.referenceClass(context.getJsInternalClass("JsImplicitExport"))
|
||||
|
||||
@@ -341,6 +343,7 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
val jsCharSequenceLength = getInternalFunction("charSequenceLength")
|
||||
val jsCharSequenceSubSequence = getInternalFunction("charSequenceSubSequence")
|
||||
|
||||
val jsContexfulRef = getInternalFunction("jsContextfulRef")
|
||||
val jsBoxIntrinsic = getInternalFunction("boxIntrinsic")
|
||||
val jsUnboxIntrinsic = getInternalFunction("unboxIntrinsic")
|
||||
|
||||
@@ -350,10 +353,12 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
val readSharedBox = getInternalFunction("sharedBoxRead")
|
||||
val writeSharedBox = getInternalFunction("sharedBoxWrite")
|
||||
|
||||
val jsUndefined = getInternalFunction("jsUndefined")
|
||||
|
||||
val linkageErrorSymbol = getInternalFunction("throwLinkageError")
|
||||
|
||||
val jsPrototypeOfSymbol = getInternalFunction("protoOf")
|
||||
val jsDefinePropertySymbol = getInternalFunction("defineProp")
|
||||
val jsObjectCreateSymbol = getInternalFunction("objectCreate") // Object.create
|
||||
|
||||
// Helpers:
|
||||
|
||||
private fun getInternalFunction(name: String) =
|
||||
|
||||
@@ -555,7 +555,7 @@ private val defaultArgumentPatchOverridesPhase = makeDeclarationTransformerPhase
|
||||
)
|
||||
|
||||
private val defaultParameterInjectorPhase = makeBodyLoweringPhase(
|
||||
{ context -> DefaultParameterInjector(context, skipExternalMethods = true, forceSetOverrideSymbols = false) },
|
||||
::JsDefaultParameterInjector,
|
||||
name = "DefaultParameterInjector",
|
||||
description = "Replace callsite with default parameters with corresponding stub function",
|
||||
prerequisite = setOf(interopCallableReferenceLoweringPhase, innerClassesLoweringPhase)
|
||||
@@ -567,19 +567,6 @@ private val defaultParameterCleanerPhase = makeDeclarationTransformerPhase(
|
||||
description = "Clean default parameters up"
|
||||
)
|
||||
|
||||
|
||||
private val exportedDefaultParameterStubPhase = makeDeclarationTransformerPhase(
|
||||
::ExportedDefaultParameterStub,
|
||||
name = "ExportedDefaultParameterStub",
|
||||
description = "Generates default stub for exported entity and renames the non-default counterpart"
|
||||
)
|
||||
|
||||
private val jsDefaultCallbackGeneratorPhase = makeBodyLoweringPhase(
|
||||
::JsDefaultCallbackGenerator,
|
||||
name = "JsDefaultCallbackGenerator",
|
||||
description = "Build binding for super calls with default parameters"
|
||||
)
|
||||
|
||||
private val varargLoweringPhase = makeBodyLoweringPhase(
|
||||
::VarargLowering,
|
||||
name = "VarargLowering",
|
||||
@@ -811,6 +798,7 @@ private val cleanupLoweringPhase = makeBodyLoweringPhase(
|
||||
name = "CleanupLowering",
|
||||
description = "Clean up IR before codegen"
|
||||
)
|
||||
|
||||
private val moveOpenClassesToSeparatePlaceLowering = makeCustomJsModulePhase(
|
||||
{ context, module ->
|
||||
if (context.granularity == JsGenerationGranularity.PER_FILE)
|
||||
@@ -899,12 +887,10 @@ val loweringList = listOf<Lowering>(
|
||||
computeStringTrimPhase,
|
||||
privateMembersLoweringPhase,
|
||||
privateMemberUsagesLoweringPhase,
|
||||
exportedDefaultParameterStubPhase,
|
||||
defaultArgumentStubGeneratorPhase,
|
||||
defaultArgumentPatchOverridesPhase,
|
||||
defaultParameterInjectorPhase,
|
||||
defaultParameterCleanerPhase,
|
||||
jsDefaultCallbackGeneratorPhase,
|
||||
throwableSuccessorsLoweringPhase,
|
||||
es6AddInternalParametersToConstructorPhase,
|
||||
es6ConstructorLowering,
|
||||
|
||||
@@ -239,7 +239,7 @@ class IrToJs(
|
||||
|
||||
val globalNames = NameTable<String>(nameGenerator.staticNames)
|
||||
val exporter = ExportModelToJsStatements(
|
||||
nameGenerator,
|
||||
staticContext,
|
||||
declareNewNamespace = { globalNames.declareFreshName(it, it) }
|
||||
)
|
||||
exportedDeclarations.forEach {
|
||||
|
||||
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.js.config.RuntimeDiagnostic
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
fun eliminateDeadDeclarations(
|
||||
modules: Iterable<IrModuleFragment>,
|
||||
@@ -116,6 +117,7 @@ private fun buildRoots(modules: Iterable<IrModuleFragment>, context: JsIrBackend
|
||||
}
|
||||
}
|
||||
|
||||
addIfNotNull(context.intrinsics.void.owner.backingField)
|
||||
addAll(context.testFunsPerFile.values)
|
||||
addAll(context.additionalExportedDeclarations)
|
||||
}
|
||||
|
||||
+27
-3
@@ -67,9 +67,9 @@ internal class JsUsefulDeclarationProcessor(
|
||||
val ref = expression.getTypeArgument(0)?.classOrNull ?: context.irBuiltIns.anyClass
|
||||
referencedJsClassesFromExpressions += ref.owner
|
||||
}
|
||||
context.intrinsics.jsObjectCreate -> {
|
||||
context.intrinsics.jsObjectCreateSymbol -> {
|
||||
val classToCreate = expression.getTypeArgument(0)!!.classifierOrFail.owner as IrClass
|
||||
classToCreate.enqueue(data, "intrinsic: jsObjectCreate")
|
||||
classToCreate.enqueue(data, "intrinsic: jsObjectCreateSymbol")
|
||||
constructedClasses += classToCreate
|
||||
}
|
||||
context.intrinsics.jsEquals -> {
|
||||
@@ -129,11 +129,29 @@ internal class JsUsefulDeclarationProcessor(
|
||||
if (irClass.containsMetadata()) {
|
||||
when {
|
||||
irClass.isObject -> context.intrinsics.metadataObjectConstructorSymbol.owner.enqueue(irClass, "object metadata")
|
||||
|
||||
irClass.isInterface -> {
|
||||
context.intrinsics.implementSymbol.owner.enqueue(irClass, "interface metadata")
|
||||
context.intrinsics.metadataInterfaceConstructorSymbol.owner.enqueue(irClass, "interface metadata")
|
||||
}
|
||||
else -> context.intrinsics.metadataClassConstructorSymbol.owner.enqueue(irClass, "class metadata")
|
||||
|
||||
else -> {
|
||||
context.intrinsics.metadataClassConstructorSymbol.owner.enqueue(irClass, "class metadata")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!irClass.isExpect && !irClass.isExternal && !irClass.defaultType.isAny()) {
|
||||
if (!irClass.isInterface) {
|
||||
context.intrinsics.jsPrototypeOfSymbol.owner.enqueue(irClass, "class metadata")
|
||||
}
|
||||
|
||||
if (irClass.superTypes.any { !it.isInterface() }) {
|
||||
context.intrinsics.jsObjectCreateSymbol.owner.enqueue(irClass, "class metadata")
|
||||
}
|
||||
|
||||
if (irClass.isInner || irClass.isObject) {
|
||||
context.intrinsics.jsDefinePropertySymbol.owner.enqueue(irClass, "class metadata")
|
||||
}
|
||||
|
||||
context.intrinsics.setMetadataForSymbol.owner.enqueue(irClass, "metadata")
|
||||
@@ -146,6 +164,12 @@ internal class JsUsefulDeclarationProcessor(
|
||||
if (irFunction.isReal && irFunction.body != null) {
|
||||
irFunction.parentClassOrNull?.takeIf { it.isInterface }?.enqueue(irFunction, "interface default method is used")
|
||||
}
|
||||
|
||||
val property = irFunction.correspondingPropertySymbol?.owner ?: return
|
||||
|
||||
if (property.isExported(context) || property.isOverriddenExternal()) {
|
||||
context.intrinsics.jsDefinePropertySymbol.owner.enqueue(irFunction, "property for export")
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrClass.containsMetadata(): Boolean =
|
||||
|
||||
+6
-3
@@ -218,14 +218,17 @@ abstract class UsefulDeclarationProcessor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.isAccessorForOverriddenExternalField(): Boolean {
|
||||
protected fun IrSimpleFunction.isAccessorForOverriddenExternalField(): Boolean {
|
||||
return correspondingPropertySymbol?.owner?.isExternalOrOverriddenExternal() ?: false
|
||||
}
|
||||
|
||||
private fun IrProperty.isExternalOrOverriddenExternal(): Boolean {
|
||||
return isEffectivelyExternal() || overriddenSymbols.any { it.owner.isExternalOrOverriddenExternal() }
|
||||
protected fun IrProperty.isExternalOrOverriddenExternal(): Boolean {
|
||||
return isEffectivelyExternal() || isOverriddenExternal()
|
||||
}
|
||||
|
||||
protected fun IrProperty.isOverriddenExternal(): Boolean =
|
||||
overriddenSymbols.any { it.owner.isExternalOrOverriddenExternal() }
|
||||
|
||||
protected open fun handleAssociatedObjects(): Unit = Unit
|
||||
|
||||
fun collectDeclarations(rootDeclarations: Iterable<IrDeclaration>): Set<IrDeclaration> {
|
||||
|
||||
+8
-3
@@ -86,13 +86,15 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
|
||||
ExportedFunction(
|
||||
function.getExportedIdentifier(),
|
||||
returnType = exportType(function.returnType),
|
||||
parameters = (listOfNotNull(function.extensionReceiverParameter) + function.valueParameters).map { exportParameter(it) },
|
||||
typeParameters = function.typeParameters.map(::exportTypeParameter),
|
||||
isMember = parent is IrClass,
|
||||
isStatic = function.isStaticMethodOfClass,
|
||||
isAbstract = parent is IrClass && !parent.isInterface && function.modality == Modality.ABSTRACT,
|
||||
isProtected = function.visibility == DescriptorVisibilities.PROTECTED,
|
||||
ir = function
|
||||
ir = function,
|
||||
parameters = (listOfNotNull(function.extensionReceiverParameter) + function.valueParameters)
|
||||
.filter { it.shouldBeExported() }
|
||||
.map { exportParameter(it) },
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -362,6 +364,10 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
|
||||
return isInterface && !isExternal || isJsImplicitExport()
|
||||
}
|
||||
|
||||
private fun IrValueParameter.shouldBeExported(): Boolean {
|
||||
return origin != JsLoweredDeclarationOrigin.JS_SUPER_CONTEXT_PARAMETER
|
||||
}
|
||||
|
||||
private fun IrClass.shouldContainImplementationOfMagicProperty(superTypes: Iterable<IrType>): Boolean {
|
||||
return !isExternal && superTypes.any {
|
||||
val superClass = it.classOrNull?.owner ?: return@any false
|
||||
@@ -640,7 +646,6 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
|
||||
if (function.origin == JsLoweredDeclarationOrigin.BRIDGE_WITHOUT_STABLE_NAME ||
|
||||
function.origin == JsLoweredDeclarationOrigin.BRIDGE_PROPERTY_ACCESSOR ||
|
||||
function.origin == JsLoweredDeclarationOrigin.BRIDGE_WITH_STABLE_NAME ||
|
||||
function.origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER ||
|
||||
function.origin == JsLoweredDeclarationOrigin.OBJECT_GET_INSTANCE_FUNCTION ||
|
||||
function.origin == JsLoweredDeclarationOrigin.JS_SHADOWED_EXPORT ||
|
||||
function.origin == JsLoweredDeclarationOrigin.ENUM_GET_INSTANCE_FUNCTION
|
||||
|
||||
+9
-15
@@ -5,21 +5,14 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.export
|
||||
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsAstUtils
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.defineProperty
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.jsAssignment
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.prototypeOf
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.jsElementAccess
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.IrNamer
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.util.companionObject
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.util.collectionUtils.filterIsInstanceAnd
|
||||
|
||||
class ExportModelToJsStatements(
|
||||
private val namer: IrNamer,
|
||||
private val namer: JsStaticContext,
|
||||
private val declareNewNamespace: (String) -> String
|
||||
) {
|
||||
private val namespaceToRefMap = mutableMapOf<String, JsNameRef>()
|
||||
@@ -88,7 +81,7 @@ class ExportModelToJsStatements(
|
||||
require(namespace != null) { "Only namespaced properties are allowed" }
|
||||
val getter = declaration.irGetter?.let { JsNameRef(namer.getNameForStaticDeclaration(it)) }
|
||||
val setter = declaration.irSetter?.let { JsNameRef(namer.getNameForStaticDeclaration(it)) }
|
||||
listOf(defineProperty(namespace, declaration.name, getter, setter).makeStmt())
|
||||
listOf(defineProperty(namespace, declaration.name, getter, setter, namer).makeStmt())
|
||||
}
|
||||
|
||||
is ErrorDeclaration -> emptyList()
|
||||
@@ -98,7 +91,7 @@ class ExportModelToJsStatements(
|
||||
val newNameSpace = jsElementAccess(declaration.name, namespace)
|
||||
val getter = JsNameRef(namer.getNameForStaticDeclaration(declaration.irGetter))
|
||||
val staticsExport = declaration.nestedClasses.flatMap { generateDeclarationExport(it, newNameSpace, esModules) }
|
||||
listOf(defineProperty(namespace, declaration.name, getter, null).makeStmt()) + staticsExport
|
||||
listOf(defineProperty(namespace, declaration.name, getter, null, namer).makeStmt()) + staticsExport
|
||||
}
|
||||
|
||||
is ExportedRegularClass -> {
|
||||
@@ -106,7 +99,7 @@ class ExportModelToJsStatements(
|
||||
val newNameSpace = if (namespace != null)
|
||||
jsElementAccess(declaration.name, namespace)
|
||||
else
|
||||
JsNameRef(Namer.PROTOTYPE_NAME, namer.getNameForClass(declaration.ir).makeRef())
|
||||
prototypeOf(namer.getNameForClass(declaration.ir).makeRef(), namer)
|
||||
val name = namer.getNameForStaticDeclaration(declaration.ir)
|
||||
val klassExport =
|
||||
if (esModules) {
|
||||
@@ -173,14 +166,15 @@ class ExportModelToJsStatements(
|
||||
blockStatements.add(JsReturn(bindConstructor.makeRef()))
|
||||
|
||||
return defineProperty(
|
||||
prototypeOf(outerClassRef),
|
||||
prototypeOf(outerClassRef, namer),
|
||||
name,
|
||||
JsFunction(
|
||||
emptyScope,
|
||||
JsBlock(*blockStatements.toTypedArray()),
|
||||
"inner class '$name' getter"
|
||||
),
|
||||
null
|
||||
null,
|
||||
namer
|
||||
).makeStmt()
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,9 @@ object JsIrBuilder {
|
||||
fun buildGetValue(symbol: IrValueSymbol) =
|
||||
IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol.owner.type, symbol, JsStatementOrigins.SYNTHESIZED_STATEMENT)
|
||||
|
||||
fun buildSetValue(symbol: IrValueSymbol, value: IrExpression) =
|
||||
IrSetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol.owner.type, symbol, value, JsStatementOrigins.SYNTHESIZED_STATEMENT)
|
||||
|
||||
fun buildSetVariable(symbol: IrVariableSymbol, value: IrExpression, type: IrType) =
|
||||
IrSetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, symbol, value, JsStatementOrigins.SYNTHESIZED_STATEMENT)
|
||||
|
||||
|
||||
+7
-3
@@ -227,10 +227,14 @@ class AutoboxingTransformer(context: JsCommonBackendContext) : AbstractValueUsag
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
if (expression.symbol == irBuiltIns.eqeqeqSymbol && expression.allArgumentsHaveType(irBuiltIns.charType)) {
|
||||
return expression.apply { transformChildrenVoid() }
|
||||
return if (
|
||||
expression.symbol != irBuiltIns.eqeqeqSymbol ||
|
||||
!expression.allArgumentsHaveType(irBuiltIns.charType) &&
|
||||
expression.origin != IrStatementOrigin.SYNTHETIC_NOT_AUTOBOXED_CHECK
|
||||
) {
|
||||
super.visitCall(expression)
|
||||
} else {
|
||||
return super.visitCall(expression)
|
||||
expression.apply { transformChildrenVoid() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-154
@@ -1,154 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.backend.common.lower.VariableRemapper
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsAnnotations
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.hasStableJsName
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
private fun IrConstructorCall.isAnnotation(name: FqName): Boolean {
|
||||
return symbol.owner.parentAsClass.fqNameWhenAvailable == name
|
||||
}
|
||||
|
||||
class ExportedDefaultParameterStub(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
|
||||
private fun IrBuilderWithScope.createDefaultResolutionExpression(
|
||||
fromParameter: IrValueParameter,
|
||||
toParameter: IrValueParameter,
|
||||
): IrExpression? {
|
||||
return fromParameter.defaultValue?.let { defaultValue ->
|
||||
irIfThenElse(
|
||||
toParameter.type,
|
||||
irEqeqeq(
|
||||
irGet(toParameter, context.irBuiltIns.anyNType),
|
||||
irCall(this@ExportedDefaultParameterStub.context.intrinsics.jsUndefined)
|
||||
),
|
||||
defaultValue.expression,
|
||||
irGet(toParameter)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrConstructor.introduceDefaultResolution(): IrConstructor {
|
||||
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
|
||||
|
||||
val variables = mutableMapOf<IrValueParameter, IrValueDeclaration>()
|
||||
|
||||
val defaultResolutionStatements = valueParameters.mapNotNull { valueParameter ->
|
||||
irBuilder.createDefaultResolutionExpression(valueParameter, valueParameter)?.let { initializer ->
|
||||
JsIrBuilder.buildVar(
|
||||
valueParameter.type,
|
||||
this@introduceDefaultResolution,
|
||||
name = valueParameter.name.asString(),
|
||||
initializer = initializer
|
||||
).also {
|
||||
variables[valueParameter] = it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (variables.isNotEmpty()) {
|
||||
body?.transformChildren(VariableRemapper(variables), null)
|
||||
|
||||
body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||
statements += defaultResolutionStatements
|
||||
statements += body?.statements ?: emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return also {
|
||||
valueParameters.forEach {
|
||||
if (it.defaultValue != null) {
|
||||
it.origin = JsLoweredDeclarationOrigin.JS_SHADOWED_DEFAULT_PARAMETER
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (declaration !is IrFunction) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (!declaration.hasStableJsName(context)) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (!declaration.valueParameters.any { it.defaultValue != null }) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (declaration is IrConstructor) {
|
||||
return listOf(declaration.introduceDefaultResolution())
|
||||
}
|
||||
|
||||
val exportedDefaultStubFun = context.irFactory.buildFun {
|
||||
updateFrom(declaration)
|
||||
name = declaration.name
|
||||
origin = JsIrBuilder.SYNTHESIZED_DECLARATION
|
||||
}
|
||||
|
||||
if (declaration.isExported(context)) {
|
||||
context.additionalExportedDeclarations.add(exportedDefaultStubFun)
|
||||
}
|
||||
|
||||
exportedDefaultStubFun.parent = declaration.parent
|
||||
exportedDefaultStubFun.copyParameterDeclarationsFrom(declaration)
|
||||
exportedDefaultStubFun.returnType = declaration.returnType.remapTypeParameters(declaration, exportedDefaultStubFun)
|
||||
exportedDefaultStubFun.valueParameters.forEach {
|
||||
if (it.defaultValue != null) {
|
||||
it.origin = JsLoweredDeclarationOrigin.JS_SHADOWED_DEFAULT_PARAMETER
|
||||
}
|
||||
|
||||
it.defaultValue = null
|
||||
|
||||
}
|
||||
|
||||
declaration.origin = JsLoweredDeclarationOrigin.JS_SHADOWED_EXPORT
|
||||
|
||||
val irBuilder = context.createIrBuilder(exportedDefaultStubFun.symbol, exportedDefaultStubFun.startOffset, exportedDefaultStubFun.endOffset)
|
||||
exportedDefaultStubFun.body = irBuilder.irBlockBody(exportedDefaultStubFun) {
|
||||
+irReturn(irCall(declaration).apply {
|
||||
passTypeArgumentsFrom(declaration)
|
||||
dispatchReceiver = exportedDefaultStubFun.dispatchReceiverParameter?.let { irGet(it) }
|
||||
extensionReceiver = exportedDefaultStubFun.extensionReceiverParameter?.let { irGet(it) }
|
||||
|
||||
declaration.valueParameters.forEachIndexed { index, irValueParameter ->
|
||||
val exportedParameter = exportedDefaultStubFun.valueParameters[index]
|
||||
val value = createDefaultResolutionExpression(irValueParameter, exportedParameter) ?: irGet(exportedParameter)
|
||||
putValueArgument(index, value)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
val (exportAnnotations, irrelevantAnnotations) = declaration.annotations.map { it.deepCopyWithSymbols(declaration as? IrDeclarationParent) }
|
||||
.partition {
|
||||
it.isAnnotation(JsAnnotations.jsExportFqn) || (it.isAnnotation(JsAnnotations.jsNameFqn))
|
||||
}
|
||||
|
||||
declaration.annotations = irrelevantAnnotations
|
||||
exportedDefaultStubFun.annotations = exportAnnotations
|
||||
|
||||
return listOf(exportedDefaultStubFun, declaration)
|
||||
}
|
||||
}
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.lower.DefaultArgumentFunctionFactory
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.util.copyTypeParametersFrom
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.isTopLevel
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class JsDefaultArgumentFunctionFactory(override val context: JsIrBackendContext) : DefaultArgumentFunctionFactory(context) {
|
||||
override fun IrFunction.generateDefaultArgumentStubFrom(original: IrFunction, useConstructorMarker: Boolean) {
|
||||
copyAttributesFrom(original)
|
||||
copyTypeParametersFrom(original)
|
||||
copyReturnTypeFrom(original)
|
||||
copyReceiversFrom(original)
|
||||
copyValueParametersFrom(original, wrapWithNullable = false)
|
||||
|
||||
if (!original.isTopLevel) {
|
||||
introduceContextParam()
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrFunction.introduceContextParam() = addValueParameter {
|
||||
name = Name.identifier("\$super")
|
||||
type = parentAsClass.defaultType
|
||||
origin = JsLoweredDeclarationOrigin.JS_SUPER_CONTEXT_PARAMETER
|
||||
}
|
||||
|
||||
}
|
||||
+215
-85
@@ -1,117 +1,247 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.ir.deepCopyWithVariables
|
||||
import org.jetbrains.kotlin.backend.common.lower.DefaultArgumentStubGenerator
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
||||
import org.jetbrains.kotlin.backend.common.lower.LoweredStatementOrigins
|
||||
import org.jetbrains.kotlin.backend.common.lower.*
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsAnnotations
|
||||
import org.jetbrains.kotlin.ir.builders.IrBlockBodyBuilder
|
||||
import org.jetbrains.kotlin.ir.builders.irCall
|
||||
import org.jetbrains.kotlin.ir.builders.irGet
|
||||
import org.jetbrains.kotlin.ir.builders.irImplicitCast
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getVoid
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
|
||||
class JsDefaultArgumentStubGenerator(override val context: JsIrBackendContext) : DefaultArgumentStubGenerator(context, true, true, false) {
|
||||
class JsDefaultArgumentStubGenerator(override val context: JsIrBackendContext) :
|
||||
DefaultArgumentStubGenerator(
|
||||
context,
|
||||
skipExternalMethods = true,
|
||||
forceSetOverrideSymbols = false,
|
||||
factory = JsDefaultArgumentFunctionFactory(context)
|
||||
) {
|
||||
|
||||
override fun needSpecialDispatch(irFunction: IrSimpleFunction) = irFunction.isOverridableOrOverrides
|
||||
|
||||
override fun IrFunction.resolveAnnotations(): List<IrConstructorCall> = copyAnnotationsWhen {
|
||||
!(isAnnotation(JsAnnotations.jsExportFqn) || isAnnotation(JsAnnotations.jsNameFqn))
|
||||
}
|
||||
|
||||
override fun IrBlockBodyBuilder.generateHandleCall(
|
||||
handlerDeclaration: IrValueParameter,
|
||||
oldIrFunction: IrFunction,
|
||||
newIrFunction: IrFunction,
|
||||
params: MutableList<IrValueDeclaration>
|
||||
): IrExpression {
|
||||
val paramCount = oldIrFunction.valueParameters.size
|
||||
val invokeFunctionN = resolveInvoke(paramCount)
|
||||
|
||||
return irCall(invokeFunctionN, IrStatementOrigin.INVOKE).apply {
|
||||
dispatchReceiver = irImplicitCast(irGet(handlerDeclaration), invokeFunctionN.dispatchReceiverParameter!!.type)
|
||||
// NOTE: currently we do not have a syntax to perform super extension call
|
||||
// that's why we've used to just fail with an exception in case we have extension function in for JS IR compilation
|
||||
// TODO: that was overkill, however, we still need to revisit this issue later on
|
||||
params.forEachIndexed { i, variable -> putValueArgument(i, irGet(variable)) }
|
||||
private fun IrBuilderWithScope.createDefaultResolutionExpression(
|
||||
defaultExpression: IrExpression?,
|
||||
toParameter: IrValueParameter,
|
||||
): IrExpression? {
|
||||
return defaultExpression?.let {
|
||||
irIfThenElse(
|
||||
toParameter.type,
|
||||
irEqeqeqWithoutBox(
|
||||
irGet(toParameter, toParameter.type),
|
||||
this@JsDefaultArgumentStubGenerator.context.getVoid()
|
||||
),
|
||||
it,
|
||||
irGet(toParameter)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun IrExpression.prepareToBeUsedIn(function: IrFunction): IrExpression {
|
||||
return deepCopyWithVariables().also {
|
||||
it.patchDeclarationParents(function)
|
||||
private fun IrBuilderWithScope.createResolutionStatement(
|
||||
parameter: IrValueParameter,
|
||||
defaultExpression: IrExpression?,
|
||||
): IrSetValue? {
|
||||
return createDefaultResolutionExpression(defaultExpression, parameter)?.let {
|
||||
JsIrBuilder.buildSetValue(parameter.symbol, it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveInvoke(paramCount: Int): IrSimpleFunction {
|
||||
assert(paramCount > 0)
|
||||
val functionKlass = context.ir.symbols.functionN(paramCount).owner
|
||||
return functionKlass.declarations.filterIsInstance<IrSimpleFunction>().first { it.name == Name.identifier("invoke") }
|
||||
}
|
||||
}
|
||||
private fun IrFunction.introduceDefaultResolution(): IrFunction {
|
||||
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
|
||||
|
||||
class JsDefaultCallbackGenerator(val context: JsIrBackendContext): BodyLoweringPass {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
super.visitCall(expression)
|
||||
if (expression.origin != LoweredStatementOrigins.DEFAULT_DISPATCH_CALL || expression.superQualifierSymbol == null) return expression
|
||||
val variables = mutableMapOf<IrValueParameter, IrValueParameter>()
|
||||
|
||||
val binding = buildBoundSuperCall(expression)
|
||||
valueParameters = valueParameters.map { param ->
|
||||
param.takeIf { it.defaultValue != null }
|
||||
?.copyTo(this, isAssignable = true, origin = JsLoweredDeclarationOrigin.JS_SHADOWED_DEFAULT_PARAMETER)
|
||||
?.also { new -> variables[param] = new } ?: param
|
||||
}
|
||||
|
||||
expression.putValueArgument(expression.valueArgumentsCount - 1, binding)
|
||||
val defaultResolutionStatements = valueParameters.mapNotNull {
|
||||
irBuilder.createResolutionStatement(it, it.defaultValue?.expression)
|
||||
}
|
||||
|
||||
return expression
|
||||
if (variables.isNotEmpty()) {
|
||||
body?.transformChildren(VariableRemapper(variables), null)
|
||||
|
||||
body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||
statements += defaultResolutionStatements
|
||||
statements += body?.statements ?: emptyList()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun buildBoundSuperCall(irCall: IrCall): IrExpression {
|
||||
|
||||
val originalFunction = context.mapping.defaultArgumentsOriginalFunction[irCall.symbol.owner]!!
|
||||
|
||||
val reference = irCall.run {
|
||||
IrFunctionReferenceImpl(
|
||||
startOffset,
|
||||
endOffset,
|
||||
context.irBuiltIns.anyType,
|
||||
originalFunction.symbol,
|
||||
typeArgumentsCount = 0,
|
||||
valueArgumentsCount = originalFunction.valueParameters.size,
|
||||
reflectionTarget = originalFunction.symbol,
|
||||
origin = JsStatementOrigins.BIND_CALL
|
||||
)
|
||||
}
|
||||
|
||||
return irCall.run {
|
||||
IrCallImpl(
|
||||
startOffset,
|
||||
endOffset,
|
||||
context.irBuiltIns.anyType,
|
||||
context.intrinsics.jsBind,
|
||||
valueArgumentsCount = 2,
|
||||
typeArgumentsCount = 0,
|
||||
origin = JsStatementOrigins.BIND_CALL,
|
||||
superQualifierSymbol = superQualifierSymbol
|
||||
)
|
||||
}.apply {
|
||||
putValueArgument(0, irCall.dispatchReceiver?.deepCopyWithSymbols())
|
||||
putValueArgument(1, reference)
|
||||
return also {
|
||||
context.mapping.defaultArgumentsDispatchFunction[it] = it
|
||||
}
|
||||
}
|
||||
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (declaration !is IrFunction || declaration.isExternalOrInheritedFromExternal()) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (declaration.hasDefaultArgs() && (declaration is IrConstructor || declaration.isTopLevel)) {
|
||||
return listOf(declaration.introduceDefaultResolution())
|
||||
}
|
||||
|
||||
val (originalFun, defaultFunStub) = super.transformFlat(declaration) ?: return null
|
||||
|
||||
if (originalFun !is IrFunction || defaultFunStub !is IrFunction) {
|
||||
return listOf(originalFun, defaultFunStub)
|
||||
}
|
||||
|
||||
if (!defaultFunStub.isFakeOverride) {
|
||||
with(defaultFunStub) {
|
||||
valueParameters.forEach {
|
||||
if (it.defaultValue != null) {
|
||||
it.origin = JsLoweredDeclarationOrigin.JS_SHADOWED_DEFAULT_PARAMETER
|
||||
}
|
||||
it.defaultValue = null
|
||||
}
|
||||
|
||||
if (originalFun.isExported(context)) {
|
||||
context.additionalExportedDeclarations.add(defaultFunStub)
|
||||
|
||||
if (!originalFun.hasAnnotation(JsAnnotations.jsNameFqn)) {
|
||||
annotations += originalFun.generateJsNameAnnotationCall()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val (exportAnnotations, irrelevantAnnotations) = originalFun.annotations
|
||||
.map { it.deepCopyWithSymbols(originalFun as? IrDeclarationParent) }
|
||||
.partition {
|
||||
it.isAnnotation(JsAnnotations.jsExportFqn) || (it.isAnnotation(JsAnnotations.jsNameFqn))
|
||||
}
|
||||
|
||||
originalFun.annotations = irrelevantAnnotations
|
||||
defaultFunStub.annotations += exportAnnotations
|
||||
originalFun.origin = JsLoweredDeclarationOrigin.JS_SHADOWED_EXPORT
|
||||
|
||||
return listOf(originalFun, defaultFunStub)
|
||||
}
|
||||
|
||||
override fun IrFunction.generateDefaultStubBody(originalDeclaration: IrFunction): IrBody {
|
||||
val ctx = context
|
||||
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
|
||||
|
||||
val variables = mutableMapOf<IrValueParameter, IrValueDeclaration>().apply {
|
||||
originalDeclaration.dispatchReceiverParameter?.let {
|
||||
set(it, dispatchReceiverParameter!!)
|
||||
}
|
||||
originalDeclaration.extensionReceiverParameter?.let {
|
||||
set(it, extensionReceiverParameter!!)
|
||||
}
|
||||
originalDeclaration.valueParameters.forEachIndexed { index, param ->
|
||||
set(param, valueParameters[index])
|
||||
}
|
||||
}
|
||||
|
||||
return irBuilder.irBlockBody(this) {
|
||||
+valueParameters.zip(originalDeclaration.valueParameters)
|
||||
.mapNotNull { (new, original) ->
|
||||
createResolutionStatement(
|
||||
new,
|
||||
original.defaultValue?.expression?.transform(VariableRemapper(variables), null),
|
||||
)
|
||||
}
|
||||
|
||||
val wrappedFunctionCall = irCall(originalDeclaration, JsStatementOrigins.IMPLEMENTATION_DELEGATION_CALL).apply {
|
||||
passTypeArgumentsFrom(originalDeclaration)
|
||||
dispatchReceiver = dispatchReceiverParameter?.let { irGet(it) }
|
||||
extensionReceiver = extensionReceiverParameter?.let { irGet(it) }
|
||||
|
||||
originalDeclaration.valueParameters.forEachIndexed { index, irValueParameter ->
|
||||
putValueArgument(index, irGet(variables[irValueParameter] ?: valueParameters[index]))
|
||||
}
|
||||
}
|
||||
|
||||
var superContextValueParam: IrValueParameter? = null
|
||||
|
||||
val superFunCall = runIf(wrappedFunctionCall.dispatchReceiver != null && !originalDeclaration.isExported(ctx)) {
|
||||
val superContext = valueParameters.last().also {
|
||||
superContextValueParam = it
|
||||
}
|
||||
val realOverrideTarget = originalDeclaration.realOverrideTarget.takeIf {
|
||||
it !is IrOverridableMember || it.modality !== Modality.ABSTRACT
|
||||
}
|
||||
if (realOverrideTarget?.parentClassOrNull?.isInterface == true) {
|
||||
irCall(realOverrideTarget).apply {
|
||||
extensionReceiver = wrappedFunctionCall.extensionReceiver?.deepCopyWithSymbols()
|
||||
(0 until wrappedFunctionCall.valueArgumentsCount).forEach {
|
||||
putValueArgument(it, wrappedFunctionCall.getValueArgument(it)?.deepCopyWithSymbols())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
irCall(ctx.intrinsics.jsCall).apply {
|
||||
putValueArgument(0, wrappedFunctionCall.dispatchReceiver!!.deepCopyWithSymbols())
|
||||
putValueArgument(
|
||||
1,
|
||||
irCall(ctx.intrinsics.jsContexfulRef).apply {
|
||||
putValueArgument(0, irGet(superContext))
|
||||
putValueArgument(1, irRawFunctionReference(ctx.dynamicType, originalDeclaration.symbol))
|
||||
}
|
||||
)
|
||||
putValueArgument(2, irVararg(ctx.dynamicType, buildList {
|
||||
addIfNotNull(wrappedFunctionCall.extensionReceiver?.deepCopyWithSymbols())
|
||||
(0 until wrappedFunctionCall.valueArgumentsCount).forEach {
|
||||
addIfNotNull(wrappedFunctionCall.getValueArgument(it)?.deepCopyWithSymbols())
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+irReturn(
|
||||
if (superFunCall == null) {
|
||||
wrappedFunctionCall
|
||||
} else {
|
||||
irIfThenElse(
|
||||
originalDeclaration.returnType,
|
||||
irEqeqeqWithoutBox(irGet(superContextValueParam!!), ctx.getVoid()),
|
||||
wrappedFunctionCall,
|
||||
superFunCall
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrFunction.generateJsNameAnnotationCall(): IrConstructorCall {
|
||||
val builder = context.createIrBuilder(symbol, startOffset, endOffset)
|
||||
|
||||
return with(context) {
|
||||
builder.irCall(intrinsics.jsNameAnnotationSymbol.constructors.single())
|
||||
.apply {
|
||||
putValueArgument(
|
||||
0,
|
||||
IrConstImpl.string(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irBuiltIns.stringType, name.identifier)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrConstructorCall.isAnnotation(name: FqName): Boolean {
|
||||
return symbol.owner.parentAsClass.fqNameWhenAvailable == name
|
||||
}
|
||||
|
||||
private fun IrFunction.hasDefaultArgs(): Boolean =
|
||||
valueParameters.any { it.defaultValue != null }
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.lower.DefaultParameterInjector
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getVoid
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.util.copyAnnotations
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.isTopLevel
|
||||
import org.jetbrains.kotlin.ir.util.isVararg
|
||||
|
||||
class JsDefaultParameterInjector(override val context: JsIrBackendContext) :
|
||||
DefaultParameterInjector(
|
||||
context,
|
||||
skipExternalMethods = true,
|
||||
forceSetOverrideSymbols = false,
|
||||
factory = JsDefaultArgumentFunctionFactory(context)
|
||||
) {
|
||||
override fun nullConst(startOffset: Int, endOffset: Int, irParameter: IrValueParameter): IrExpression? =
|
||||
if (irParameter.isVararg && !irParameter.hasDefaultValue()) {
|
||||
null
|
||||
} else {
|
||||
context.getVoid()
|
||||
}
|
||||
|
||||
override fun shouldReplaceWithSyntheticFunction(functionAccess: IrFunctionAccessExpression): Boolean {
|
||||
return super.shouldReplaceWithSyntheticFunction(functionAccess) || functionAccess.symbol.owner.run {
|
||||
origin == JsLoweredDeclarationOrigin.JS_SHADOWED_EXPORT &&
|
||||
!isTopLevel &&
|
||||
functionAccess.origin != JsStatementOrigins.IMPLEMENTATION_DELEGATION_CALL &&
|
||||
isExported(context)
|
||||
}
|
||||
}
|
||||
|
||||
override fun parametersForCall(expression: IrFunctionAccessExpression): Pair<IrFunctionSymbol, List<IrExpression?>>? {
|
||||
val startOffset = expression.startOffset
|
||||
val endOffset = expression.endOffset
|
||||
val declaration = expression.symbol.owner
|
||||
|
||||
val stubFunction = factory.findBaseFunctionWithDefaultArgumentsFor(declaration, skipInline, skipExternalMethods)?.let {
|
||||
factory.generateDefaultsFunction(
|
||||
it,
|
||||
skipInline,
|
||||
skipExternalMethods,
|
||||
forceSetOverrideSymbols,
|
||||
defaultArgumentStubVisibility(declaration),
|
||||
useConstructorMarker(declaration),
|
||||
it.copyAnnotations(),
|
||||
)
|
||||
} ?: return null
|
||||
|
||||
return stubFunction.symbol to buildList {
|
||||
for (i in 0 until expression.valueArgumentsCount) {
|
||||
val declaredParameter = stubFunction.valueParameters[i]
|
||||
val actualParameter = expression.getValueArgument(i)
|
||||
add(actualParameter ?: nullConst(startOffset, endOffset, declaredParameter))
|
||||
}
|
||||
|
||||
if (expression is IrCall && stubFunction.hasSuperContextParameter()) {
|
||||
add(expression.superQualifierSymbol?.prototypeOf() ?: context.getVoid())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrFunction.hasSuperContextParameter(): Boolean {
|
||||
return valueParameters.lastOrNull()?.origin == JsLoweredDeclarationOrigin.JS_SUPER_CONTEXT_PARAMETER
|
||||
}
|
||||
|
||||
private fun IrClassSymbol.prototypeOf(): IrExpression {
|
||||
return IrCallImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
context.dynamicType,
|
||||
context.intrinsics.jsPrototypeOfSymbol,
|
||||
0,
|
||||
1
|
||||
).apply {
|
||||
putValueArgument(
|
||||
0,
|
||||
IrCallImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
context.dynamicType,
|
||||
context.intrinsics.jsClass,
|
||||
1,
|
||||
0
|
||||
).apply {
|
||||
putTypeArgument(0, owner.defaultType)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrValueParameter.hasDefaultValue(): Boolean =
|
||||
origin == JsLoweredDeclarationOrigin.JS_SHADOWED_DEFAULT_PARAMETER
|
||||
}
|
||||
|
||||
+5
@@ -24,6 +24,11 @@ class JsPropertyAccessorInlineLowering(
|
||||
if (!isTopLevel && !context.icCompatibleIr2Js.incrementalCacheEnabled)
|
||||
return true
|
||||
|
||||
// Just undefined value
|
||||
if (symbol == context.intrinsics.void) {
|
||||
return true
|
||||
}
|
||||
|
||||
// TODO: teach the deserializer to load constant property initializers
|
||||
if (context.icCompatibleIr2Js.isCompatible) {
|
||||
val accessFile = accessContainer.fileOrNull ?: return false
|
||||
|
||||
+4
-1
@@ -52,8 +52,11 @@ private val JsPackage = FqName("kotlin.js")
|
||||
|
||||
private val JsIntrinsicFqName = FqName("kotlin.js.JsIntrinsic")
|
||||
|
||||
private fun IrDeclaration.isPlacedInsideInternalPackage() =
|
||||
(parent as? IrPackageFragment)?.fqName == JsPackage
|
||||
|
||||
private fun isIntrinsic(declaration: IrDeclaration): Boolean =
|
||||
declaration is IrSimpleFunction && (declaration.parent as? IrPackageFragment)?.fqName == JsPackage &&
|
||||
declaration is IrSimpleFunction && declaration.isPlacedInsideInternalPackage() &&
|
||||
declaration.annotations.any { it.symbol.owner.constructedClass.fqNameWhenAvailable == JsIntrinsicFqName }
|
||||
|
||||
fun moveBodilessDeclarationsToSeparatePlace(context: JsIrBackendContext, moduleFragment: IrModuleFragment) {
|
||||
|
||||
+1
-1
@@ -86,7 +86,7 @@ class SecondaryConstructorLowering(val context: JsIrBackendContext) : Declaratio
|
||||
private fun generateFactoryBody(constructor: IrConstructor, irClass: IrClass, stub: IrSimpleFunction, delegate: IrSimpleFunction) {
|
||||
stub.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||
val type = irClass.defaultType
|
||||
val createFunctionIntrinsic = context.intrinsics.jsObjectCreate
|
||||
val createFunctionIntrinsic = context.intrinsics.jsObjectCreateSymbol
|
||||
val irCreateCall = JsIrBuilder.buildCall(createFunctionIntrinsic, type, listOf(type))
|
||||
val irDelegateCall = JsIrBuilder.buildCall(delegate.symbol, type).also { call ->
|
||||
for (i in 0 until stub.typeParameters.size) {
|
||||
|
||||
+2
-3
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getVoid
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent
|
||||
@@ -28,10 +29,8 @@ class ThrowableLowering(
|
||||
|
||||
private val throwableConstructors = context.throwableConstructors
|
||||
private val newThrowableFunction = context.newThrowableSymbol
|
||||
private val jsUndefined = context.intrinsics.jsUndefined
|
||||
|
||||
fun nullValue(): IrExpression = IrConstImpl.constNull(UNDEFINED_OFFSET, UNDEFINED_OFFSET, nothingNType)
|
||||
fun undefinedValue(): IrExpression = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, nothingNType, jsUndefined, 0, 0)
|
||||
private fun undefinedValue(): IrExpression = context.getVoid()
|
||||
|
||||
data class ThrowableArguments(
|
||||
val message: IrExpression,
|
||||
|
||||
+1
-1
@@ -158,7 +158,7 @@ class IrModuleToJsTransformer(
|
||||
val moduleBody = generateModuleBody(modules, staticContext)
|
||||
val internalModuleName = ReservedJsNames.makeInternalModuleName()
|
||||
val globalNames = NameTable<String>(namer.globalNames)
|
||||
val exportStatements = ExportModelToJsStatements(nameGenerator) { globalNames.declareFreshName(it, it) }
|
||||
val exportStatements = ExportModelToJsStatements(staticContext) { globalNames.declareFreshName(it, it) }
|
||||
.generateModuleExport(exportedModule, internalModuleName)
|
||||
|
||||
val (crossModuleImports, importedKotlinModules) = generateCrossModuleImports(nameGenerator, modules, dependencies, { JsName(sanitizeName(it), false) })
|
||||
|
||||
+6
-3
@@ -38,7 +38,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
private val baseClassRef by lazy { // Lazy in case was not collected by namer during JsClassGenerator construction
|
||||
if (baseClass != null && !baseClass.isAny()) baseClass.getClassRef(context) else null
|
||||
}
|
||||
private val classPrototypeRef = prototypeOf(classNameRef)
|
||||
private val classPrototypeRef = prototypeOf(classNameRef, context.staticContext)
|
||||
private val classBlock = JsCompositeBlock()
|
||||
private val classModel = JsIrClassModel(irClass)
|
||||
|
||||
@@ -202,7 +202,8 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
classPrototypeRef,
|
||||
context.getNameForProperty(property).ident,
|
||||
getter = getterForwarder,
|
||||
setter = setterForwarder
|
||||
setter = setterForwarder,
|
||||
context.staticContext
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -328,11 +329,13 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
val associatedObjects = generateAssociatedObjects()
|
||||
val suspendArity = generateSuspendArity()
|
||||
|
||||
val undefined = context.staticContext.backendContext.getVoid().accept(IrElementToJsExpressionTransformer(), context)
|
||||
|
||||
return JsInvocation(
|
||||
JsNameRef(context.getNameForStaticFunction(setMetadataFor)),
|
||||
listOf(ctor, name, metadataConstructor, parent, interfaces, associatedObjectKey, associatedObjects, suspendArity)
|
||||
.dropLastWhile { it == null }
|
||||
.map { it ?: Namer.JS_UNDEFINED }
|
||||
.map { it ?: undefined }
|
||||
).makeStmt()
|
||||
|
||||
}
|
||||
|
||||
+24
-8
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||
import org.jetbrains.kotlin.ir.expressions.IrRawFunctionReference
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
@@ -86,11 +87,10 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
|
||||
prefixOp(intrinsics.jsTypeOf, JsUnaryOperator.TYPEOF)
|
||||
|
||||
add(intrinsics.jsObjectCreate) { call, context ->
|
||||
add(intrinsics.jsObjectCreateSymbol) { call, context ->
|
||||
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)
|
||||
objectCreate(prototypeOf(className.makeRef(), context.staticContext), context.staticContext)
|
||||
}
|
||||
|
||||
add(intrinsics.jsClass) { call, context ->
|
||||
@@ -194,6 +194,16 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
JsNameRef(fieldName, arg)
|
||||
}
|
||||
|
||||
add(intrinsics.jsCall) { call, context: JsGenerationContext ->
|
||||
val args = translateCallArguments(call, context)
|
||||
val receiver = args[0]
|
||||
val target = args[1]
|
||||
val varargs = args[2] as? JsArrayLiteral ?: error("Expect to have JsArrayLiteral, because of vararg with dynamic element type")
|
||||
|
||||
val callRef = JsNameRef(Namer.CALL_FUNCTION, target)
|
||||
JsInvocation(callRef, receiver, *varargs.expressions.toTypedArray())
|
||||
}
|
||||
|
||||
add(intrinsics.jsBind) { call, context: JsGenerationContext ->
|
||||
val receiver = call.getValueArgument(0)!!
|
||||
val jsReceiver = receiver.accept(IrElementToJsExpressionTransformer(), context)
|
||||
@@ -202,7 +212,7 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
val superClass = call.superQualifierSymbol!!
|
||||
val functionName = context.getNameForMemberFunction(target.symbol.owner as IrSimpleFunction)
|
||||
val superName = context.getNameForClass(superClass.owner).makeRef()
|
||||
JsNameRef(functionName, prototypeOf(superName))
|
||||
JsNameRef(functionName, prototypeOf(superName, context.staticContext))
|
||||
}
|
||||
is IrFunctionExpression -> target.accept(IrElementToJsExpressionTransformer(), context)
|
||||
else -> compilationException(
|
||||
@@ -214,6 +224,15 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
JsInvocation(bindRef, jsReceiver)
|
||||
}
|
||||
|
||||
add(intrinsics.jsContexfulRef) { call, context: JsGenerationContext ->
|
||||
val receiver = call.getValueArgument(0)!!
|
||||
val jsReceiver = receiver.accept(IrElementToJsExpressionTransformer(), context)
|
||||
val target = call.getValueArgument(1) as IrRawFunctionReference
|
||||
val jsTarget = context.getNameForMemberFunction(target.symbol.owner as IrSimpleFunction)
|
||||
|
||||
JsNameRef(jsTarget, jsReceiver)
|
||||
}
|
||||
|
||||
add(intrinsics.unreachable) { _, _ ->
|
||||
JsInvocation(JsNameRef(Namer.UNREACHABLE_NAME))
|
||||
}
|
||||
@@ -234,9 +253,6 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
val value = args[1]
|
||||
jsAssignment(JsNameRef(Namer.SHARED_BOX_V, box), value)
|
||||
}
|
||||
add(intrinsics.jsUndefined) { _, _ ->
|
||||
JsPrefixOperation(JsUnaryOperator.VOID, JsIntLiteral(1))
|
||||
}
|
||||
|
||||
val suspendInvokeTransform: (IrCall, JsGenerationContext) -> JsExpression = { call, context: JsGenerationContext ->
|
||||
// Because it is intrinsic, we know everything about this function
|
||||
@@ -263,7 +279,7 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
}
|
||||
|
||||
private fun translateCallArguments(expression: IrCall, context: JsGenerationContext): List<JsExpression> {
|
||||
return translateCallArguments(expression, context, IrElementToJsExpressionTransformer())
|
||||
return translateCallArguments(expression, context, IrElementToJsExpressionTransformer(), false)
|
||||
}
|
||||
|
||||
private fun MutableMap<IrSymbol, IrCallTransformer>.add(functionSymbol: IrSymbol, t: IrCallTransformer) {
|
||||
|
||||
+55
-26
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.common.compilationException
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrFileEntry
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
||||
import org.jetbrains.kotlin.ir.backend.js.sourceMapsInfo
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
@@ -31,6 +32,14 @@ import java.io.IOException
|
||||
import java.io.InputStreamReader
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
|
||||
fun jsUndefined(context: IrNamer, backendContext: JsIrBackendContext): JsExpression {
|
||||
return when (val void = backendContext.getVoid()) {
|
||||
is IrGetField -> context.getNameForField(void.symbol.owner).makeRef()
|
||||
else -> JsNullLiteral()
|
||||
}
|
||||
}
|
||||
|
||||
fun jsVar(name: JsName, initializer: IrExpression?, context: JsGenerationContext): JsVars {
|
||||
val jsInitializer = initializer?.accept(IrElementToJsExpressionTransformer(), context)
|
||||
return JsVars(JsVars.JsVar(name, jsInitializer))
|
||||
@@ -63,7 +72,34 @@ fun jsElementAccess(name: JsName, receiver: JsExpression?): JsExpression =
|
||||
|
||||
fun jsAssignment(left: JsExpression, right: JsExpression) = JsBinaryOperation(JsBinaryOperator.ASG, left, right)
|
||||
|
||||
fun prototypeOf(classNameRef: JsExpression) = JsNameRef(Namer.PROTOTYPE_NAME, classNameRef)
|
||||
fun prototypeOf(classNameRef: JsExpression, context: JsStaticContext) =
|
||||
JsInvocation(
|
||||
context
|
||||
.getNameForStaticFunction(context.backendContext.intrinsics.jsPrototypeOfSymbol.owner)
|
||||
.makeRef(),
|
||||
classNameRef
|
||||
)
|
||||
|
||||
fun objectCreate(prototype: JsExpression, context: JsStaticContext) =
|
||||
JsInvocation(
|
||||
context
|
||||
.getNameForStaticFunction(context.backendContext.intrinsics.jsObjectCreateSymbol.owner)
|
||||
.makeRef(),
|
||||
prototype
|
||||
)
|
||||
|
||||
fun defineProperty(obj: JsExpression, name: String, getter: JsExpression?, setter: JsExpression?, context: JsStaticContext) =
|
||||
JsInvocation(
|
||||
context
|
||||
.getNameForStaticFunction(context.backendContext.intrinsics.jsDefinePropertySymbol.owner)
|
||||
.makeRef(),
|
||||
obj,
|
||||
JsStringLiteral(name),
|
||||
*listOf(getter, setter)
|
||||
.dropLastWhile { it == null }
|
||||
.map { it ?: jsUndefined(context, context.backendContext) }
|
||||
.toTypedArray()
|
||||
)
|
||||
|
||||
fun translateFunction(declaration: IrFunction, name: JsName?, context: JsGenerationContext): JsFunction {
|
||||
context.staticContext.backendContext.getJsCodeForFunction(declaration.symbol)?.let { function ->
|
||||
@@ -167,7 +203,7 @@ fun translateCall(
|
||||
} else {
|
||||
val qualifierName = context.getNameForClass(klass).makeRef()
|
||||
val targetName = context.getNameForMemberFunction(target)
|
||||
val qPrototype = JsNameRef(targetName, prototypeOf(qualifierName))
|
||||
val qPrototype = JsNameRef(targetName, prototypeOf(qualifierName, context.staticContext))
|
||||
JsNameRef(Namer.CALL_FUNCTION, qPrototype)
|
||||
}
|
||||
|
||||
@@ -336,6 +372,7 @@ fun translateCallArguments(
|
||||
expression: IrMemberAccessExpression<IrFunctionSymbol>,
|
||||
context: JsGenerationContext,
|
||||
transformer: IrElementToJsExpressionTransformer,
|
||||
allowDropTailVoids: Boolean = true
|
||||
): List<JsExpression> {
|
||||
val size = expression.valueArgumentsCount
|
||||
|
||||
@@ -344,13 +381,15 @@ fun translateCallArguments(
|
||||
val validWithNullArgs = expression.validWithNullArgs()
|
||||
val arguments = (0 until size)
|
||||
.mapTo(ArrayList(size)) { index ->
|
||||
val argument = expression.getValueArgument(index)
|
||||
argument?.accept(transformer, context)
|
||||
expression.getValueArgument(index).checkOnNullability(validWithNullArgs)
|
||||
}
|
||||
.onEach { result ->
|
||||
if (result == null) {
|
||||
assert(validWithNullArgs)
|
||||
}
|
||||
.dropLastWhile {
|
||||
allowDropTailVoids &&
|
||||
it is IrGetField &&
|
||||
it.symbol.owner.correspondingPropertySymbol == context.staticContext.backendContext.intrinsics.void
|
||||
}
|
||||
.map {
|
||||
it?.accept(transformer, context)
|
||||
}
|
||||
.mapIndexed { index, result ->
|
||||
val isEmptyExternalVararg = validWithNullArgs &&
|
||||
@@ -363,34 +402,24 @@ fun translateCallArguments(
|
||||
} else result
|
||||
}
|
||||
.dropLastWhile { it == null }
|
||||
.map { it ?: JsPrefixOperation(JsUnaryOperator.VOID, JsIntLiteral(1)) }
|
||||
.map { it ?: jsUndefined(context, context.staticContext.backendContext) }
|
||||
|
||||
check(!expression.symbol.isSuspend) { "Suspend functions should be lowered" }
|
||||
return arguments
|
||||
}
|
||||
|
||||
private fun IrExpression?.checkOnNullability(validWithNullArgs: Boolean) =
|
||||
also {
|
||||
if (it == null) {
|
||||
assert(validWithNullArgs)
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrMemberAccessExpression<*>.validWithNullArgs() =
|
||||
this is IrFunctionAccessExpression && symbol.owner.isExternalOrInheritedFromExternal()
|
||||
|
||||
fun JsStatement.asBlock() = this as? JsBlock ?: JsBlock(this)
|
||||
|
||||
fun defineProperty(receiver: JsExpression, name: String, value: () -> JsExpression): JsInvocation {
|
||||
val objectDefineProperty = JsNameRef("defineProperty", Namer.JS_OBJECT)
|
||||
return JsInvocation(objectDefineProperty, receiver, JsStringLiteral(name), value())
|
||||
}
|
||||
|
||||
fun defineProperty(receiver: JsExpression, name: String, getter: JsExpression?, setter: JsExpression? = null) =
|
||||
defineProperty(receiver, name) {
|
||||
JsObjectLiteral(true).apply {
|
||||
propertyInitializers += JsPropertyInitializer(JsStringLiteral("configurable"), JsBooleanLiteral(true))
|
||||
if (getter != null)
|
||||
propertyInitializers += JsPropertyInitializer(JsStringLiteral("get"), getter)
|
||||
if (setter != null)
|
||||
propertyInitializers += JsPropertyInitializer(JsStringLiteral("set"), setter)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Partially copied from org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||
object JsAstUtils {
|
||||
private fun deBlockIfPossible(statement: JsStatement): JsStatement {
|
||||
|
||||
@@ -7,10 +7,14 @@ package org.jetbrains.kotlin.ir.backend.js.utils
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.isClass
|
||||
import org.jetbrains.kotlin.descriptors.isInterface
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrReturn
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
|
||||
import org.jetbrains.kotlin.ir.util.parentClassOrNull
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -41,3 +45,18 @@ fun IrDeclarationWithName.getFqNameWithJsNameWhenAvailable(shouldIncludePackage:
|
||||
private fun getKotlinOrJsQualifier(parent: IrPackageFragment, shouldIncludePackage: Boolean): FqName? {
|
||||
return (parent as? IrFile)?.getJsQualifier()?.let { FqName(it) } ?: parent.fqName.takeIf { shouldIncludePackage }
|
||||
}
|
||||
|
||||
// TODO: the code is written to pass Repl tests, so we should understand. why in Repl tests we don't have backingField
|
||||
fun JsIrBackendContext.getVoid(): IrExpression =
|
||||
intrinsics.void.owner.backingField?.let {
|
||||
IrGetFieldImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
it.symbol,
|
||||
irBuiltIns.nothingNType
|
||||
)
|
||||
} ?: IrConstImpl.constNull(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
irBuiltIns.nothingNType
|
||||
)
|
||||
|
||||
@@ -136,7 +136,10 @@ fun calculateJsFunctionSignature(declaration: IrFunction, context: JsIrBackendCo
|
||||
nameBuilder.append("_r$${it.type.asString()}")
|
||||
}
|
||||
declaration.valueParameters.ifNotEmpty {
|
||||
joinTo(nameBuilder, "") { "_${it.type.asString()}" }
|
||||
joinTo(nameBuilder, "") {
|
||||
val defaultValueSign = if (it.origin == JsLoweredDeclarationOrigin.JS_SHADOWED_DEFAULT_PARAMETER) "?" else ""
|
||||
"_${it.type.asString()}$defaultValueSign"
|
||||
}
|
||||
}
|
||||
declaration.returnType.let {
|
||||
// Return type is only used in signature for inline class and Unit types because
|
||||
|
||||
@@ -27,12 +27,7 @@ object Namer {
|
||||
|
||||
val JS_ERROR = JsNameRef("Error")
|
||||
|
||||
val JS_OBJECT = JsNameRef("Object")
|
||||
val JS_UNDEFINED = JsNameRef("undefined")
|
||||
val JS_OBJECT_CREATE_FUNCTION = JsNameRef("create", JS_OBJECT)
|
||||
|
||||
val METADATA = "\$metadata\$"
|
||||
val INTERFACES_MASK = "\$imask\$"
|
||||
|
||||
val KCALLABLE_GET_NAME = "<get-name>"
|
||||
val KCALLABLE_NAME = "callableName"
|
||||
|
||||
@@ -38,7 +38,6 @@ fun IrFunction.hasStableJsName(context: JsIrBackendContext): Boolean {
|
||||
|
||||
if (
|
||||
origin == JsLoweredDeclarationOrigin.JS_SHADOWED_EXPORT ||
|
||||
origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER ||
|
||||
origin == JsLoweredDeclarationOrigin.BRIDGE_WITHOUT_STABLE_NAME ||
|
||||
origin == JsLoweredDeclarationOrigin.BRIDGE_PROPERTY_ACCESSOR
|
||||
) {
|
||||
|
||||
@@ -149,8 +149,8 @@ fun IrBuilderWithScope.irSet(variable: IrValueSymbol, value: IrExpression, origi
|
||||
fun IrBuilderWithScope.irSet(variable: IrValueDeclaration, value: IrExpression, origin: IrStatementOrigin = IrStatementOrigin.EQ) =
|
||||
irSet(variable.symbol, value, origin)
|
||||
|
||||
fun IrBuilderWithScope.irGetField(receiver: IrExpression?, field: IrField) =
|
||||
IrGetFieldImpl(startOffset, endOffset, field.symbol, field.type, receiver)
|
||||
fun IrBuilderWithScope.irGetField(receiver: IrExpression?, field: IrField, type: IrType = field.type) =
|
||||
IrGetFieldImpl(startOffset, endOffset, field.symbol, type, receiver)
|
||||
|
||||
fun IrBuilderWithScope.irSetField(receiver: IrExpression?, field: IrField, value: IrExpression, origin: IrStatementOrigin? = null) =
|
||||
IrSetFieldImpl(startOffset, endOffset, field.symbol, receiver, value, context.irBuiltIns.unitType, origin = origin)
|
||||
@@ -161,6 +161,17 @@ fun IrBuilderWithScope.irGetObjectValue(type: IrType, classSymbol: IrClassSymbol
|
||||
fun IrBuilderWithScope.irEqeqeq(arg1: IrExpression, arg2: IrExpression) =
|
||||
context.eqeqeq(startOffset, endOffset, arg1, arg2)
|
||||
|
||||
fun IrBuilderWithScope.irEqeqeqWithoutBox(arg1: IrExpression, arg2: IrExpression) =
|
||||
primitiveOp2(
|
||||
startOffset,
|
||||
endOffset,
|
||||
context.irBuiltIns.eqeqeqSymbol,
|
||||
context.irBuiltIns.booleanType,
|
||||
IrStatementOrigin.SYNTHETIC_NOT_AUTOBOXED_CHECK,
|
||||
arg1,
|
||||
arg2
|
||||
)
|
||||
|
||||
fun IrBuilderWithScope.irNull() =
|
||||
irNull(context.irBuiltIns.nothingNType)
|
||||
|
||||
|
||||
@@ -54,6 +54,10 @@ abstract class IrStatementsBuilder<out T : IrElement>(
|
||||
addStatement(this)
|
||||
}
|
||||
|
||||
operator fun List<IrStatement>.unaryPlus() {
|
||||
forEach(::addStatement)
|
||||
}
|
||||
|
||||
protected abstract fun addStatement(irStatement: IrStatement)
|
||||
abstract fun doBuild(): T
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.expressions
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
|
||||
|
||||
abstract class IrStatementOriginImpl(val debugName: String) : IrStatementOrigin {
|
||||
override fun toString(): String = debugName
|
||||
}
|
||||
@@ -90,6 +92,8 @@ interface IrStatementOrigin {
|
||||
|
||||
object BRIDGE_DELEGATION : IrStatementOriginImpl("BRIDGE_DELEGATION")
|
||||
|
||||
object SYNTHETIC_NOT_AUTOBOXED_CHECK : IrStatementOriginImpl("SYNTHETIC_NOT_AUTOBOXED_CHECK")
|
||||
|
||||
data class COMPONENT_N private constructor(val index: Int) : IrStatementOriginImpl("COMPONENT_$index") {
|
||||
companion object {
|
||||
private val precreatedComponents = Array(32) { i -> COMPONENT_N(i + 1) }
|
||||
|
||||
+1
@@ -19,4 +19,5 @@ interface JsStatementOrigins {
|
||||
object COROUTINE_ROOT_LOOP : IrStatementOriginImpl("COROUTINE_ROOT_LOOP")
|
||||
object COROUTINE_SWITCH : IrStatementOriginImpl("COROUTINE_SWITCH")
|
||||
object CLASS_REFERENCE : IrStatementOriginImpl("CLASS_REFERENCE")
|
||||
object IMPLEMENTATION_DELEGATION_CALL : IrStatementOriginImpl("IMPLEMENTATION_DELEGATION_CALL")
|
||||
}
|
||||
@@ -90,7 +90,8 @@ fun trimMarginConstantCustomPrefixInterpolatedUsingConstant(): String {
|
||||
""".trimMargin(marginPrefix = "$OCTOTHORPE@$OCTOTHORPE")
|
||||
}
|
||||
|
||||
// CHECK_CALLED_IN_SCOPE: function=trimMargin$default scope=trimMarginNotConstant
|
||||
// CHECK_CALLED_IN_SCOPE: function=trimMargin$default scope=trimMarginNotConstant IGNORED_BACKENDS=JS_IR
|
||||
// CHECK_CALLED_IN_SCOPE: function=trimMargin scope=trimMarginNotConstant TARGET_BACKENDS=JS_IR
|
||||
fun trimMarginNotConstant(arg: String): String {
|
||||
return arg.trimMargin()
|
||||
}
|
||||
@@ -100,7 +101,8 @@ fun trimMarginNotConstantCustomPrefix(arg: String): String {
|
||||
return arg.trimMargin("###")
|
||||
}
|
||||
|
||||
// CHECK_CALLED_IN_SCOPE: function=trimMargin$default scope=trimMarginInterpolated
|
||||
// CHECK_CALLED_IN_SCOPE: function=trimMargin$default scope=trimMarginInterpolated IGNORED_BACKENDS=JS_IR
|
||||
// CHECK_CALLED_IN_SCOPE: function=trimMargin scope=trimMarginInterpolated TARGET_BACKENDS=JS_IR
|
||||
fun trimMarginInterpolated(arg: Int): String {
|
||||
return """
|
||||
|Hello,
|
||||
|
||||
+2
-2
@@ -30,5 +30,5 @@ fun box() {
|
||||
// EXPECTATIONS JS_IR
|
||||
// test.kt:9 box
|
||||
// test.kt:11 box
|
||||
// test.kt:4 A.foo_26di_k$
|
||||
// test.kt:5 box
|
||||
// test.kt:4 protoOf.foo_26di_k$
|
||||
// test.kt:5 box
|
||||
+2
-2
@@ -32,9 +32,9 @@ fun box() {
|
||||
// EXPECTATIONS JS_IR
|
||||
// test.kt:9 box
|
||||
// test.kt:10 box
|
||||
// test.kt:4 A.foo_26di_k$
|
||||
// test.kt:4 protoOf.foo_26di_k$
|
||||
// test.kt:11 box
|
||||
// test.kt:4 A.foo_26di_k$
|
||||
// test.kt:4 protoOf.foo_26di_k$
|
||||
// test.kt:5 box
|
||||
// test.kt:13 box
|
||||
// test.kt:5 box
|
||||
|
||||
+1
-1
@@ -45,4 +45,4 @@ fun box() {
|
||||
// test.kt:15 box
|
||||
// test.kt:16 box
|
||||
// test.kt:16 box
|
||||
// test.kt:8 Companion_19.foo_26di_k$
|
||||
// test.kt:8 protoOf.foo_26di_k$
|
||||
+21
-23
@@ -68,29 +68,27 @@ fun box() {
|
||||
// test.kt:3 D
|
||||
// test.kt:3 D
|
||||
// test.kt:14 box
|
||||
// test.kt:1 D.equals
|
||||
// test.kt:1 D.equals
|
||||
// test.kt:1 D.equals
|
||||
// test.kt:1 D.equals
|
||||
// test.kt:1 D.equals
|
||||
// test.kt:1 D.equals
|
||||
// test.kt:1 protoOf.equals
|
||||
// test.kt:1 protoOf.equals
|
||||
// test.kt:1 protoOf.equals
|
||||
// test.kt:1 protoOf.equals
|
||||
// test.kt:1 protoOf.equals
|
||||
// test.kt:1 protoOf.equals
|
||||
// test.kt:15 box
|
||||
// test.kt:1 D.hashCode
|
||||
// test.kt:1 D.hashCode
|
||||
// test.kt:1 protoOf.hashCode
|
||||
// test.kt:1 protoOf.hashCode
|
||||
// test.kt:16 box
|
||||
// test.kt:1 D.toString
|
||||
// test.kt:1 protoOf.toString
|
||||
// test.kt:17 box
|
||||
// test.kt:17 box
|
||||
// test.kt:1 D.component1_7eebsc_k$
|
||||
// test.kt:1 protoOf.component1_7eebsc_k$
|
||||
// test.kt:17 box
|
||||
// test.kt:1 D.component2_7eebsb_k$
|
||||
// test.kt:1 protoOf.component2_7eebsb_k$
|
||||
// test.kt:18 box
|
||||
// test.kt:1 D.copy$default_cbhffz_k$
|
||||
// test.kt:1 D.copy$default_cbhffz_k$
|
||||
// test.kt:1 D.copy$default_cbhffz_k$
|
||||
// test.kt:1 D.copy$default_cbhffz_k$
|
||||
// test.kt:1 D.copy$default_cbhffz_k$
|
||||
// test.kt:1 D.copy_t8q04r_k$
|
||||
// test.kt:1 protoOf.copy$default_roih85_k$
|
||||
// test.kt:1 protoOf.copy$default_roih85_k$
|
||||
// test.kt:1 protoOf.copy$default_roih85_k$
|
||||
// test.kt:1 protoOf.copy_t8q04r_k$
|
||||
// test.kt:3 D
|
||||
// test.kt:3 D
|
||||
// test.kt:19 box
|
||||
@@ -100,17 +98,17 @@ fun box() {
|
||||
// test.kt:5 E
|
||||
// test.kt:5 E
|
||||
// test.kt:20 box
|
||||
// test.kt:7 E.equals
|
||||
// test.kt:7 protoOf.equals
|
||||
// test.kt:21 box
|
||||
// test.kt:8 E.hashCode
|
||||
// test.kt:8 protoOf.hashCode
|
||||
// test.kt:22 box
|
||||
// test.kt:6 E.toString
|
||||
// test.kt:6 protoOf.toString
|
||||
// test.kt:23 box
|
||||
// test.kt:23 box
|
||||
// test.kt:1 E.component1_7eebsc_k$
|
||||
// test.kt:1 protoOf.component1_7eebsc_k$
|
||||
// test.kt:23 box
|
||||
// test.kt:1 E.component2_7eebsb_k$
|
||||
// test.kt:1 protoOf.component2_7eebsb_k$
|
||||
// test.kt:24 box
|
||||
// test.kt:9 E.copy_1tks5_k$
|
||||
// test.kt:9 protoOf.copy_1tks5_k$
|
||||
// test.kt:5 E
|
||||
// test.kt:5 E
|
||||
|
||||
+5
-4
@@ -26,7 +26,8 @@ fun box() {
|
||||
// EXPECTATIONS JS_IR
|
||||
// test.kt:11 box
|
||||
// test.kt:11 box
|
||||
// test.kt:6 A.foo$default_dec9f7_k$
|
||||
// test.kt:6 A.foo$default_dec9f7_k$
|
||||
// test.kt:4 A.computeParam_vubdyi_k$
|
||||
// test.kt:6 A.foo$default_dec9f7_k$
|
||||
// test.kt:6 protoOf.foo$default_ourpn2_k$
|
||||
// test.kt:4 protoOf.computeParam_vubdyi_k$
|
||||
// test.kt:6 protoOf.foo$default_ourpn2_k$
|
||||
// test.kt:6 protoOf.foo$default_ourpn2_k$
|
||||
// test.kt:6 protoOf.foo$default_ourpn2_k$
|
||||
+1
-1
@@ -57,7 +57,7 @@ fun box() {
|
||||
// test.kt:11 E
|
||||
// test.kt:11 E
|
||||
// test.kt:22 box
|
||||
// test.kt:9 E.foo_26di_k$
|
||||
// test.kt:9 protoOf.foo_26di_k$
|
||||
// test.kt:15 E2_initEntries
|
||||
// test.kt:14 E2
|
||||
// test.kt:17 E2_initEntries
|
||||
|
||||
@@ -24,6 +24,4 @@ inline fun bar(i: Int = 1) {
|
||||
|
||||
// EXPECTATIONS JS_IR
|
||||
// test.kt:4 box
|
||||
// test.kt:8 foo$default
|
||||
// test.kt:8 foo$default
|
||||
// test.kt:8 foo$default
|
||||
// test.kt:8 foo
|
||||
+1
-1
@@ -22,4 +22,4 @@ fun box() {
|
||||
// EXPECTATIONS JS_IR
|
||||
// test.kt:11 box
|
||||
// test.kt:11 box
|
||||
// test.kt:6 A.get_prop_wosl9o_k$
|
||||
// test.kt:6 protoOf.get_prop_wosl9o_k$
|
||||
+1
-4
@@ -18,7 +18,4 @@ fun box(): String {
|
||||
|
||||
// EXPECTATIONS JS_IR
|
||||
// test.kt:8 box
|
||||
// test.kt:3 ifoo$default
|
||||
// test.kt:3 ifoo$default
|
||||
// test.kt:3 ifoo$default
|
||||
// test.kt:4 ifoo
|
||||
// test.kt:3 ifoo
|
||||
@@ -19,7 +19,7 @@ suspend fun box() {
|
||||
// test.kt:11 box
|
||||
|
||||
// EXPECTATIONS JS_IR
|
||||
// test.kt:8 $boxCOROUTINE$0.doResume_5yljmg_k$
|
||||
// test.kt:8 protoOf.doResume_5yljmg_k$
|
||||
// test.kt:4 foo
|
||||
// test.kt:4 foo
|
||||
// test.kt:9 box$lambda
|
||||
|
||||
@@ -1220,6 +1220,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
runTest("js/js.translator/testData/box/defaultArguments/inheritViaAnotherInterfaceIndirectly.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("interfaceSuperCall.kt")
|
||||
public void testInterfaceSuperCall() throws Exception {
|
||||
runTest("js/js.translator/testData/box/defaultArguments/interfaceSuperCall.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("overloadFunWithDefArg.kt")
|
||||
public void testOverloadFunWithDefArg() throws Exception {
|
||||
@@ -2130,6 +2136,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
runTest("js/js.translator/testData/box/export/exportClassWithInternalOneFile.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("exportDefaultParameterAndOverrideIt.kt")
|
||||
public void testExportDefaultParameterAndOverrideIt() throws Exception {
|
||||
runTest("js/js.translator/testData/box/export/exportDefaultParameterAndOverrideIt.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("exportEnumClass.kt")
|
||||
public void testExportEnumClass() throws Exception {
|
||||
|
||||
+12
@@ -1284,6 +1284,12 @@ public class FirJsTestGenerated extends AbstractFirJsTest {
|
||||
runTest("js/js.translator/testData/box/defaultArguments/inheritViaAnotherInterfaceIndirectly.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("interfaceSuperCall.kt")
|
||||
public void testInterfaceSuperCall() throws Exception {
|
||||
runTest("js/js.translator/testData/box/defaultArguments/interfaceSuperCall.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("overloadFunWithDefArg.kt")
|
||||
public void testOverloadFunWithDefArg() throws Exception {
|
||||
@@ -2602,6 +2608,12 @@ public class FirJsTestGenerated extends AbstractFirJsTest {
|
||||
runTest("js/js.translator/testData/box/export/exportClassWithInternalOneFile.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("exportDefaultParameterAndOverrideIt.kt")
|
||||
public void testExportDefaultParameterAndOverrideIt() throws Exception {
|
||||
runTest("js/js.translator/testData/box/export/exportDefaultParameterAndOverrideIt.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("exportEnumClass.kt")
|
||||
public void testExportEnumClass() throws Exception {
|
||||
|
||||
+12
@@ -1284,6 +1284,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
|
||||
runTest("js/js.translator/testData/box/defaultArguments/inheritViaAnotherInterfaceIndirectly.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("interfaceSuperCall.kt")
|
||||
public void testInterfaceSuperCall() throws Exception {
|
||||
runTest("js/js.translator/testData/box/defaultArguments/interfaceSuperCall.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("overloadFunWithDefArg.kt")
|
||||
public void testOverloadFunWithDefArg() throws Exception {
|
||||
@@ -2602,6 +2608,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
|
||||
runTest("js/js.translator/testData/box/export/exportClassWithInternalOneFile.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("exportDefaultParameterAndOverrideIt.kt")
|
||||
public void testExportDefaultParameterAndOverrideIt() throws Exception {
|
||||
runTest("js/js.translator/testData/box/export/exportDefaultParameterAndOverrideIt.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("exportEnumClass.kt")
|
||||
public void testExportEnumClass() throws Exception {
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1299
|
||||
package foo
|
||||
|
||||
interface A {
|
||||
open fun foo(x: Int = 20, y: Int = 3) = x + y
|
||||
}
|
||||
|
||||
open class B : A {
|
||||
override fun foo(x: Int, y: Int) = 0
|
||||
fun bar1() = super.foo()
|
||||
|
||||
fun bar2() = super.foo(30)
|
||||
|
||||
fun bar3() = super.foo(y = 4)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val v1 = B().bar1()
|
||||
if (v1 != 23) return "fail1: $v1"
|
||||
|
||||
val v2 = B().bar2()
|
||||
if (v2 != 33) return "fail2: $v2"
|
||||
|
||||
val v3 = B().bar3()
|
||||
if (v3 != 24) return "fail3: $v3"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1252
|
||||
// RUN_PLAIN_BOX_FUNCTION
|
||||
// INFER_MAIN_MODULE
|
||||
// SKIP_DCE_DRIVEN
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
// MODULE: export_default_method
|
||||
// FILE: lib.kt
|
||||
|
||||
@JsExport
|
||||
abstract class Adapter {
|
||||
abstract fun method(o: String = "O", k: String = "K")
|
||||
}
|
||||
|
||||
@JsExport
|
||||
class TwoArgumentsWrapper(val adapter: Adapter) {
|
||||
fun method(a: String, b: String) {
|
||||
adapter.method(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
@JsExport
|
||||
class OneArgumentWrapper(val adapter: Adapter) {
|
||||
fun method(param: String) {
|
||||
adapter.method(param)
|
||||
}
|
||||
}
|
||||
|
||||
@JsExport
|
||||
class NoArgumentsWrapper(val adapter: Adapter) {
|
||||
fun method() {
|
||||
adapter.method()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FILE: test.js
|
||||
|
||||
function box() {
|
||||
const Adapter = this.export_default_method.Adapter
|
||||
const Wrapper2 = this.export_default_method.TwoArgumentsWrapper
|
||||
const Wrapper1 = this.export_default_method.OneArgumentWrapper
|
||||
const Wrapper0 = this.export_default_method.NoArgumentsWrapper
|
||||
|
||||
class WebAdapter extends Adapter {
|
||||
constructor(name) {
|
||||
super()
|
||||
this.resetError(name)
|
||||
}
|
||||
|
||||
method(o = "O", k = "K") {
|
||||
this.result = o + k
|
||||
}
|
||||
|
||||
resetError(name) {
|
||||
this.result = `Error: ${name}'s overridden method was not called`
|
||||
}
|
||||
}
|
||||
|
||||
const webAdapter = new WebAdapter("webAdapter2")
|
||||
|
||||
const wrapper2 = new Wrapper2(webAdapter)
|
||||
wrapper2.method("O", "K")
|
||||
|
||||
if (webAdapter.result !== "OK") return webAdapter.result
|
||||
|
||||
webAdapter.resetError("webAdapter1")
|
||||
|
||||
const wrapper1 = new Wrapper1(webAdapter)
|
||||
wrapper1.method("O")
|
||||
|
||||
if (webAdapter.result !== "OK") return webAdapter.result
|
||||
|
||||
webAdapter.resetError("webAdapter0")
|
||||
|
||||
const wrapper0 = new Wrapper0(webAdapter)
|
||||
wrapper0.method()
|
||||
|
||||
if (webAdapter.result !== "OK") return webAdapter.result
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Vendored
+1
-2
@@ -15,8 +15,7 @@ inline fun <reified T> boo() = "boo"
|
||||
// MODULE: main(#my_libr@ry)
|
||||
// MODULE_KIND: PLAIN
|
||||
// FILE: box.kt
|
||||
// CHECK_CONTAINS_NO_CALLS: box except=assertEquals TARGET_BACKENDS=JS
|
||||
// CHECK_CONTAINS_NO_CALLS: box except=assertEquals$default IGNORED_BACKENDS=JS
|
||||
// CHECK_CONTAINS_NO_CALLS: box except=assertEquals
|
||||
|
||||
fun box(): String {
|
||||
assertEquals("foo", foo())
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ fun baz() = 1
|
||||
fun bar() = 2
|
||||
|
||||
// LINES(JS): 1 3 3 2 2 4 3 4 4 4 5 5 2 8 8 10 10 10 12 12 12
|
||||
// LINES(JS_IR): 8 8 * 1 3 3 1 4 5 1 1 * 10 10 * 12 12
|
||||
// LINES(JS_IR): 1 3 3 4 5 1 * 8 8 * 10 10 * 12 12
|
||||
|
||||
+1
-1
@@ -6,4 +6,4 @@ data class A(
|
||||
// LINES(JS): 1 2 3 * 1 2 2 1 3 3 1 1 1 2 3 1 1 1 2 3 1 1 1 2 3 1 1 1 1 1 2 3
|
||||
|
||||
// FIXME: componentN function body should point to the corresponding property.
|
||||
// LINES(JS_IR): 2 2 3 3 * 2 2 * 3 3 * 1 1 * 1 1 * 1 1 * 1 1 1 1 1 1 1 1 * 1 1 * 1 1 1 1 1 1 * 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
|
||||
// LINES(JS_IR): 2 2 3 3 * 2 2 * 3 3 * 1 1 * 1 1 * 1 1 * 1 1 1 1 * 1 1 * 1 1 1 1 1 1 * 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
|
||||
|
||||
@@ -11,4 +11,4 @@ class B : A() {
|
||||
}
|
||||
|
||||
// LINES(JS): 1 2 2 2 2 2 2 2 2 2 4 4 4 * 7 7 8 10 9 9
|
||||
// LINES(JS_IR): 2 2 * 2 2 2 2 2 * 4 4 * 7 * 9 9
|
||||
// LINES(JS_IR): 2 2 * 2 2 2 * 4 4 * 7 * 9 9
|
||||
|
||||
+1
-1
@@ -8,4 +8,4 @@ fun box(
|
||||
}
|
||||
|
||||
// LINES(JS): 1 8 2 2 2 2 3 3 3 4 6 6 7 7
|
||||
// LINES(JS_IR): 1 1 2 1 4 1 * 6 6 7 7 * 1 1 2 1 1 4 1 1
|
||||
// LINES(JS_IR): 1 2 1 1 4 1 6 6 7 7
|
||||
|
||||
@@ -90,8 +90,8 @@ internal fun captureStack(instance: Throwable, constructorFunction: Any) {
|
||||
internal fun newThrowable(message: String?, cause: Throwable?): Throwable {
|
||||
val throwable = js("new Error()")
|
||||
throwable.message = if (isUndefined(message)) {
|
||||
if (isUndefined(cause)) message else cause?.toString() ?: undefined
|
||||
} else message ?: undefined
|
||||
if (isUndefined(cause)) message else cause?.toString() ?: VOID
|
||||
} else message ?: VOID
|
||||
throwable.cause = cause
|
||||
throwable.name = "Throwable"
|
||||
return throwable.unsafeCast<Throwable>()
|
||||
@@ -109,10 +109,10 @@ internal fun setPropertiesToThrowableInstance(this_: dynamic, message: String?,
|
||||
@Suppress("SENSELESS_COMPARISON")
|
||||
if (message !== null) {
|
||||
// undefined
|
||||
cause?.toString() ?: undefined
|
||||
cause?.toString() ?: VOID
|
||||
} else {
|
||||
// real null
|
||||
undefined
|
||||
VOID
|
||||
}
|
||||
} else message
|
||||
}
|
||||
@@ -135,7 +135,19 @@ internal fun errorCode(description: String): Nothing {
|
||||
}
|
||||
|
||||
@Suppress("SENSELESS_COMPARISON")
|
||||
internal fun isUndefined(value: dynamic): Boolean = value === undefined
|
||||
internal fun isUndefined(value: dynamic): Boolean = value === VOID
|
||||
|
||||
internal fun <T, R> boxIntrinsic(@Suppress("UNUSED_PARAMETER") x: T): R = error("Should be lowered")
|
||||
internal fun <T, R> unboxIntrinsic(@Suppress("UNUSED_PARAMETER") x: T): R = error("Should be lowered")
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
internal fun protoOf(constructor: Any) =
|
||||
js("constructor.prototype")
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
internal fun <T> objectCreate(proto: T?) =
|
||||
js("Object.create(proto)")
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
internal fun defineProp(obj: Any, name: String, getter: Any?, setter: Any?) =
|
||||
js("Object.defineProperty(obj, name, { configurable: true, get: getter, set: setter })")
|
||||
|
||||
@@ -18,6 +18,9 @@ internal fun jsEqeq(a: Any?, b: Any?): Boolean
|
||||
@JsIntrinsic
|
||||
internal fun jsNotEq(a: Any?, b: Any?): Boolean
|
||||
|
||||
@JsIntrinsic
|
||||
internal fun jsUndefined(): Nothing?
|
||||
|
||||
@JsIntrinsic
|
||||
internal fun jsEqeqeq(a: Any?, b: Any?): Boolean
|
||||
|
||||
@@ -172,9 +175,6 @@ internal fun float32ArrayOf(a: Any?): Any?
|
||||
@JsIntrinsic
|
||||
internal fun float64ArrayOf(a: Any?): Any?
|
||||
|
||||
@JsIntrinsic
|
||||
internal fun <T> objectCreate(): T
|
||||
|
||||
@JsIntrinsic
|
||||
internal fun <T> sharedBoxCreate(v: T?): dynamic
|
||||
|
||||
@@ -184,15 +184,15 @@ internal fun <T> sharedBoxRead(box: dynamic): T?
|
||||
@JsIntrinsic
|
||||
internal fun <T> sharedBoxWrite(box: dynamic, nv: T?)
|
||||
|
||||
@JsIntrinsic
|
||||
internal fun jsUndefined(): Nothing?
|
||||
|
||||
@JsIntrinsic
|
||||
internal fun <T> DefaultType(): T
|
||||
|
||||
@JsIntrinsic
|
||||
internal fun jsBind(receiver: Any?, target: Any?): Any?
|
||||
|
||||
@JsIntrinsic
|
||||
internal fun jsCall(receiver: Any?, target: Any?, vararg args: Any?): Any?
|
||||
|
||||
@JsIntrinsic
|
||||
internal fun <A> slice(a: A): A
|
||||
|
||||
@@ -220,4 +220,7 @@ internal fun <reified T : Any> jsClassIntrinsic(): JsClass<T>
|
||||
internal fun jsInIntrinsic(lhs: Any?, rhs: Any): Boolean
|
||||
|
||||
@JsIntrinsic
|
||||
internal fun jsDelete(e: Any?)
|
||||
internal fun jsDelete(e: Any?)
|
||||
|
||||
@JsIntrinsic
|
||||
internal fun jsContextfulRef(context: dynamic, fn: dynamic): dynamic
|
||||
@@ -44,8 +44,7 @@ private fun getKPropMetadata(paramCount: Int, setter: Any?): dynamic {
|
||||
}
|
||||
|
||||
private fun metadataObject(): Metadata {
|
||||
val undef = js("undefined")
|
||||
return classMeta(undef, undef, undef, undef)
|
||||
return classMeta(VOID, VOID, VOID, VOID)
|
||||
}
|
||||
|
||||
private val propertyRefClassMetadataCache: Array<Array<dynamic>> = arrayOf<Array<dynamic>>(
|
||||
|
||||
@@ -44,7 +44,7 @@ internal fun classMeta(name: String?, associatedObjectKey: Number?, associatedOb
|
||||
}
|
||||
|
||||
// Seems like we need to disable this check if variables are used inside js annotation
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
@Suppress("UNUSED_PARAMETER", "UNUSED_VARIABLE")
|
||||
private fun createMetadata(
|
||||
kind: String,
|
||||
name: String?,
|
||||
@@ -53,13 +53,14 @@ private fun createMetadata(
|
||||
suspendArity: Array<Int>?,
|
||||
iid: Int?
|
||||
): Metadata {
|
||||
val undef = VOID
|
||||
return js("""({
|
||||
kind: kind,
|
||||
simpleName: name,
|
||||
associatedObjectKey: associatedObjectKey,
|
||||
associatedObjects: associatedObjects,
|
||||
suspendArity: suspendArity,
|
||||
${'$'}kClass$: undefined,
|
||||
${'$'}kClass$: undef,
|
||||
iid: iid
|
||||
})""")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
package kotlin.js
|
||||
|
||||
internal val VOID: Nothing? = js("void 0")
|
||||
Reference in New Issue
Block a user