[JS IR BE] Implement property reference
Add cache for direct (which has no closured parameters) KCallable references Refactor FunctionReferenceLowering * Rename FunctionReferenceLowering -> CallableReferenceLowering * Add util method to create value parameters
This commit is contained in:
committed by
Roman Artemev
parent
fb1fbf1473
commit
261edd5f4c
+4
-18
@@ -18,12 +18,12 @@ package org.jetbrains.kotlin.backend.js
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.descriptors.DescriptorsFactory
|
import org.jetbrains.kotlin.backend.common.descriptors.DescriptorsFactory
|
||||||
import org.jetbrains.kotlin.builtins.CompanionObjectMapping.isMappedIntrinsicCompanionObject
|
import org.jetbrains.kotlin.builtins.CompanionObjectMapping.isMappedIntrinsicCompanionObject
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
|
||||||
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
||||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.createValueParameter
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||||
import org.jetbrains.kotlin.ir.symbols.*
|
import org.jetbrains.kotlin.ir.symbols.*
|
||||||
@@ -34,9 +34,7 @@ import org.jetbrains.kotlin.ir.util.dump
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class JsDescriptorsFactory(
|
class JsDescriptorsFactory : DescriptorsFactory {
|
||||||
private val builtIns: KotlinBuiltIns
|
|
||||||
) : DescriptorsFactory {
|
|
||||||
private val singletonFieldDescriptors = HashMap<IrBindableSymbol<*, *>, IrFieldSymbol>()
|
private val singletonFieldDescriptors = HashMap<IrBindableSymbol<*, *>, IrFieldSymbol>()
|
||||||
private val outerThisFieldSymbols = HashMap<IrClass, IrFieldSymbol>()
|
private val outerThisFieldSymbols = HashMap<IrClass, IrFieldSymbol>()
|
||||||
private val innerClassConstructors = HashMap<IrConstructorSymbol, IrConstructorSymbol>()
|
private val innerClassConstructors = HashMap<IrConstructorSymbol, IrConstructorSymbol>()
|
||||||
@@ -93,19 +91,7 @@ class JsDescriptorsFactory(
|
|||||||
classDescriptor, oldDescriptor.annotations, oldDescriptor.isPrimary, oldDescriptor.source
|
classDescriptor, oldDescriptor.annotations, oldDescriptor.isPrimary, oldDescriptor.source
|
||||||
)
|
)
|
||||||
|
|
||||||
val outerThisValueParameter = ValueParameterDescriptorImpl(
|
val outerThisValueParameter = createValueParameter(newDescriptor, 0, Namer.OUTER_NAME, outerThisType)
|
||||||
newDescriptor,
|
|
||||||
null,
|
|
||||||
0,
|
|
||||||
Annotations.EMPTY,
|
|
||||||
Name.identifier("\$outer"),
|
|
||||||
outerThisType,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
null,
|
|
||||||
SourceElement.NO_SOURCE
|
|
||||||
)
|
|
||||||
|
|
||||||
val newValueParameters =
|
val newValueParameters =
|
||||||
listOf(outerThisValueParameter) +
|
listOf(outerThisValueParameter) +
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.descriptors.*
|
|||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||||
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.createValueParameter
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.getFunctions
|
import org.jetbrains.kotlin.ir.backend.js.utils.getFunctions
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||||
@@ -74,11 +75,19 @@ class JsIntrinsics(private val module: ModuleDescriptor, private val irBuiltIns:
|
|||||||
val jsBitShiftL = binOpInt("jsBitShiftL")
|
val jsBitShiftL = binOpInt("jsBitShiftL")
|
||||||
|
|
||||||
|
|
||||||
|
// KFunction operations:
|
||||||
|
|
||||||
|
val jsName = unOp("kCallableName", irBuiltIns.string)
|
||||||
|
val jsPropertyGet = binOp("kPropertyGet")
|
||||||
|
val jsPropertySet = tripleOp("kPropertySet", irBuiltIns.unit)
|
||||||
|
|
||||||
// Other:
|
// Other:
|
||||||
|
|
||||||
val jsInstanceOf = binOpBool("jsInstanceOf")
|
val jsInstanceOf = binOpBool("jsInstanceOf")
|
||||||
|
|
||||||
val jsObjectCreate: IrSimpleFunction = defineObjectCreateIntrinsic()
|
val jsObjectCreate = defineObjectCreateIntrinsic()
|
||||||
|
|
||||||
|
val jsSetJSField = defineSetJSPropertyIntrinsic()
|
||||||
|
|
||||||
val jsCode = module.getFunctions(FqName("kotlin.js.js")).singleOrNull()?.let { symbolTable.referenceFunction(it) }
|
val jsCode = module.getFunctions(FqName("kotlin.js.js")).singleOrNull()?.let { symbolTable.referenceFunction(it) }
|
||||||
|
|
||||||
@@ -112,6 +121,26 @@ class JsIntrinsics(private val module: ModuleDescriptor, private val irBuiltIns:
|
|||||||
return stubBuilder.generateFunctionStub(desc)
|
return stubBuilder.generateFunctionStub(desc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun defineSetJSPropertyIntrinsic(): IrSimpleFunction {
|
||||||
|
val returnType = irBuiltIns.unit
|
||||||
|
|
||||||
|
val desc = SimpleFunctionDescriptorImpl.create(
|
||||||
|
module,
|
||||||
|
Annotations.EMPTY,
|
||||||
|
Name.identifier("\$setJSProperty\$"),
|
||||||
|
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||||
|
SourceElement.NO_SOURCE
|
||||||
|
).apply {
|
||||||
|
|
||||||
|
val parameterDescriptors = listOf("receiver", "fieldName", "fieldValue")
|
||||||
|
.mapIndexed { i, name -> createValueParameter(this, i, name, irBuiltIns.any) }
|
||||||
|
initialize(null, null, emptyList(), parameterDescriptors, returnType, Modality.FINAL, Visibilities.PUBLIC)
|
||||||
|
}
|
||||||
|
|
||||||
|
return stubBuilder.generateFunctionStub(desc)
|
||||||
|
}
|
||||||
|
|
||||||
private fun unOp(name: String, returnType: KotlinType = irBuiltIns.anyN) =
|
private fun unOp(name: String, returnType: KotlinType = irBuiltIns.anyN) =
|
||||||
irBuiltIns.run { defineOperator(name, returnType, listOf(anyN)) }
|
irBuiltIns.run { defineOperator(name, returnType, listOf(anyN)) }
|
||||||
|
|
||||||
@@ -121,6 +150,9 @@ class JsIntrinsics(private val module: ModuleDescriptor, private val irBuiltIns:
|
|||||||
private fun binOp(name: String, returnType: KotlinType = irBuiltIns.anyN) =
|
private fun binOp(name: String, returnType: KotlinType = irBuiltIns.anyN) =
|
||||||
irBuiltIns.run { defineOperator(name, returnType, listOf(anyN, anyN)) }
|
irBuiltIns.run { defineOperator(name, returnType, listOf(anyN, anyN)) }
|
||||||
|
|
||||||
|
private fun tripleOp(name: String, returnType: KotlinType = irBuiltIns.anyN) =
|
||||||
|
irBuiltIns.run { defineOperator(name, returnType, listOf(anyN, anyN, anyN)) }
|
||||||
|
|
||||||
private fun binOpBool(name: String) = binOp(name, irBuiltIns.bool)
|
private fun binOpBool(name: String) = binOp(name, irBuiltIns.bool)
|
||||||
private fun binOpInt(name: String) = binOp(name, irBuiltIns.int)
|
private fun binOpInt(name: String) = binOp(name, irBuiltIns.int)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class JsIrBackendContext(
|
|||||||
override val builtIns = module.builtIns
|
override val builtIns = module.builtIns
|
||||||
override val sharedVariablesManager =
|
override val sharedVariablesManager =
|
||||||
JsSharedVariablesManager(builtIns, KnownPackageFragmentDescriptor(builtIns.builtInsModule, FqName("kotlin.js.internal")))
|
JsSharedVariablesManager(builtIns, KnownPackageFragmentDescriptor(builtIns.builtInsModule, FqName("kotlin.js.internal")))
|
||||||
override val descriptorsFactory = JsDescriptorsFactory(builtIns)
|
override val descriptorsFactory = JsDescriptorsFactory()
|
||||||
|
|
||||||
override val reflectionTypes: ReflectionTypes by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
override val reflectionTypes: ReflectionTypes by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||||
// TODO
|
// TODO
|
||||||
|
|||||||
+2
-15
@@ -13,8 +13,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
|||||||
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
|
||||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
||||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
import org.jetbrains.kotlin.ir.backend.js.utils.createValueParameter
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
@@ -136,19 +135,7 @@ class JsSharedVariablesManager(val builtIns: KotlinBuiltIns, val jsInterinalPack
|
|||||||
listOf(), true
|
listOf(), true
|
||||||
)
|
)
|
||||||
|
|
||||||
val paramDesc = ValueParameterDescriptorImpl(
|
val paramDesc = createValueParameter(this, 0, "v", parameterType)
|
||||||
this,
|
|
||||||
null,
|
|
||||||
0,
|
|
||||||
Annotations.EMPTY,
|
|
||||||
Name.identifier("v"),
|
|
||||||
parameterType,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
null,
|
|
||||||
SourceElement.NO_SOURCE
|
|
||||||
)
|
|
||||||
|
|
||||||
initialize(listOf(paramDesc), Visibilities.PUBLIC)
|
initialize(listOf(paramDesc), Visibilities.PUBLIC)
|
||||||
returnType = KotlinTypeFactory.simpleNotNullType(
|
returnType = KotlinTypeFactory.simpleNotNullType(
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.backend.common.lower.*
|
|||||||
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.BlockDecomposerLowering
|
import org.jetbrains.kotlin.ir.backend.js.lower.BlockDecomposerLowering
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.FunctionReferenceLowering
|
import org.jetbrains.kotlin.ir.backend.js.lower.CallableReferenceLowering
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.IntrinsicifyCallsLowering
|
import org.jetbrains.kotlin.ir.backend.js.lower.IntrinsicifyCallsLowering
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.SecondaryCtorLowering
|
import org.jetbrains.kotlin.ir.backend.js.lower.SecondaryCtorLowering
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
||||||
@@ -67,6 +67,6 @@ fun JsIrBackendContext.lower(file: IrFile) {
|
|||||||
InitializersLowering(this, JsLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, false).runOnFilePostfix(file)
|
InitializersLowering(this, JsLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, false).runOnFilePostfix(file)
|
||||||
BlockDecomposerLowering(this).runOnFilePostfix(file)
|
BlockDecomposerLowering(this).runOnFilePostfix(file)
|
||||||
SecondaryCtorLowering(this).runOnFilePostfix(file)
|
SecondaryCtorLowering(this).runOnFilePostfix(file)
|
||||||
|
CallableReferenceLowering(this).lower(file)
|
||||||
IntrinsicifyCallsLowering(this).lower(file)
|
IntrinsicifyCallsLowering(this).lower(file)
|
||||||
FunctionReferenceLowering(this).lower(file)
|
|
||||||
}
|
}
|
||||||
+3
-23
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
|||||||
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
|
||||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
import org.jetbrains.kotlin.ir.backend.js.utils.createValueParameter
|
||||||
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
|
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
@@ -23,28 +23,8 @@ import org.jetbrains.kotlin.name.Name
|
|||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
object JsSymbolBuilder {
|
object JsSymbolBuilder {
|
||||||
fun buildValueParameter(
|
fun buildValueParameter(containingSymbol: IrSimpleFunctionSymbol, index: Int, type: KotlinType, name: String? = null) =
|
||||||
containingSymbol: IrSimpleFunctionSymbol,
|
IrValueParameterSymbolImpl(createValueParameter(containingSymbol.descriptor, index, name ?: "param$index", type))
|
||||||
index: Int,
|
|
||||||
type: KotlinType,
|
|
||||||
name: String? = null,
|
|
||||||
hasDefault: Boolean = false
|
|
||||||
) =
|
|
||||||
IrValueParameterSymbolImpl(
|
|
||||||
ValueParameterDescriptorImpl(
|
|
||||||
containingSymbol.descriptor,
|
|
||||||
null,
|
|
||||||
index,
|
|
||||||
Annotations.EMPTY,
|
|
||||||
Name.identifier(name ?: "param$index"),
|
|
||||||
type,
|
|
||||||
hasDefault,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
null,
|
|
||||||
SourceElement.NO_SOURCE
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
fun buildSimpleFunction(
|
fun buildSimpleFunction(
|
||||||
containingDeclaration: DeclarationDescriptor,
|
containingDeclaration: DeclarationDescriptor,
|
||||||
|
|||||||
@@ -78,4 +78,5 @@ object JsIrBuilder {
|
|||||||
|
|
||||||
fun buildNull(type: KotlinType) = IrConstImpl.constNull(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type)
|
fun buildNull(type: KotlinType) = IrConstImpl.constNull(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type)
|
||||||
fun buildBoolean(type: KotlinType, v: Boolean) = IrConstImpl.boolean(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, v)
|
fun buildBoolean(type: KotlinType, v: Boolean) = IrConstImpl.boolean(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, v)
|
||||||
|
fun buildString(type: KotlinType, s: String) = IrConstImpl.string(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, s)
|
||||||
}
|
}
|
||||||
+7
-6
@@ -10,9 +10,9 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
import org.jetbrains.kotlin.ir.backend.js.descriptors.JsSymbolBuilder
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.descriptors.initialize
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.symbols.JsSymbolBuilder
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.symbols.initialize
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
@@ -393,16 +393,16 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : FunctionLowerin
|
|||||||
collectingList += tempResult.runIfChangedOrDefault(listOf(statement)) { statements }
|
collectingList += tempResult.runIfChangedOrDefault(listOf(statement)) { statements }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastStatement != null) {
|
return if (lastStatement != null) {
|
||||||
val result = lastStatement.accept(expressionVisitor, data).runIfChangedOrDefault(lastStatement as IrExpression) {
|
val result = lastStatement.accept(expressionVisitor, data).runIfChangedOrDefault(lastStatement as IrExpression) {
|
||||||
collectingList += statements
|
collectingList += statements
|
||||||
resultValue
|
resultValue
|
||||||
}
|
}
|
||||||
collectingList += JsIrBuilder.buildSetVariable(variable, result)
|
collectingList += JsIrBuilder.buildSetVariable(variable, result)
|
||||||
return DecomposedResult(mutableListOf(varDeclaration, body), JsIrBuilder.buildGetValue(variable))
|
DecomposedResult(mutableListOf(varDeclaration, body), JsIrBuilder.buildGetValue(variable))
|
||||||
} else {
|
} else {
|
||||||
// do not allow variable to be uninitialized
|
// do not allow variable to be uninitialized
|
||||||
return DecomposedResult(mutableListOf(), unitValue)
|
DecomposedResult(mutableListOf(), unitValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -562,7 +562,8 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : FunctionLowerin
|
|||||||
expression.endOffset,
|
expression.endOffset,
|
||||||
expression.type,
|
expression.type,
|
||||||
expression.varargElementType,
|
expression.varargElementType,
|
||||||
newArguments)
|
newArguments
|
||||||
|
)
|
||||||
|
|
||||||
return DecomposedResult(newStatements, newExpression)
|
return DecomposedResult(newStatements, newExpression)
|
||||||
}
|
}
|
||||||
|
|||||||
+353
@@ -0,0 +1,353 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
|
||||||
|
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.copyAsValueParameter
|
||||||
|
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.util.transformFlat
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.*
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
|
class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringPass, DeclarationContainerLoweringPass {
|
||||||
|
|
||||||
|
private val callableToGetterFunction = mutableMapOf<CallableDescriptor, IrFunction>()
|
||||||
|
|
||||||
|
// TODO: replace descriptor usage with symbol instead
|
||||||
|
private val collectedReferenceMap = mutableMapOf<IrDeclaration, IrCallableReference>()
|
||||||
|
|
||||||
|
private val callableNameConst = JsIrBuilder.buildString(context.irBuiltIns.string, Namer.KCALLABLE_NAME)
|
||||||
|
private val getterConst = JsIrBuilder.buildString(context.irBuiltIns.string, Namer.KPROPERTY_GET)
|
||||||
|
private val setterConst = JsIrBuilder.buildString(context.irBuiltIns.string, Namer.KPROPERTY_SET)
|
||||||
|
|
||||||
|
override fun lower(irFile: IrFile) {
|
||||||
|
irFile.acceptVoid(CallableReferenceCollector())
|
||||||
|
runOnFilePostfix(irFile)
|
||||||
|
irFile.transformChildrenVoid(CallableReferenceTransformer())
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class CallableReferenceCollector : IrElementVisitorVoid {
|
||||||
|
override fun visitFunctionReference(expression: IrFunctionReference) {
|
||||||
|
collectedReferenceMap[expression.symbol.owner] = expression
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitPropertyReference(expression: IrPropertyReference) {
|
||||||
|
//Note: The getter is taken because the `invoke()` function of the resulted reference has to be corresponding getter call
|
||||||
|
collectedReferenceMap[expression.getter!!.owner] = expression
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitElement(element: IrElement) {
|
||||||
|
element.acceptChildrenVoid(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
|
||||||
|
irDeclarationContainer.declarations.transformFlat { d ->
|
||||||
|
collectedReferenceMap[d]?.accept(object : IrElementVisitor<List<IrDeclaration>, IrFunction> {
|
||||||
|
override fun visitElement(element: IrElement, data: IrFunction) = error("Unreachable execution")
|
||||||
|
override fun visitFunctionReference(expression: IrFunctionReference, data: IrFunction) =
|
||||||
|
lowerKFunctionReference(data, expression)
|
||||||
|
|
||||||
|
override fun visitPropertyReference(expression: IrPropertyReference, data: IrFunction) =
|
||||||
|
lowerKPropertyReference(data, expression)
|
||||||
|
}, d as IrFunction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class CallableReferenceTransformer : IrElementTransformerVoid() {
|
||||||
|
override fun visitCallableReference(expression: IrCallableReference) = callableToGetterFunction[expression.descriptor]?.let {
|
||||||
|
redirectToFunction(expression, it)
|
||||||
|
} ?: expression
|
||||||
|
|
||||||
|
private fun redirectToFunction(callable: IrCallableReference, newTarget: IrFunction) =
|
||||||
|
IrCallImpl(callable.startOffset, callable.endOffset, newTarget.symbol, callable.origin).apply {
|
||||||
|
copyTypeArgumentsFrom(callable)
|
||||||
|
var index = 0
|
||||||
|
for (i in 0 until callable.valueArgumentsCount) {
|
||||||
|
val arg = callable.getValueArgument(i)
|
||||||
|
if (arg != null) {
|
||||||
|
putValueArgument(index++, arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createClosureGetterName(descriptor: CallableDescriptor) = createHelperFunctionName(descriptor, "KReferenceGet")
|
||||||
|
private fun createPropertyClosureGetterName(descriptor: CallableDescriptor) = createHelperFunctionName(descriptor, "KPropertyGet")
|
||||||
|
private fun createClosureInstanceName(descriptor: CallableDescriptor) = createHelperFunctionName(descriptor, "KReferenceClosure")
|
||||||
|
|
||||||
|
private fun createHelperFunctionName(descriptor: CallableDescriptor, suffix: String): String {
|
||||||
|
val nameBuilder = StringBuilder()
|
||||||
|
if (descriptor is ClassConstructorDescriptor) {
|
||||||
|
nameBuilder.append(descriptor.constructedClass.fqNameSafe)
|
||||||
|
nameBuilder.append('_')
|
||||||
|
}
|
||||||
|
nameBuilder.append(descriptor.name)
|
||||||
|
nameBuilder.append('_')
|
||||||
|
nameBuilder.append(suffix)
|
||||||
|
return nameBuilder.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun getReferenceName(descriptor: CallableDescriptor): String {
|
||||||
|
if (descriptor is ClassConstructorDescriptor) {
|
||||||
|
return descriptor.constructedClass.name.identifier
|
||||||
|
}
|
||||||
|
return descriptor.name.identifier
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun lowerKFunctionReference(declaration: IrFunction, functionReference: IrFunctionReference): List<IrDeclaration> {
|
||||||
|
// transform
|
||||||
|
// x = Foo::bar ->
|
||||||
|
// x = Foo_bar_KreferenceGet(c1: closure$C1, c2: closure$C2) : KFunctionN<Foo, T2, ..., TN, TReturn> {
|
||||||
|
// [ if ($cache$ == null) { ] // in case reference has no closure param cache it
|
||||||
|
// val x = fun Foo_bar_KreferenceClosure(p0: Foo, p1: T2, p2: T3): TReturn {
|
||||||
|
// return p0.bar(c1, c2, p1, p2)
|
||||||
|
// }
|
||||||
|
// x.callableName = "bar"
|
||||||
|
// [ $cache$ = x } ]
|
||||||
|
// return {$cache$|x}
|
||||||
|
// }
|
||||||
|
|
||||||
|
// KFunctionN<Foo, T2, ..., TN, TReturn>, arguments.size = N + 1
|
||||||
|
|
||||||
|
val refGetFunction = buildGetFunction(declaration, functionReference.type, createClosureGetterName(declaration.descriptor))
|
||||||
|
val refClosureFunction = buildClosureFunction(declaration, refGetFunction)
|
||||||
|
|
||||||
|
val additionalDeclarations = generateGetterBodyWithGuard(refGetFunction) {
|
||||||
|
val irClosureReference = JsIrBuilder.buildFunctionReference(functionReference.type, refClosureFunction.symbol)
|
||||||
|
val irVarSymbol = JsSymbolBuilder.buildTempVar(refGetFunction.symbol, irClosureReference.type)
|
||||||
|
val irVar = JsIrBuilder.buildVar(irVarSymbol, irClosureReference)
|
||||||
|
|
||||||
|
// TODO: fill other fields of callable reference (returnType, parameters, isFinal, etc.)
|
||||||
|
val irSetName = JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply {
|
||||||
|
putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol))
|
||||||
|
putValueArgument(1, callableNameConst)
|
||||||
|
putValueArgument(2, JsIrBuilder.buildString(context.irBuiltIns.string, getReferenceName(declaration.descriptor)))
|
||||||
|
}
|
||||||
|
Pair(listOf(irVar, irSetName), irVarSymbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
callableToGetterFunction[functionReference.descriptor] = refGetFunction
|
||||||
|
|
||||||
|
return additionalDeclarations + listOf(declaration, refGetFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun lowerKPropertyReference(getterDeclaration: IrFunction, propertyReference: IrPropertyReference): List<IrDeclaration> {
|
||||||
|
// transform
|
||||||
|
// x = Foo::bar ->
|
||||||
|
// x = Foo_bar_KreferenceGet() : KPropertyN<Foo, PType> {
|
||||||
|
// if ($cache$ == null) { // very likely property reference is going to be cached
|
||||||
|
// val x = fun Foo_bar_KreferenceClosure_get(r: Foo): PType {
|
||||||
|
// return r.<get>()
|
||||||
|
// }
|
||||||
|
// x.get = x
|
||||||
|
// x.callableName = "bar"
|
||||||
|
// if (mutable) {
|
||||||
|
// x.set = fun Foo_bar_KreferenceClosure_set(r: Foo, v: PType>) {
|
||||||
|
// r.<set>(v)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// $cache$ = x
|
||||||
|
// }
|
||||||
|
// return $cache$
|
||||||
|
// }
|
||||||
|
|
||||||
|
val getterName = createPropertyClosureGetterName(propertyReference.descriptor)
|
||||||
|
val refGetFunction = buildGetFunction(propertyReference.getter!!.owner, propertyReference.type, getterName)
|
||||||
|
|
||||||
|
val getterFunction = propertyReference.getter?.let { buildClosureFunction(it.owner, refGetFunction) }!!
|
||||||
|
val setterFunction = propertyReference.setter?.let { buildClosureFunction(it.owner, refGetFunction) }
|
||||||
|
|
||||||
|
val additionalDeclarations = generateGetterBodyWithGuard(refGetFunction) {
|
||||||
|
val statements = mutableListOf<IrStatement>()
|
||||||
|
|
||||||
|
val getterFunctionType = context.builtIns.getFunction(getterFunction.valueParameters.size + 1)
|
||||||
|
val irGetReference = JsIrBuilder.buildFunctionReference(getterFunctionType.defaultType, getterFunction.symbol)
|
||||||
|
val irVarSymbol = JsSymbolBuilder.buildTempVar(refGetFunction.symbol, getterFunctionType.defaultType)
|
||||||
|
|
||||||
|
statements += JsIrBuilder.buildVar(irVarSymbol, irGetReference)
|
||||||
|
|
||||||
|
JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).run {
|
||||||
|
putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol))
|
||||||
|
putValueArgument(1, getterConst)
|
||||||
|
putValueArgument(2, JsIrBuilder.buildGetValue(irVarSymbol))
|
||||||
|
statements += this
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setterFunction != null) {
|
||||||
|
val setterFunctionType = context.builtIns.getFunction(setterFunction.valueParameters.size + 1)
|
||||||
|
val irSetReference = JsIrBuilder.buildFunctionReference(setterFunctionType.defaultType, setterFunction.symbol)
|
||||||
|
JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).run {
|
||||||
|
putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol))
|
||||||
|
putValueArgument(1, setterConst)
|
||||||
|
putValueArgument(2, irSetReference)
|
||||||
|
statements += this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: fill other fields of callable reference (returnType, parameters, isFinal, etc.)
|
||||||
|
JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).run {
|
||||||
|
putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol))
|
||||||
|
putValueArgument(1, callableNameConst)
|
||||||
|
putValueArgument(2, JsIrBuilder.buildString(context.irBuiltIns.string, getReferenceName(propertyReference.descriptor)))
|
||||||
|
statements += this
|
||||||
|
}
|
||||||
|
|
||||||
|
Pair(statements, irVarSymbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
callableToGetterFunction[propertyReference.descriptor] = refGetFunction
|
||||||
|
|
||||||
|
return additionalDeclarations + listOf(getterDeclaration, refGetFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateGetterBodyWithGuard(
|
||||||
|
getterFunction: IrSimpleFunction,
|
||||||
|
builder: () -> Pair<List<IrStatement>, IrValueSymbol>
|
||||||
|
): List<IrDeclaration> {
|
||||||
|
|
||||||
|
val (bodyStatements, varSymbol) = builder()
|
||||||
|
val statements = mutableListOf<IrStatement>()
|
||||||
|
val returnValue: IrExpression
|
||||||
|
val returnStatements: List<IrDeclaration>
|
||||||
|
if (getterFunction.valueParameters.isEmpty()) {
|
||||||
|
// compose cache for 'direct' closure
|
||||||
|
// if ($cache$ === null) {
|
||||||
|
// $cache$ = <body>
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
val cacheName = "${getterFunction.name}_${Namer.KCALLABLE_CACHE_SUFFIX}"
|
||||||
|
val cacheVarSymbol =
|
||||||
|
JsSymbolBuilder.buildVar(getterFunction.descriptor.containingDeclaration, getterFunction.returnType, cacheName, true)
|
||||||
|
val irCacheNull = JsIrBuilder.buildNull(cacheVarSymbol.descriptor.type)
|
||||||
|
val irCacheDeclaration = JsIrBuilder.buildVar(cacheVarSymbol, irCacheNull)
|
||||||
|
val irCacheValue = JsIrBuilder.buildGetValue(cacheVarSymbol)
|
||||||
|
val irIfCondition = JsIrBuilder.buildCall(context.irBuiltIns.eqeqeqSymbol).apply {
|
||||||
|
putValueArgument(0, irCacheValue)
|
||||||
|
putValueArgument(1, irCacheNull)
|
||||||
|
}
|
||||||
|
val irSetCache = JsIrBuilder.buildSetVariable(cacheVarSymbol, JsIrBuilder.buildGetValue(varSymbol))
|
||||||
|
val thenStatements = mutableListOf<IrStatement>().apply {
|
||||||
|
addAll(bodyStatements)
|
||||||
|
add(irSetCache)
|
||||||
|
}
|
||||||
|
val irThenBranch = JsIrBuilder.buildBlock(context.irBuiltIns.unit, thenStatements)
|
||||||
|
val irIfNode = JsIrBuilder.buildIfElse(context.irBuiltIns.unit, irIfCondition, irThenBranch)
|
||||||
|
statements += irIfNode
|
||||||
|
returnValue = irCacheValue
|
||||||
|
returnStatements = listOf(irCacheDeclaration)
|
||||||
|
} else {
|
||||||
|
statements += bodyStatements
|
||||||
|
returnValue = JsIrBuilder.buildGetValue(varSymbol)
|
||||||
|
returnStatements = emptyList()
|
||||||
|
}
|
||||||
|
statements += JsIrBuilder.buildReturn(getterFunction.symbol, returnValue)
|
||||||
|
|
||||||
|
getterFunction.body = JsIrBuilder.buildBlockBody(statements)
|
||||||
|
return returnStatements
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateSignatureForClosure(
|
||||||
|
callable: IrFunctionSymbol,
|
||||||
|
getter: IrSimpleFunctionSymbol,
|
||||||
|
closure: IrSimpleFunctionSymbol
|
||||||
|
): List<IrValueParameterSymbol> {
|
||||||
|
val result = mutableListOf<IrValueParameterSymbol>()
|
||||||
|
|
||||||
|
callable.owner.dispatchReceiverParameter?.run { result.add(JsSymbolBuilder.buildValueParameter(closure, result.size, type)) }
|
||||||
|
callable.owner.extensionReceiverParameter?.run { result.add(JsSymbolBuilder.buildValueParameter(closure, result.size, type)) }
|
||||||
|
|
||||||
|
for (i in getter.owner.valueParameters.size until callable.owner.valueParameters.size) {
|
||||||
|
val param = callable.owner.valueParameters[i]
|
||||||
|
val paramName = param.name.run { if (!isSpecial) identifier else null }
|
||||||
|
result += JsSymbolBuilder.buildValueParameter(closure, result.size, param.type, paramName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildGetFunction(declaration: IrFunction, callableType: KotlinType, getterName: String): IrSimpleFunction {
|
||||||
|
|
||||||
|
val closureParams = callableType.arguments.dropLast(1) // drop return type
|
||||||
|
var kFunctionValueParamsCount = closureParams.size
|
||||||
|
if (declaration.dispatchReceiverParameter != null) kFunctionValueParamsCount--
|
||||||
|
if (declaration.extensionReceiverParameter != null) kFunctionValueParamsCount--
|
||||||
|
|
||||||
|
assert(kFunctionValueParamsCount >= 0)
|
||||||
|
|
||||||
|
// The `getter` function takes only closure parameters
|
||||||
|
val getterValueParameters = declaration.valueParameters.dropLast(kFunctionValueParamsCount)
|
||||||
|
|
||||||
|
val refGetSymbol = JsSymbolBuilder.buildSimpleFunction(declaration.descriptor.containingDeclaration, getterName).apply {
|
||||||
|
initialize(
|
||||||
|
valueParameters = getterValueParameters.mapIndexed { i, p -> p.descriptor.copyAsValueParameter(descriptor, i) },
|
||||||
|
type = callableType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return JsIrBuilder.buildFunction(refGetSymbol).apply {
|
||||||
|
for (i in 0 until getterValueParameters.size) {
|
||||||
|
val p = getterValueParameters[i]
|
||||||
|
valueParameters += IrValueParameterImpl(p.startOffset, p.endOffset, p.origin, refGetSymbol.descriptor.valueParameters[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildClosureFunction(declaration: IrFunction, refGetFunction: IrSimpleFunction): IrFunction {
|
||||||
|
val closureName = createClosureInstanceName(declaration.descriptor)
|
||||||
|
val refClosureSymbol = JsSymbolBuilder.buildSimpleFunction(refGetFunction.descriptor, closureName)
|
||||||
|
|
||||||
|
// the params which are passed to closure
|
||||||
|
val closureParamSymbols = generateSignatureForClosure(declaration.symbol, refGetFunction.symbol, refClosureSymbol)
|
||||||
|
val closureParamDescriptors = closureParamSymbols.map { it.descriptor as ValueParameterDescriptor }
|
||||||
|
|
||||||
|
refClosureSymbol.initialize(valueParameters = closureParamDescriptors, type = declaration.returnType)
|
||||||
|
|
||||||
|
return JsIrBuilder.buildFunction(refClosureSymbol).apply {
|
||||||
|
for (it in closureParamSymbols) {
|
||||||
|
valueParameters += JsIrBuilder.buildValueParameter(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
val irCall = JsIrBuilder.buildCall(declaration.symbol)
|
||||||
|
|
||||||
|
var p = 0
|
||||||
|
declaration.dispatchReceiverParameter?.run { irCall.dispatchReceiver = JsIrBuilder.buildGetValue(closureParamSymbols[p++]) }
|
||||||
|
declaration.extensionReceiverParameter?.run { irCall.extensionReceiver = JsIrBuilder.buildGetValue(closureParamSymbols[p++]) }
|
||||||
|
|
||||||
|
var j = 0
|
||||||
|
for (v in refGetFunction.valueParameters) {
|
||||||
|
irCall.putValueArgument(j++, JsIrBuilder.buildGetValue(v.symbol))
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in p until closureParamSymbols.size) {
|
||||||
|
irCall.putValueArgument(j++, JsIrBuilder.buildGetValue(closureParamSymbols[i]))
|
||||||
|
}
|
||||||
|
|
||||||
|
val irClosureReturn = JsIrBuilder.buildReturn(symbol, irCall)
|
||||||
|
|
||||||
|
body = JsIrBuilder.buildBlockBody(listOf(irClosureReturn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
-183
@@ -1,183 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
|
||||||
* that can be found in the license/LICENSE.txt file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
|
|
||||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
|
||||||
import org.jetbrains.kotlin.backend.common.lower.copyAsValueParameter
|
|
||||||
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.descriptors.JsSymbolBuilder
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.descriptors.initialize
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.copyTypeArgumentsFrom
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.util.transformFlat
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.*
|
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
|
|
||||||
// TODO replace with DeclarationContainerLowerPass && do flatTransform
|
|
||||||
class FunctionReferenceLowering(val context: JsIrBackendContext) : FileLoweringPass, DeclarationContainerLoweringPass {
|
|
||||||
|
|
||||||
private val lambdas = mutableMapOf<IrDeclaration, KotlinType>()
|
|
||||||
private val oldToNewDeclarationMap = mutableMapOf<IrFunctionSymbol, IrFunction>()
|
|
||||||
|
|
||||||
override fun lower(irFile: IrFile) {
|
|
||||||
irFile.acceptVoid(FunctionReferenceCollector())
|
|
||||||
runOnFilePostfix(irFile)
|
|
||||||
irFile.transformChildrenVoid(FunctionReferenceVisitor())
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class FunctionReferenceCollector : IrElementVisitorVoid {
|
|
||||||
override fun visitFunctionReference(expression: IrFunctionReference) {
|
|
||||||
lambdas[expression.symbol.owner as IrFunction] = expression.type
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitElement(element: IrElement) {
|
|
||||||
element.acceptChildrenVoid(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
|
|
||||||
irDeclarationContainer.declarations.transformFlat { d ->
|
|
||||||
if (d is IrFunction) {
|
|
||||||
lambdas[d]?.let {
|
|
||||||
lowerKFunctionReference(d, it)
|
|
||||||
}
|
|
||||||
} else null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class FunctionReferenceVisitor : IrElementTransformerVoid() {
|
|
||||||
|
|
||||||
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
|
|
||||||
val newTarget = oldToNewDeclarationMap[expression.symbol]
|
|
||||||
|
|
||||||
return if (newTarget != null) IrCallImpl(expression.startOffset, expression.endOffset, newTarget.symbol, expression.origin).apply {
|
|
||||||
copyTypeArgumentsFrom(expression)
|
|
||||||
var index = 0
|
|
||||||
for (i in 0 until expression.valueArgumentsCount) {
|
|
||||||
val arg = expression.getValueArgument(i)
|
|
||||||
if (arg != null) {
|
|
||||||
putValueArgument(index++, arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else expression
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createClosureGetterName(declaration: IrFunction) = createHelperFunctionName(declaration, "KreferenceGet")
|
|
||||||
private fun createClosureInstanceName(declaration: IrFunction) = createHelperFunctionName(declaration, "KreferenceClosure")
|
|
||||||
|
|
||||||
private fun createHelperFunctionName(declaration: IrFunction, suffix: String): String {
|
|
||||||
val nameBuilder = StringBuilder()
|
|
||||||
if (declaration is IrConstructor) {
|
|
||||||
nameBuilder.append(declaration.descriptor.constructedClass.fqNameSafe)
|
|
||||||
nameBuilder.append('_')
|
|
||||||
}
|
|
||||||
nameBuilder.append(declaration.descriptor.name)
|
|
||||||
nameBuilder.append('_')
|
|
||||||
nameBuilder.append(suffix)
|
|
||||||
return nameBuilder.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun lowerKFunctionReference(declaration: IrFunction, functionType: KotlinType): List<IrFunction> {
|
|
||||||
// TODO: property reference
|
|
||||||
|
|
||||||
// transform
|
|
||||||
// x = Foo::bar ->
|
|
||||||
// x = Foo_bar_KreferenceGet(c1: closure$C1, c2: closure$C2) : KFunctionN<Foo, T2, ..., TN, TReturn> {
|
|
||||||
// return fun Foo_bar_KreferenceClosure(p0: Foo, p1: T2, p2: T3): TReturn {
|
|
||||||
// return p0.bar(c1, c2, p1, p2)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// KFunctionN<Foo, T2, ..., TN, TReturn>, arguments.size = N + 1
|
|
||||||
|
|
||||||
val closureParams = functionType.arguments.dropLast(1) // drop return type
|
|
||||||
var kFunctionValueParamsCount = closureParams.size
|
|
||||||
if (declaration.dispatchReceiverParameter != null) kFunctionValueParamsCount--
|
|
||||||
if (declaration.extensionReceiverParameter != null) kFunctionValueParamsCount--
|
|
||||||
|
|
||||||
assert(kFunctionValueParamsCount >= 0)
|
|
||||||
|
|
||||||
// The `getter` function takes only parameters which have to be closured
|
|
||||||
val getterValueParameters = declaration.valueParameters.dropLast(kFunctionValueParamsCount)
|
|
||||||
val getterName = createClosureGetterName(declaration)
|
|
||||||
|
|
||||||
val refGetSymbol =
|
|
||||||
JsSymbolBuilder.buildSimpleFunction(declaration.descriptor.containingDeclaration, getterName).apply {
|
|
||||||
initialize(
|
|
||||||
valueParameters = getterValueParameters.mapIndexed { i, p -> p.descriptor.copyAsValueParameter(this.descriptor, i) },
|
|
||||||
type = functionType
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val refGetFunction = JsIrBuilder.buildFunction(refGetSymbol).apply {
|
|
||||||
getterValueParameters.mapIndexed { i, p ->
|
|
||||||
valueParameters += IrValueParameterImpl(p.startOffset, p.endOffset, p.origin, refGetSymbol.descriptor.valueParameters[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val closureName = createClosureInstanceName(declaration)
|
|
||||||
val refClosureSymbol = JsSymbolBuilder.buildSimpleFunction(refGetSymbol.descriptor, closureName)
|
|
||||||
|
|
||||||
// the params which are passed to closure
|
|
||||||
val closureParamSymbols = closureParams.mapIndexed { index, p ->
|
|
||||||
// TODO: re-use original parameter names
|
|
||||||
JsSymbolBuilder.buildValueParameter(refClosureSymbol, index, p.type)
|
|
||||||
}
|
|
||||||
|
|
||||||
val closureParamDescriptors = closureParamSymbols.map { it.descriptor as ValueParameterDescriptor }
|
|
||||||
|
|
||||||
refClosureSymbol.initialize(valueParameters = closureParamDescriptors, type = declaration.returnType)
|
|
||||||
|
|
||||||
JsIrBuilder.buildFunction(refClosureSymbol).apply {
|
|
||||||
closureParamSymbols.forEach { valueParameters += JsIrBuilder.buildValueParameter(it) }
|
|
||||||
|
|
||||||
val irClosureCall = JsIrBuilder.buildCall(declaration.symbol).apply {
|
|
||||||
var p = 0
|
|
||||||
if (declaration.dispatchReceiverParameter != null) {
|
|
||||||
dispatchReceiver = JsIrBuilder.buildGetValue(closureParamSymbols[p++])
|
|
||||||
}
|
|
||||||
if (declaration.extensionReceiverParameter != null) {
|
|
||||||
extensionReceiver = JsIrBuilder.buildGetValue(closureParamSymbols[p++])
|
|
||||||
}
|
|
||||||
|
|
||||||
var j = 0
|
|
||||||
refGetFunction.valueParameters.forEach { v ->
|
|
||||||
putValueArgument(j++, JsIrBuilder.buildGetValue(v.symbol))
|
|
||||||
}
|
|
||||||
|
|
||||||
closureParamSymbols.drop(p).forEach { v ->
|
|
||||||
putValueArgument(j++, JsIrBuilder.buildGetValue(v))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val irClosureReturn = JsIrBuilder.buildReturn(refClosureSymbol, irClosureCall)
|
|
||||||
|
|
||||||
body = JsIrBuilder.buildBlockBody(listOf(irClosureReturn))
|
|
||||||
}
|
|
||||||
|
|
||||||
refGetFunction.apply {
|
|
||||||
val irClosureReference = JsIrBuilder.buildFunctionReference(functionType, refClosureSymbol)
|
|
||||||
val irGetterReturn = JsIrBuilder.buildReturn(refGetSymbol, irClosureReference)
|
|
||||||
body = JsIrBuilder.buildBlockBody(listOf(irGetterReturn))
|
|
||||||
}
|
|
||||||
|
|
||||||
oldToNewDeclarationMap[declaration.symbol] = refGetFunction
|
|
||||||
|
|
||||||
return listOf(declaration, refGetFunction)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+38
@@ -6,8 +6,10 @@
|
|||||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
@@ -20,6 +22,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
|||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.SimpleType
|
import org.jetbrains.kotlin.types.SimpleType
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
@@ -30,11 +33,16 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
|||||||
private val memberToTransformer: Map<SimpleMemberKey, (IrCall) -> IrCall>
|
private val memberToTransformer: Map<SimpleMemberKey, (IrCall) -> IrCall>
|
||||||
private val memberToIrFunction: Map<SimpleMemberKey, IrSimpleFunction>
|
private val memberToIrFunction: Map<SimpleMemberKey, IrSimpleFunction>
|
||||||
private val symbolToIrFunction: Map<IrFunctionSymbol, IrSimpleFunction>
|
private val symbolToIrFunction: Map<IrFunctionSymbol, IrSimpleFunction>
|
||||||
|
private val nameToIrTransformer: Map<Name, (IrCall) -> IrCall>
|
||||||
|
|
||||||
|
val kCallable = context.builtIns.getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.kCallable.toSafe())
|
||||||
|
val kProperty = context.builtIns.getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.kProperty.asSingleFqName())
|
||||||
|
|
||||||
init {
|
init {
|
||||||
memberToIrFunction = mutableMapOf()
|
memberToIrFunction = mutableMapOf()
|
||||||
symbolToIrFunction = mutableMapOf()
|
symbolToIrFunction = mutableMapOf()
|
||||||
memberToTransformer = mutableMapOf()
|
memberToTransformer = mutableMapOf()
|
||||||
|
nameToIrTransformer = mutableMapOf()
|
||||||
|
|
||||||
val primitiveNumbers = context.irBuiltIns.run { listOf(int, short, byte, float, double) }
|
val primitiveNumbers = context.irBuiltIns.run { listOf(int, short, byte, float, double) }
|
||||||
|
|
||||||
@@ -103,6 +111,25 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nameToIrTransformer.run {
|
||||||
|
addWithPredicate(
|
||||||
|
Name.special(Namer.KCALLABLE_GET_NAME),
|
||||||
|
{ call -> call.symbol.owner.dispatchReceiverParameter?.run { DescriptorUtils.isSubtypeOfClass(type, kCallable) } ?: false },
|
||||||
|
{ call -> irCall(call, context.intrinsics.jsName.symbol, dispatchReceiverAsFirstArgument = true) })
|
||||||
|
|
||||||
|
addWithPredicate(
|
||||||
|
Name.identifier(Namer.KPROPERTY_GET),
|
||||||
|
{ call -> call.symbol.owner.dispatchReceiverParameter?.run { DescriptorUtils.isSubtypeOfClass(type, kProperty) } ?: false },
|
||||||
|
{ call -> irCall(call, context.intrinsics.jsPropertyGet.symbol, dispatchReceiverAsFirstArgument = true)}
|
||||||
|
)
|
||||||
|
|
||||||
|
addWithPredicate(
|
||||||
|
Name.identifier(Namer.KPROPERTY_SET),
|
||||||
|
{ call -> call.symbol.owner.dispatchReceiverParameter?.run { DescriptorUtils.isSubtypeOfClass(type, kProperty) } ?: false},
|
||||||
|
{ call -> irCall(call, context.intrinsics.jsPropertySet.symbol, dispatchReceiverAsFirstArgument = true)}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun lower(irFile: IrFile) {
|
override fun lower(irFile: IrFile) {
|
||||||
@@ -132,7 +159,12 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
|||||||
return it(call)
|
return it(call)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nameToIrTransformer[symbol.owner.name]?.let {
|
||||||
|
return it(call)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return call
|
return call
|
||||||
@@ -196,4 +228,10 @@ private fun <V> MutableMap<IrFunctionSymbol, V>.add(from: IrFunctionSymbol, to:
|
|||||||
put(from, to)
|
put(from, to)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun <K> MutableMap<K, (IrCall) -> IrCall>.addWithPredicate(from: K, predicate: (IrCall) -> Boolean, action: (IrCall) -> IrCall) {
|
||||||
|
put(from) { call: IrCall -> select({ predicate(call) }, { action(call) }, { call }) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun <T> select(crossinline predicate: () -> Boolean, crossinline ifTrue: () -> T, crossinline ifFalse: () -> T): T = if (predicate()) ifTrue() else ifFalse()
|
||||||
|
|
||||||
private data class SimpleMemberKey(val klass: KotlinType, val name: Name)
|
private data class SimpleMemberKey(val klass: KotlinType, val name: Name)
|
||||||
|
|||||||
+5
-4
@@ -6,10 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
|
||||||
class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatement, JsGenerationContext> {
|
class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatement, JsGenerationContext> {
|
||||||
@@ -35,4 +32,8 @@ class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatemen
|
|||||||
)
|
)
|
||||||
return jsAssignment(JsNameRef(fieldName, JsThisRef()), initExpression).makeStmt()
|
return jsAssignment(JsNameRef(fieldName, JsThisRef()), initExpression).makeStmt()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitVariable(declaration: IrVariable, context: JsGenerationContext): JsStatement {
|
||||||
|
return declaration.accept(IrElementToJsStatementTransformer(), context)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-2
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.ir.backend.js.utils.isAny
|
|||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.util.isInterface
|
import org.jetbrains.kotlin.ir.util.isInterface
|
||||||
import org.jetbrains.kotlin.ir.util.isReal
|
import org.jetbrains.kotlin.ir.util.isReal
|
||||||
@@ -34,12 +35,12 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
fun generate(): JsStatement {
|
fun generate(): JsStatement {
|
||||||
|
|
||||||
maybeGeneratePrimaryConstructor()
|
maybeGeneratePrimaryConstructor()
|
||||||
val transformer = IrFunctionToJsTransformer()
|
val transformer = IrDeclarationToJsTransformer()
|
||||||
|
|
||||||
for (declaration in irClass.declarations) {
|
for (declaration in irClass.declarations) {
|
||||||
when (declaration) {
|
when (declaration) {
|
||||||
is IrConstructor -> {
|
is IrConstructor -> {
|
||||||
classBlock.statements += declaration.accept(transformer, context).makeStmt()
|
classBlock.statements += declaration.accept(transformer, context)
|
||||||
classBlock.statements += generateInheritanceCode()
|
classBlock.statements += generateInheritanceCode()
|
||||||
}
|
}
|
||||||
is IrSimpleFunction -> {
|
is IrSimpleFunction -> {
|
||||||
@@ -48,6 +49,9 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
is IrClass -> {
|
is IrClass -> {
|
||||||
classBlock.statements += JsClassGenerator(declaration, context).generate()
|
classBlock.statements += JsClassGenerator(declaration, context).generate()
|
||||||
}
|
}
|
||||||
|
is IrVariable -> {
|
||||||
|
classBlock.statements += declaration.accept(transformer, context)
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+32
@@ -70,6 +70,17 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
|||||||
JsInvocation(Namer.JS_OBJECT_CREATE_FUNCTION, prototype)
|
JsInvocation(Namer.JS_OBJECT_CREATE_FUNCTION, prototype)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
add(intrinsics.jsSetJSField) { call, context ->
|
||||||
|
val args = translateCallArguments(call, context)
|
||||||
|
val receiver = args[0]
|
||||||
|
val fieldName = args[1] as JsStringLiteral
|
||||||
|
val fieldValue = args[2]
|
||||||
|
|
||||||
|
val fieldNameLiteral = fieldName.value!!
|
||||||
|
|
||||||
|
jsAssignment(JsNameRef(fieldNameLiteral, receiver), fieldValue)
|
||||||
|
}
|
||||||
|
|
||||||
add(backendContext.sharedVariablesManager.closureBoxConstructorTypeSymbol) { call, context ->
|
add(backendContext.sharedVariablesManager.closureBoxConstructorTypeSymbol) { call, context ->
|
||||||
val args = translateCallArguments(call, context)
|
val args = translateCallArguments(call, context)
|
||||||
val initializer = args[0]
|
val initializer = args[0]
|
||||||
@@ -86,6 +97,27 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
|||||||
else -> JsInvocation(JsFunction(context.currentScope, jsCode as? JsBlock ?: JsBlock(jsCode as JsStatement), ""))
|
else -> JsInvocation(JsFunction(context.currentScope, jsCode as? JsBlock ?: JsBlock(jsCode as JsStatement), ""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
add(intrinsics.jsName) { call: IrCall, context ->
|
||||||
|
val args = translateCallArguments(call, context)
|
||||||
|
val receiver = args[0]
|
||||||
|
JsNameRef(Namer.KCALLABLE_NAME, receiver)
|
||||||
|
}
|
||||||
|
|
||||||
|
add(intrinsics.jsPropertyGet) { call: IrCall, context ->
|
||||||
|
val args = translateCallArguments(call, context)
|
||||||
|
val reference = args[0]
|
||||||
|
val receiver = args[1]
|
||||||
|
JsInvocation(JsNameRef(Namer.KPROPERTY_GET, reference), listOf(receiver))
|
||||||
|
}
|
||||||
|
|
||||||
|
add(intrinsics.jsPropertySet) { call: IrCall, context ->
|
||||||
|
val args = translateCallArguments(call, context)
|
||||||
|
val reference = args[0]
|
||||||
|
val receiver = args[1]
|
||||||
|
val value = args[2]
|
||||||
|
JsInvocation(JsNameRef(Namer.KPROPERTY_SET, reference), listOf(receiver, value))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ object Namer {
|
|||||||
val SLICE_FUNCTION = "slice"
|
val SLICE_FUNCTION = "slice"
|
||||||
val CONCAT_FUNCTION = "concat"
|
val CONCAT_FUNCTION = "concat"
|
||||||
|
|
||||||
|
val OUTER_NAME = "\$outer"
|
||||||
val UNREACHABLE_NAME = "\$unreachable"
|
val UNREACHABLE_NAME = "\$unreachable"
|
||||||
|
|
||||||
val OUTER_FIELD_NAME = "\$outer"
|
val OUTER_FIELD_NAME = "\$outer"
|
||||||
@@ -85,6 +86,12 @@ object Namer {
|
|||||||
val GETTER_PREFIX = "get_"
|
val GETTER_PREFIX = "get_"
|
||||||
val SETTER_PREFIX = "set_"
|
val SETTER_PREFIX = "set_"
|
||||||
|
|
||||||
|
val KCALLABLE_GET_NAME = "<get-name>"
|
||||||
|
val KCALLABLE_NAME = "callableName"
|
||||||
|
val KPROPERTY_GET = "get"
|
||||||
|
val KPROPERTY_SET = "set"
|
||||||
|
val KCALLABLE_CACHE_SUFFIX = "\$cache"
|
||||||
|
|
||||||
val SETTER_ARGUMENT = "\$setValue"
|
val SETTER_ARGUMENT = "\$setValue"
|
||||||
|
|
||||||
val THIS_SPECIAL_NAME = "<this>"
|
val THIS_SPECIAL_NAME = "<this>"
|
||||||
|
|||||||
+28
-2
@@ -6,13 +6,15 @@
|
|||||||
package org.jetbrains.kotlin.ir.backend.js.utils
|
package org.jetbrains.kotlin.ir.backend.js.utils
|
||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
val IrConstructorSymbol.constructedClass get() = descriptor.constructedClass
|
val IrConstructorSymbol.constructedClass get() = descriptor.constructedClass
|
||||||
|
|
||||||
@@ -25,3 +27,27 @@ fun ModuleDescriptor.getFunctions(fqName: FqName): List<FunctionDescriptor> {
|
|||||||
fun ModuleDescriptor.getFunctions(packageFqName: FqName, name: Name): List<FunctionDescriptor> {
|
fun ModuleDescriptor.getFunctions(packageFqName: FqName, name: Name): List<FunctionDescriptor> {
|
||||||
return getPackage(packageFqName).memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND).toList()
|
return getPackage(packageFqName).memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND).toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ModuleDescriptor.getClassifier(fqName: FqName): ClassifierDescriptor? {
|
||||||
|
return getClassifier(fqName.parent(), fqName.shortName())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ModuleDescriptor.getClassifier(packageFqName: FqName, name: Name): ClassifierDescriptor? {
|
||||||
|
return getPackage(packageFqName).memberScope.getContributedClassifier(name, NoLookupLocation.FROM_BACKEND)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createValueParameter(containingDeclaration: CallableDescriptor, index: Int, name: String, type: KotlinType): ValueParameterDescriptor {
|
||||||
|
return ValueParameterDescriptorImpl(
|
||||||
|
containingDeclaration = containingDeclaration,
|
||||||
|
original = null,
|
||||||
|
index = index,
|
||||||
|
annotations = Annotations.EMPTY,
|
||||||
|
name = Name.identifier(name),
|
||||||
|
outType = type,
|
||||||
|
declaresDefaultValue = false,
|
||||||
|
isCrossinline = false,
|
||||||
|
isNoinline = false,
|
||||||
|
varargElementType = null,
|
||||||
|
source = SourceElement.NO_SOURCE
|
||||||
|
)
|
||||||
|
}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
// EXPECTED_REACHABLE_NODES: 1109
|
||||||
|
// This test was adapted from compiler/testData/codegen/box/callableReference/function/local/.
|
||||||
|
package foo
|
||||||
|
|
||||||
|
import kotlin.reflect.KFunction
|
||||||
|
|
||||||
|
fun foo0() = "OK"
|
||||||
|
fun foo1(a: String) = "O" + a
|
||||||
|
fun foo2(a: String, b: String) = a + b
|
||||||
|
|
||||||
|
fun refName0(ref: KFunction<String>) = ref.name
|
||||||
|
//fun refName1(ref: KFunction1<String, String>) = ref.name
|
||||||
|
//fun refName2(ref: KFunction2<String, String, String>) = ref.name
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val name = refName0(::foo0)
|
||||||
|
val f1 = ::foo1
|
||||||
|
val f2 = ::foo2
|
||||||
|
|
||||||
|
if (name != "foo0") return "Fail: " + name
|
||||||
|
if (f1.name != "foo1") return "Fail: " + f1.name
|
||||||
|
if (f2.name != "foo2") return "Fail: " + f2.name
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user