Implement function literals in JS BE
This commit is contained in:
+1
-1
@@ -3,7 +3,7 @@
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.descriptors
|
||||
package org.jetbrains.kotlin.backend.common.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
+4
-3
@@ -73,6 +73,7 @@ class LocalDeclarationsLowering(val context: BackendContext, val localNameProvid
|
||||
is IrProperty -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
|
||||
is IrField -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
|
||||
is IrAnonymousInitializer -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
|
||||
// TODO: visit children as well
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
@@ -178,8 +179,6 @@ class LocalDeclarationsLowering(val context: BackendContext, val localNameProvid
|
||||
|
||||
private fun collectRewrittenDeclarations(): ArrayList<IrDeclaration> =
|
||||
ArrayList<IrDeclaration>(localFunctions.size + localClasses.size + 1).apply {
|
||||
add(memberDeclaration)
|
||||
|
||||
localFunctions.values.mapTo(this) {
|
||||
val original = it.declaration
|
||||
it.transformedDeclaration.apply {
|
||||
@@ -195,6 +194,8 @@ class LocalDeclarationsLowering(val context: BackendContext, val localNameProvid
|
||||
localClasses.values.mapTo(this) {
|
||||
it.declaration
|
||||
}
|
||||
|
||||
add(memberDeclaration)
|
||||
}
|
||||
|
||||
private inner class FunctionBodiesRewriter(val localContext: LocalContext?) : IrElementTransformerVoid() {
|
||||
@@ -490,7 +491,7 @@ class LocalDeclarationsLowering(val context: BackendContext, val localNameProvid
|
||||
newValueParameters,
|
||||
oldDescriptor.returnType,
|
||||
Modality.FINAL,
|
||||
Visibilities.PRIVATE
|
||||
Visibilities.LOCAL
|
||||
)
|
||||
|
||||
oldDescriptor.extensionReceiverParameter?.let {
|
||||
|
||||
@@ -7,9 +7,12 @@ package org.jetbrains.kotlin.ir.backend.js
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
|
||||
|
||||
object JsLoweredDeclarationOrigin : IrDeclarationOrigin {
|
||||
object CLASS_STATIC_INITIALIZER : IrDeclarationOriginImpl("CLASS_STATIC_INITIALIZER")
|
||||
object SECONDARY_CTOR_RECEIVER : IrDeclarationOriginImpl("SECONDARY_CTOR_RECEIVER")
|
||||
object JS_INTRINSICS_STUB : IrDeclarationOriginImpl("JS_INTRINSICS_STUB")
|
||||
object JS_CLOSURE_BOX_CLASS : IrStatementOriginImpl("JS_CLOSURE_BOX_CLASS")
|
||||
object JS_LAMBDA_CREATION : IrDeclarationOriginImpl("JS_LAMBDA_CREATION")
|
||||
}
|
||||
+15
-7
@@ -7,24 +7,31 @@ package org.jetbrains.kotlin.ir.backend.js
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.ReflectionTypes
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.KnownPackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.ir.Ir
|
||||
import org.jetbrains.kotlin.backend.common.ir.Symbols
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.types.KotlinTypeFactory
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
class JsIrBackendContext(
|
||||
val module: ModuleDescriptor,
|
||||
@@ -36,7 +43,8 @@ class JsIrBackendContext(
|
||||
val intrinsics = JsIntrinsics(module, irBuiltIns, symbolTable)
|
||||
|
||||
override val builtIns = module.builtIns
|
||||
override val sharedVariablesManager = JsSharedVariablesManager(builtIns)
|
||||
override val sharedVariablesManager =
|
||||
JsSharedVariablesManager(builtIns, KnownPackageFragmentDescriptor(builtIns.builtInsModule, FqName("kotlin.js.internal")))
|
||||
|
||||
override val reflectionTypes: ReflectionTypes by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||
// TODO
|
||||
|
||||
+189
-14
@@ -5,29 +5,204 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.KnownClassDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.SharedVariablesManager
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.*
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrGetValue
|
||||
import org.jetbrains.kotlin.ir.expressions.IrSetVariable
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.types.*
|
||||
|
||||
class JsSharedVariablesManager(builtIns: KotlinBuiltIns): SharedVariablesManager {
|
||||
override fun createSharedVariableDescriptor(variableDescriptor: VariableDescriptor): VariableDescriptor {
|
||||
TODO("not implemented")
|
||||
}
|
||||
class JsSharedVariablesManager(val builtIns: KotlinBuiltIns, val jsInterinalPackage: PackageFragmentDescriptor) : SharedVariablesManager {
|
||||
|
||||
override fun createSharedVariableDescriptor(variableDescriptor: VariableDescriptor): VariableDescriptor =
|
||||
LocalVariableDescriptor(
|
||||
variableDescriptor.containingDeclaration, Annotations.EMPTY, variableDescriptor.name,
|
||||
getSharedVariableType(variableDescriptor.type),
|
||||
false, false, variableDescriptor.isLateInit, variableDescriptor.source
|
||||
)
|
||||
|
||||
override fun defineSharedValue(sharedVariableDescriptor: VariableDescriptor, originalDeclaration: IrVariable): IrStatement {
|
||||
TODO("not implemented")
|
||||
val valueType = originalDeclaration.descriptor.type
|
||||
val boxConstructor = closureBoxConstructorTypeDescriptor
|
||||
val boxConstructorSymbol = closureBoxConstrctorTypeSymbol
|
||||
val constructorTypeParam = closureBoxConstructorTypeDescriptor.typeParameters[0]
|
||||
val boxConstructorTypeArgument = mapOf(constructorTypeParam to valueType)
|
||||
val initializer = originalDeclaration.initializer ?: IrConstImpl.constNull(
|
||||
originalDeclaration.startOffset,
|
||||
originalDeclaration.endOffset,
|
||||
valueType
|
||||
)
|
||||
val constructorCall = IrCallImpl(
|
||||
originalDeclaration.startOffset,
|
||||
originalDeclaration.endOffset,
|
||||
boxConstructorSymbol,
|
||||
boxConstructor,
|
||||
boxConstructorTypeArgument,
|
||||
JsLoweredDeclarationOrigin.JS_CLOSURE_BOX_CLASS
|
||||
).apply { putValueArgument(0, initializer) }
|
||||
|
||||
|
||||
return IrVariableImpl(
|
||||
originalDeclaration.startOffset,
|
||||
originalDeclaration.endOffset,
|
||||
originalDeclaration.origin,
|
||||
sharedVariableDescriptor,
|
||||
constructorCall
|
||||
)
|
||||
}
|
||||
|
||||
override fun getSharedValue(sharedVariableDescriptor: VariableDescriptor, originalGet: IrGetValue): IrExpression {
|
||||
TODO("not implemented")
|
||||
override fun getSharedValue(sharedVariableDescriptor: VariableDescriptor, originalGet: IrGetValue): IrExpression =
|
||||
IrGetFieldImpl(
|
||||
originalGet.startOffset, originalGet.endOffset,
|
||||
closureBoxFieldSymbol,
|
||||
IrGetValueImpl(
|
||||
originalGet.startOffset,
|
||||
originalGet.endOffset,
|
||||
symbolForDescriptor(sharedVariableDescriptor)
|
||||
),
|
||||
originalGet.origin
|
||||
)
|
||||
|
||||
override fun setSharedValue(sharedVariableDescriptor: VariableDescriptor, originalSet: IrSetVariable): IrExpression =
|
||||
IrSetFieldImpl(
|
||||
originalSet.startOffset, originalSet.endOffset,
|
||||
closureBoxFieldSymbol,
|
||||
IrGetValueImpl(
|
||||
originalSet.startOffset,
|
||||
originalSet.endOffset,
|
||||
symbolForDescriptor(sharedVariableDescriptor)
|
||||
),
|
||||
originalSet.value,
|
||||
originalSet.origin
|
||||
)
|
||||
|
||||
private val boxTypeName = "\$closureBox\$"
|
||||
|
||||
private val closureBoxTypeDescriptor = createClosureBoxClass()
|
||||
private val closureBoxConstructorTypeDescriptor = createClosureBoxClassConstructor()
|
||||
private val closureBoxFieldDescriptor = createClosureBoxField()
|
||||
|
||||
private val closureBoxTypeSymbol = IrClassSymbolImpl(closureBoxTypeDescriptor)
|
||||
val closureBoxConstrctorTypeSymbol = createFunctionSymbol(closureBoxConstructorTypeDescriptor)
|
||||
private val closureBoxFieldSymbol = IrFieldSymbolImpl(closureBoxFieldDescriptor)
|
||||
|
||||
|
||||
private fun createClosureBoxClass(): ClassDescriptor =
|
||||
KnownClassDescriptor.createClassWithTypeParameters(
|
||||
Name.identifier(boxTypeName), jsInterinalPackage, listOf(builtIns.anyType), listOf(
|
||||
Name.identifier("T")
|
||||
)
|
||||
)
|
||||
|
||||
private fun createClosureBoxClassConstructor(): ClassConstructorDescriptor =
|
||||
ClassConstructorDescriptorImpl.create(
|
||||
closureBoxTypeDescriptor,
|
||||
Annotations.EMPTY,
|
||||
true,
|
||||
SourceElement.NO_SOURCE
|
||||
).apply {
|
||||
|
||||
/// constructor<T>(v: T) : T
|
||||
|
||||
val typeParameter = constructedClass.declaredTypeParameters[0]
|
||||
|
||||
|
||||
// val typeParameter = typeParameters[0]
|
||||
val typeParameterType = KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(
|
||||
Annotations.EMPTY,
|
||||
typeParameter.typeConstructor,
|
||||
listOf(),
|
||||
false,
|
||||
MemberScope.Empty
|
||||
)
|
||||
|
||||
val parameterType = KotlinTypeFactory.simpleType(
|
||||
Annotations.EMPTY,
|
||||
typeParameter.typeConstructor,
|
||||
listOf(), true
|
||||
)
|
||||
|
||||
val paramDesc = ValueParameterDescriptorImpl(
|
||||
this,
|
||||
null,
|
||||
0,
|
||||
Annotations.EMPTY,
|
||||
Name.identifier("v"),
|
||||
parameterType,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
null,
|
||||
SourceElement.NO_SOURCE
|
||||
)
|
||||
|
||||
initialize(listOf(paramDesc), Visibilities.PUBLIC)
|
||||
returnType = KotlinTypeFactory.simpleNotNullType(
|
||||
Annotations.EMPTY,
|
||||
closureBoxTypeDescriptor,
|
||||
listOf(TypeProjectionImpl(Variance.INVARIANT, typeParameterType))
|
||||
)
|
||||
}
|
||||
|
||||
private fun createClosureBoxField(): PropertyDescriptor {
|
||||
val desc = PropertyDescriptorImpl.create(
|
||||
closureBoxTypeDescriptor,
|
||||
Annotations.EMPTY,
|
||||
Modality.FINAL,
|
||||
Visibilities.PUBLIC,
|
||||
true,
|
||||
Name.identifier("v"),
|
||||
CallableMemberDescriptor.Kind.DECLARATION,
|
||||
SourceElement.NO_SOURCE,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
)
|
||||
|
||||
|
||||
desc.setType(builtIns.anyType, emptyList(), closureBoxTypeDescriptor.thisAsReceiverParameter, null as ReceiverParameterDescriptor?)
|
||||
desc.initialize(null, null)
|
||||
|
||||
return desc
|
||||
}
|
||||
|
||||
override fun setSharedValue(sharedVariableDescriptor: VariableDescriptor, originalSet: IrSetVariable): IrExpression {
|
||||
TODO("not implemented")
|
||||
}
|
||||
private fun getSubstitutedRefConstructor(valueType: KotlinType): ClassConstructorDescriptor =
|
||||
closureBoxConstructorTypeDescriptor.substitute(
|
||||
TypeSubstitutor.create(
|
||||
closureBoxConstructorTypeDescriptor.typeParameters.associate {
|
||||
it.typeConstructor to TypeProjectionImpl(
|
||||
Variance.INVARIANT,
|
||||
valueType
|
||||
)
|
||||
}
|
||||
)
|
||||
)!!
|
||||
|
||||
private fun getRefType(valueType: KotlinType) =
|
||||
KotlinTypeFactory.simpleNotNullType(
|
||||
Annotations.EMPTY,
|
||||
closureBoxTypeDescriptor,
|
||||
listOf(TypeProjectionImpl(Variance.INVARIANT, valueType))
|
||||
)
|
||||
|
||||
private fun getSharedVariableType(type: KotlinType) = getRefType(type)
|
||||
|
||||
private val variableSymbols = mutableMapOf<VariableDescriptor, IrValueSymbol>()
|
||||
|
||||
private fun symbolForDescriptor(sharedVariableDescriptor: VariableDescriptor): IrValueSymbol =
|
||||
variableSymbols.getOrPut(sharedVariableDescriptor, { IrVariableSymbolImpl(sharedVariableDescriptor) })
|
||||
}
|
||||
|
||||
@@ -9,8 +9,7 @@ import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.backend.common.lower.*
|
||||
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
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.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
|
||||
@@ -56,11 +55,13 @@ fun compile(
|
||||
|
||||
fun JsIrBackendContext.lower(file: IrFile) {
|
||||
LateinitLowering(this, true).lower(file)
|
||||
LocalFunctionsLowering(this).lower(file)
|
||||
DefaultArgumentStubGenerator(this).runOnFilePostfix(file)
|
||||
SharedVariablesLowering(this).runOnFilePostfix(file)
|
||||
LocalDeclarationsLowering(this).runOnFilePostfix(file)
|
||||
PropertiesLowering().lower(file)
|
||||
InitializersLowering(this, JsLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, false).runOnFilePostfix(file)
|
||||
SecondaryCtorLowering(this).lower(file)
|
||||
|
||||
IntrinsicifyCallsLowering(this).lower(file)
|
||||
FunctionReferenceLowering(this).lower(file)
|
||||
|
||||
}
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* 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.FileLoweringPass
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
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.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
|
||||
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.*
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.visitors.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class FunctionReferenceLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.acceptVoid(FunctionReferenceCollector())
|
||||
irFile.transformChildrenVoid(LambdaFunctionVisitor())
|
||||
irFile.transformChildrenVoid(FunctionReferenceVisitor())
|
||||
lambdaImpls.forEach { it.transformChildrenVoid(FunctionReferenceVisitor()) }
|
||||
}
|
||||
|
||||
val lambdas = mutableMapOf<IrFunction, KotlinType>()
|
||||
val oldToNewDeclMap = mutableMapOf<IrSymbolOwner, IrFunction>()
|
||||
val lambdaImpls = mutableListOf<IrFunction>()
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
inner class FunctionReferenceVisitor : IrElementTransformerVoid() {
|
||||
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
|
||||
val newTarget = oldToNewDeclMap[expression.symbol.owner]
|
||||
|
||||
return if (newTarget != null) IrCallImpl(expression.startOffset, expression.endOffset, newTarget.symbol).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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inner class LambdaFunctionVisitor : IrElementTransformerVoid() {
|
||||
override fun visitFunction(declaration: IrFunction): IrStatement {
|
||||
if (declaration !in lambdas.keys) return declaration
|
||||
|
||||
// transform
|
||||
// foo$lambda(a: A, b: B, c: closure$C, d: closure$D) { /*body*/ } ===>
|
||||
// foo$lambda(c: closure$C, d: closure$D) {
|
||||
// var $funcRef = function(a: A, b: B) { /*body*/ }
|
||||
// return $funcRef
|
||||
// }
|
||||
|
||||
val functionType = lambdas[declaration]!!
|
||||
|
||||
// FunctionN<T1, T2, ..., TN, TReturn>, arguments.size = N + 1
|
||||
|
||||
val lambdaParamCount =
|
||||
if (declaration.extensionReceiverParameter == null) functionType.arguments.size - 1 else functionType.arguments.size - 2
|
||||
|
||||
assert(lambdaParamCount >= 0)
|
||||
|
||||
val descriptor = SimpleFunctionDescriptorImpl.create(
|
||||
declaration.descriptor.containingDeclaration,
|
||||
Annotations.EMPTY,
|
||||
Name.identifier("${declaration.descriptor.name}_impl"),
|
||||
declaration.descriptor.kind,
|
||||
declaration.descriptor.source
|
||||
)
|
||||
descriptor.initialize(
|
||||
null,
|
||||
declaration.descriptor.dispatchReceiverParameter,
|
||||
// declaration.descriptor.typeParameters,
|
||||
emptyList(),
|
||||
declaration.descriptor.valueParameters.drop(declaration.valueParameters.size - lambdaParamCount).mapIndexed { index, valueParameterDescriptor ->
|
||||
valueParameterDescriptor.copy(descriptor, valueParameterDescriptor.name, index)
|
||||
},
|
||||
declaration.descriptor.returnType,
|
||||
declaration.descriptor.modality,
|
||||
declaration.descriptor.visibility
|
||||
)
|
||||
|
||||
val symbol = IrSimpleFunctionSymbolImpl(descriptor)
|
||||
val func = IrFunctionImpl(declaration.startOffset, declaration.endOffset, declaration.origin, symbol).apply {
|
||||
dispatchReceiverParameter = declaration.dispatchReceiverParameter
|
||||
extensionReceiverParameter = declaration.extensionReceiverParameter
|
||||
declaration.valueParameters.drop(declaration.valueParameters.size - lambdaParamCount).forEachIndexed { index, param ->
|
||||
valueParameters += IrValueParameterImpl(
|
||||
param.startOffset,
|
||||
param.endOffset,
|
||||
param.origin,
|
||||
descriptor.valueParameters[index]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val newDeclDescriptor = SimpleFunctionDescriptorImpl.create(
|
||||
declaration.descriptor.containingDeclaration,
|
||||
declaration.descriptor.annotations,
|
||||
declaration.descriptor.name,
|
||||
declaration.descriptor.kind,
|
||||
declaration.descriptor.source
|
||||
).initialize(
|
||||
null,
|
||||
declaration.descriptor.dispatchReceiverParameter,
|
||||
// declaration.descriptor.typeParameters,
|
||||
emptyList(),
|
||||
declaration.descriptor.valueParameters.dropLast(lambdaParamCount),
|
||||
functionType,
|
||||
declaration.descriptor.modality,
|
||||
declaration.descriptor.visibility
|
||||
)
|
||||
val newDeclSymbol = IrSimpleFunctionSymbolImpl(newDeclDescriptor)
|
||||
|
||||
val funcReference = IrFunctionReferenceImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, functionType, symbol, descriptor, null, null)
|
||||
val varDescriptor = IrTemporaryVariableDescriptorImpl(newDeclDescriptor, Name.identifier("\$funRef"), functionType)
|
||||
val closureStmt = IrVariableImpl(
|
||||
declaration.startOffset,
|
||||
declaration.endOffset,
|
||||
JsLoweredDeclarationOrigin.JS_LAMBDA_CREATION,
|
||||
varDescriptor,
|
||||
funcReference
|
||||
)
|
||||
val returnStmt = IrReturnImpl(
|
||||
declaration.startOffset,
|
||||
declaration.endOffset,
|
||||
symbol,
|
||||
IrGetValueImpl(declaration.startOffset, declaration.endOffset, IrVariableSymbolImpl(varDescriptor))
|
||||
)
|
||||
|
||||
val oldBody = declaration.body
|
||||
|
||||
val newBody = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, listOf(closureStmt, returnStmt))
|
||||
func.body = oldBody
|
||||
|
||||
lambdaImpls += func
|
||||
|
||||
val newDeclaration = IrFunctionImpl(declaration.startOffset, declaration.endOffset, declaration.origin, newDeclSymbol).apply {
|
||||
body = newBody
|
||||
valueParameters += declaration.valueParameters.dropLast(lambdaParamCount)
|
||||
}
|
||||
|
||||
oldToNewDeclMap[declaration] = newDeclaration
|
||||
|
||||
return newDeclaration
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-8
@@ -114,16 +114,19 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
||||
return irCall(call, it.symbol)
|
||||
}
|
||||
|
||||
(symbol.owner as? IrFunction)?.dispatchReceiverParameter?.let {
|
||||
val key = SimpleMemberKey(it.type, symbol.name)
|
||||
if (symbol.isBound) {
|
||||
|
||||
memberToIrFunction[key]?.let {
|
||||
// TODO: don't apply intrinsics when type of receiver or argument is Long
|
||||
return irCall(call, it.symbol, dispatchReceiverAsFirstArgument = true)
|
||||
}
|
||||
(symbol.owner as? IrFunction)?.dispatchReceiverParameter?.let {
|
||||
val key = SimpleMemberKey(it.type, symbol.name)
|
||||
|
||||
memberToTransformer[key]?.let {
|
||||
return it(call)
|
||||
memberToIrFunction[key]?.let {
|
||||
// TODO: don't apply intrinsics when type of receiver or argument is Long
|
||||
return irCall(call, it.symbol, dispatchReceiverAsFirstArgument = true)
|
||||
}
|
||||
|
||||
memberToTransformer[key]?.let {
|
||||
return it(call)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-4
@@ -268,11 +268,18 @@ class SecondaryCtorLowering(val context: JsIrBackendContext) : IrElementTransfor
|
||||
override fun visitFunction(declaration: IrFunction, data: IrFunction?): IrStatement = super.visitFunction(declaration, declaration)
|
||||
|
||||
override fun visitCall(expression: IrCall, ownerFunc: IrFunction?): IrElement {
|
||||
val target = expression.symbol.owner as IrFunction
|
||||
if (expression.symbol.isBound) {
|
||||
|
||||
if (target is IrConstructor) {
|
||||
if (!target.descriptor.isPrimary) {
|
||||
return redirectCall(expression, context.secondaryConstructorsMap[target.symbol]!!.stub)
|
||||
val target = expression.symbol.owner as IrFunction
|
||||
|
||||
if (target is IrConstructor) {
|
||||
if (!target.descriptor.isPrimary) {
|
||||
val ctor = context.secondaryConstructorsMap[target.symbol]
|
||||
if (ctor != null) {
|
||||
|
||||
return redirectCall(expression, ctor.stub)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-4
@@ -11,9 +11,6 @@ import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
|
||||
class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatement, JsGenerationContext> {
|
||||
override fun visitProperty(declaration: IrProperty, context: JsGenerationContext): JsStatement {
|
||||
return jsVar(declaration.name, declaration.backingField?.initializer?.expression, context)
|
||||
}
|
||||
|
||||
override fun visitSimpleFunction(declaration: IrSimpleFunction, context: JsGenerationContext): JsStatement {
|
||||
return declaration.accept(IrFunctionToJsTransformer(), context).makeStmt()
|
||||
@@ -28,7 +25,7 @@ class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatemen
|
||||
}
|
||||
|
||||
override fun visitField(declaration: IrField, context: JsGenerationContext): JsStatement {
|
||||
val fieldName = declaration.name.toJsName()
|
||||
val fieldName = context.getNameForSymbol(declaration.symbol)
|
||||
val initExpression =
|
||||
declaration.initializer?.accept(IrElementToJsExpressionTransformer(), context) ?: JsPrefixOperation(
|
||||
JsUnaryOperator.VOID,
|
||||
|
||||
+45
-32
@@ -5,32 +5,37 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||
|
||||
import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.isSpecial
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.name
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsExpression, JsGenerationContext> {
|
||||
|
||||
// TODO: should we prohibit using blocks as expression in the future?
|
||||
override fun visitBlock(expression: IrBlock, context: JsGenerationContext): JsExpression {
|
||||
if (expression.statements.isEmpty()) {
|
||||
// TODO: what should we do here? Crash? Generate throw? Should it be treated as unreachable code?
|
||||
return super.visitBlock(expression, context)
|
||||
private val neutralExpression: JsExpression = JsPrefixOperation(JsUnaryOperator.VOID, JsIntLiteral(1))
|
||||
|
||||
override fun visitContainerExpression(expression: IrContainerExpression, context: JsGenerationContext): JsExpression =
|
||||
expression.statements.map { it.accept(this, context) }.fold(neutralExpression) { left, right ->
|
||||
if (left != neutralExpression) JsBinaryOperation(JsBinaryOperator.COMMA, left, right) else right
|
||||
}
|
||||
|
||||
return expression.statements
|
||||
.map { it.accept(this, context) }
|
||||
.reduce { left, right -> JsBinaryOperation(JsBinaryOperator.COMMA, left, right) }
|
||||
}
|
||||
override fun visitBlock(expression: IrBlock, data: JsGenerationContext): JsExpression = visitContainerExpression(expression, data)
|
||||
|
||||
override fun visitExpressionBody(body: IrExpressionBody, context: JsGenerationContext): JsExpression {
|
||||
return body.expression.accept(this, context)
|
||||
override fun visitComposite(expression: IrComposite, data: JsGenerationContext): JsExpression =
|
||||
visitContainerExpression(expression, data)
|
||||
|
||||
override fun visitExpressionBody(body: IrExpressionBody, context: JsGenerationContext): JsExpression =
|
||||
body.expression.accept(this, context)
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference, context: JsGenerationContext): JsExpression {
|
||||
val irFunction = expression.symbol.owner as IrFunction
|
||||
return irFunction.accept(IrFunctionToJsTransformer(), context)
|
||||
}
|
||||
|
||||
override fun <T> visitConst(expression: IrConst<T>, context: JsGenerationContext): JsExpression {
|
||||
@@ -61,36 +66,36 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
}
|
||||
|
||||
override fun visitGetField(expression: IrGetField, context: JsGenerationContext): JsExpression {
|
||||
return JsNameRef(expression.symbol.name.asString(), expression.receiver?.accept(this, context))
|
||||
val fieldName = context.getNameForSymbol(expression.symbol)
|
||||
return JsNameRef(fieldName, expression.receiver?.accept(this, context))
|
||||
}
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue, context: JsGenerationContext): JsExpression {
|
||||
|
||||
return if (expression.symbol.isSpecial) {
|
||||
context.getSpecialRefForName(expression.symbol.name)
|
||||
} else {
|
||||
JsNameRef(context.getNameForSymbol(expression.symbol))
|
||||
}
|
||||
override fun visitGetValue(expression: IrGetValue, context: JsGenerationContext): JsExpression =
|
||||
context.getNameForSymbol(expression.symbol).makeRef()
|
||||
|
||||
override fun visitGetObjectValue(expression: IrGetObjectValue, data: JsGenerationContext): JsExpression {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override fun visitSetField(expression: IrSetField, context: JsGenerationContext): JsExpression {
|
||||
val dest = JsNameRef(expression.symbol.name.asString(), expression.receiver?.accept(this, context))
|
||||
val fieldName = context.getNameForSymbol(expression.symbol)
|
||||
val dest = JsNameRef(fieldName, expression.receiver?.accept(this, context))
|
||||
val source = expression.value.accept(this, context)
|
||||
return jsAssignment(dest, source)
|
||||
}
|
||||
|
||||
override fun visitSetVariable(expression: IrSetVariable, context: JsGenerationContext): JsExpression {
|
||||
val ref = JsNameRef(expression.symbol.name.toJsName())
|
||||
val ref = JsNameRef(context.getNameForSymbol(expression.symbol))
|
||||
val value = expression.value.accept(this, context)
|
||||
return JsBinaryOperation(JsBinaryOperator.ASG, ref, value)
|
||||
}
|
||||
|
||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, context: JsGenerationContext): JsExpression {
|
||||
val classNameRef = expression.symbol.owner.descriptor.constructedClass.name.toJsName().makeRef()
|
||||
val classNameRef = context.getNameForSymbol(expression.symbol).makeRef()
|
||||
val callFuncRef = JsNameRef(Namer.CALL_FUNCTION, classNameRef)
|
||||
val fromPrimary = context.currentFunction is IrConstructor
|
||||
val thisRef = if (fromPrimary) JsThisRef() else JsNameRef("\$this")
|
||||
val thisRef =
|
||||
if (fromPrimary) JsThisRef() else context.getNameForSymbol(context.currentFunction!!.valueParameters.last().symbol).makeRef()
|
||||
val arguments = translateCallArguments(expression, context)
|
||||
return JsInvocation(callFuncRef, listOf(thisRef) + arguments)
|
||||
}
|
||||
@@ -102,18 +107,26 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
return it(expression, context)
|
||||
}
|
||||
|
||||
val dispatchReceiver = expression.dispatchReceiver?.accept(this, context)
|
||||
val extensionReceiver = expression.extensionReceiver?.accept(this, context)
|
||||
|
||||
val dispatchReceiver = expression.dispatchReceiver
|
||||
val jsDispatchReceiver = expression.dispatchReceiver?.accept(this, context)
|
||||
val jsExtensionReceiver = expression.extensionReceiver?.accept(this, context)
|
||||
val arguments = translateCallArguments(expression, context)
|
||||
|
||||
if (dispatchReceiver != null && dispatchReceiver.type.isFunctionTypeOrSubtype && symbol.name == OperatorNameConventions.INVOKE) {
|
||||
return JsInvocation(jsDispatchReceiver!!, arguments)
|
||||
}
|
||||
|
||||
context.staticContext.intrinsics[symbol]?.let {
|
||||
return it(expression, arguments)
|
||||
}
|
||||
|
||||
return if (symbol is IrConstructorSymbol) {
|
||||
JsNew(JsNameRef((symbol.owner.parent as IrClass).name.asString()), arguments)
|
||||
JsNew(context.getNameForSymbol(symbol).makeRef(), arguments)
|
||||
} else {
|
||||
// TODO sanitize name
|
||||
val symbolName = context.getNameForSymbol(symbol)
|
||||
val ref = if (dispatchReceiver != null) JsNameRef(symbolName, dispatchReceiver) else JsNameRef(symbolName)
|
||||
JsInvocation(ref, extensionReceiver?.let { listOf(extensionReceiver) + arguments } ?: arguments)
|
||||
val ref = if (jsDispatchReceiver != null) JsNameRef(symbolName, jsDispatchReceiver) else JsNameRef(symbolName)
|
||||
JsInvocation(ref, jsExtensionReceiver?.let { listOf(jsExtensionReceiver) + arguments } ?: arguments)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,4 +134,4 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
// TODO check when w/o else branch and empty when
|
||||
return expression.toJsNode(this, context, ::JsConditional)!!
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -56,7 +56,8 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
|
||||
}
|
||||
|
||||
override fun visitVariable(declaration: IrVariable, context: JsGenerationContext): JsStatement {
|
||||
return jsVar(declaration.name, declaration.initializer, context)
|
||||
val varName = context.getNameForSymbol(declaration.symbol)
|
||||
return jsVar(varName, declaration.initializer, context)
|
||||
}
|
||||
|
||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, context: JsGenerationContext): JsStatement {
|
||||
|
||||
+2
-3
@@ -21,8 +21,7 @@ open class IrFunctionToJsTransformer : BaseIrElementToJsNodeTransformer<JsFuncti
|
||||
|
||||
override fun visitConstructor(declaration: IrConstructor, context: JsGenerationContext): JsFunction {
|
||||
assert(declaration.symbol.isPrimary)
|
||||
return translateFunction(declaration, declaration.symbol.constructedClassName.toJsName(), context)
|
||||
val funcName = context.getNameForSymbol(declaration.symbol)
|
||||
return translateFunction(declaration, funcName, context)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+18
-11
@@ -5,16 +5,15 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
|
||||
class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationContext) {
|
||||
|
||||
private val classNameRef = irClass.name.toJsName().makeRef()
|
||||
private val className = context.getNameForSymbol(irClass.symbol)
|
||||
private val classNameRef = className.makeRef()
|
||||
private val classPrototypeRef = prototypeOf(classNameRef)
|
||||
private val classBlock = JsBlock()
|
||||
|
||||
@@ -31,12 +30,19 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
if (declaration.symbol.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE &&
|
||||
declaration.symbol.modality != Modality.ABSTRACT
|
||||
) {
|
||||
classBlock.statements += declaration.accept(transformer, context).apply { name = null }.let {
|
||||
val memberName = context.getNameForSymbol(declaration.symbol)
|
||||
val memberRef = JsNameRef(memberName, classPrototypeRef)
|
||||
jsAssignment(memberRef, it).makeStmt()
|
||||
classBlock.statements += declaration.accept(transformer, context).let {
|
||||
if (declaration.visibility == Visibilities.LOCAL) {
|
||||
it.makeStmt()
|
||||
} else {
|
||||
val memberName = context.getNameForSymbol(declaration.symbol)
|
||||
val memberRef = JsNameRef(memberName, classPrototypeRef)
|
||||
jsAssignment(memberRef, it).makeStmt()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (declaration is IrClass) {
|
||||
//TODO: redesign inner classes generation
|
||||
classBlock.statements += JsClassGenerator(declaration, context).generate()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +53,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
private fun maybeGeneratePrimaryConstructor() {
|
||||
if (!irClass.declarations.any { it is IrConstructor }) {
|
||||
val func = JsFunction(JsFunctionScope(context.currentScope, "Ctor for ${irClass.name}"), JsBlock(), "Ctor for ${irClass.name}")
|
||||
func.name = irClass.name.toJsName()
|
||||
func.name = className
|
||||
classBlock.statements += func.makeStmt()
|
||||
classBlock.statements += generateInheritanceCode()
|
||||
}
|
||||
@@ -59,8 +65,9 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
val baseName = context.getNameForSymbol(baseClass.owner.symbol)
|
||||
val createCall = jsAssignment(
|
||||
classPrototypeRef, JsInvocation(Namer.JS_OBJECT_CREATE_FUNCTION, prototypeOf(baseClass.owner.name.toJsName().makeRef()))
|
||||
classPrototypeRef, JsInvocation(Namer.JS_OBJECT_CREATE_FUNCTION, prototypeOf(baseName.makeRef()))
|
||||
).makeStmt()
|
||||
|
||||
val ctorAssign = jsAssignment(JsNameRef(Namer.CONSTRUCTOR_NAME, classPrototypeRef), classNameRef).makeStmt()
|
||||
@@ -83,7 +90,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
|
||||
private fun generateSuperClasses(): JsPropertyInitializer = JsPropertyInitializer(
|
||||
JsNameRef(Namer.METADATA_INTERFACES),
|
||||
JsArrayLiteral(irClass.superClasses.filter { it.kind == ClassKind.INTERFACE }.map { JsNameRef(it.owner.name.toJsName()) })
|
||||
JsArrayLiteral(irClass.superClasses.filter { it.kind == ClassKind.INTERFACE }.map { JsNameRef(context.getNameForSymbol(it.owner.symbol)) })
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
+16
-3
@@ -5,7 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIntrinsics
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
@@ -15,10 +15,12 @@ import org.jetbrains.kotlin.js.backend.ast.*
|
||||
|
||||
typealias IrCallTransformer = (IrCall, context: JsGenerationContext) -> JsExpression
|
||||
|
||||
class JsIntrinsicTransformers(intrinsics: JsIntrinsics) {
|
||||
class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
private val transformers: Map<IrSymbol, IrCallTransformer>
|
||||
|
||||
init {
|
||||
val intrinsics = backendContext.intrinsics
|
||||
|
||||
transformers = mutableMapOf()
|
||||
|
||||
transformers.apply {
|
||||
@@ -63,7 +65,14 @@ class JsIntrinsicTransformers(intrinsics: JsIntrinsics) {
|
||||
val classToCreate = call.getTypeArgument(0)!!
|
||||
val prototype = prototypeOf(classToCreate.constructor.declarationDescriptor!!.name.toJsName().makeRef())
|
||||
JsInvocation(Namer.JS_OBJECT_CREATE_FUNCTION, prototype)
|
||||
}
|
||||
|
||||
add(backendContext.sharedVariablesManager.closureBoxConstructorTypeSymbol) { call, context ->
|
||||
val args = translateCallArguments(call, context)
|
||||
val initializer = args[0]
|
||||
val propertyInit = JsPropertyInitializer(JsNameRef("v"), initializer)
|
||||
val objectLiteral = JsObjectLiteral()
|
||||
objectLiteral.apply { propertyInitializers += propertyInit }
|
||||
}
|
||||
|
||||
addIfNotNull(intrinsics.jsCode) { call, context ->
|
||||
@@ -71,7 +80,7 @@ class JsIntrinsicTransformers(intrinsics: JsIntrinsics) {
|
||||
|
||||
when (jsCode) {
|
||||
is JsExpression -> jsCode
|
||||
// TODO don't generate function for this case
|
||||
// TODO don't generate function for this case
|
||||
else -> JsInvocation(JsFunction(context.currentScope, jsCode as? JsBlock ?: JsBlock(jsCode as JsStatement), ""))
|
||||
}
|
||||
}
|
||||
@@ -81,6 +90,10 @@ class JsIntrinsicTransformers(intrinsics: JsIntrinsics) {
|
||||
operator fun get(symbol: IrSymbol): IrCallTransformer? = transformers[symbol]
|
||||
}
|
||||
|
||||
private fun MutableMap<IrSymbol, IrCallTransformer>.add(functionSymbol: IrSymbol, t: IrCallTransformer) {
|
||||
put(functionSymbol, t)
|
||||
}
|
||||
|
||||
private fun MutableMap<IrSymbol, IrCallTransformer>.add(function: IrFunction, t: IrCallTransformer) {
|
||||
put(function.symbol, t)
|
||||
}
|
||||
|
||||
+15
-13
@@ -12,15 +12,23 @@ import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
@Deprecated("Use context.getNameForSymbol(symbol) instead")
|
||||
fun Name.toJsName() = JsDynamicScope.declareName(asString())
|
||||
// TODO don't use JsDynamicScope
|
||||
val dummyScope = JsDynamicScope
|
||||
|
||||
fun jsVar(name: Name, initializer: IrExpression?, context: JsGenerationContext): JsVars {
|
||||
fun Name.toJsName() =
|
||||
// TODO sanitize
|
||||
dummyScope.declareName(asString())
|
||||
|
||||
fun jsVar(name: JsName, initializer: IrExpression?, context: JsGenerationContext): JsVars {
|
||||
val jsInitializer = initializer?.accept(IrElementToJsExpressionTransformer(), context)
|
||||
return JsVars(JsVars.JsVar(name.toJsName(), jsInitializer))
|
||||
return JsVars(JsVars.JsVar(name, jsInitializer))
|
||||
}
|
||||
|
||||
fun <T : JsNode, D : JsGenerationContext> IrWhen.toJsNode(tr: BaseIrElementToJsNodeTransformer<T, D>, data: D, node: (JsExpression, T, T?) -> T): T? =
|
||||
fun <T : JsNode, D : JsGenerationContext> IrWhen.toJsNode(
|
||||
tr: BaseIrElementToJsNodeTransformer<T, D>,
|
||||
data: D,
|
||||
node: (JsExpression, T, T?) -> T
|
||||
): T? =
|
||||
branches.foldRight<IrBranch, T?>(null) { br, n ->
|
||||
val body = br.result.accept(tr, data)
|
||||
if (br is IrElseBranch) body
|
||||
@@ -47,14 +55,8 @@ fun translateFunction(declaration: IrFunction, name: JsName?, context: JsGenerat
|
||||
parameters.add(JsParameter(parameter))
|
||||
}
|
||||
|
||||
declaration.extensionReceiverParameter?.let { function.addParameter("\$receiver") }
|
||||
declaration.valueParameters.forEach {
|
||||
if (it.name.isSpecial) {
|
||||
function.addParameter(context.staticContext.getSpecialNameString(it.name.asString()))
|
||||
} else {
|
||||
function.addParameter(it.name.asString())
|
||||
}
|
||||
}
|
||||
declaration.extensionReceiverParameter?.let { function.addParameter(context.getNameForSymbol(it.symbol).ident) }
|
||||
declaration.valueParameters.forEach { function.addParameter(context.getNameForSymbol(it.symbol).ident) }
|
||||
|
||||
return function
|
||||
}
|
||||
|
||||
-7
@@ -5,16 +5,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.utils
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrElementToJsExpressionTransformer
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrElementToJsStatementTransformer
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.toJsName
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class JsGenerationContext {
|
||||
fun newDeclaration(scope: JsScope, func: IrFunction? = null): JsGenerationContext {
|
||||
@@ -48,5 +42,4 @@ class JsGenerationContext {
|
||||
}
|
||||
|
||||
fun getNameForSymbol(symbol: IrSymbol): JsName = staticContext.getNameForSymbol(symbol)
|
||||
fun getSpecialRefForName(name: Name): JsExpression = staticContext.getSpecialRefForName(name)
|
||||
}
|
||||
+2
-4
@@ -18,11 +18,9 @@ class JsStaticContext(
|
||||
private val rootScope: JsRootScope,
|
||||
private val globalBlock: JsGlobalBlock,
|
||||
private val nameGenerator: NameGenerator,
|
||||
val backendContext: JsIrBackendContext
|
||||
backendContext: JsIrBackendContext
|
||||
) {
|
||||
val intrinsics = JsIntrinsicTransformers(backendContext.intrinsics)
|
||||
val intrinsics = JsIntrinsicTransformers(backendContext)
|
||||
|
||||
fun getNameForSymbol(irSymbol: IrSymbol) = nameGenerator.getNameForSymbol(irSymbol, rootScope)
|
||||
fun getSpecialRefForName(name: Name): JsExpression = nameGenerator.getSpecialRefForName(name)
|
||||
fun getSpecialNameString(specNameString: String): String = nameGenerator.getSpecialNameString(specNameString)
|
||||
}
|
||||
@@ -5,16 +5,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.utils
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsExpression
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsName
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsScope
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
interface NameGenerator {
|
||||
fun getNameForSymbol(symbol: IrSymbol, scope: JsScope): JsName
|
||||
|
||||
fun getSpecialRefForName(name: Name): JsExpression
|
||||
fun getSpecialNameString(specNameString: String): String
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@ object Namer {
|
||||
|
||||
val ROOT_PACKAGE = "_"
|
||||
|
||||
val RECEIVER_PARAMETER_NAME = "\$receiver"
|
||||
val EXTENSION_RECEIVER_NAME = "\$receiver"
|
||||
val IMPLICIT_RECEIVER_NAME = "this"
|
||||
val ANOTHER_THIS_PARAMETER_NAME = "$this"
|
||||
|
||||
val THROW_CLASS_CAST_EXCEPTION_FUN_NAME = "throwCCE"
|
||||
|
||||
+45
-17
@@ -6,11 +6,14 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js.utils
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsName
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsScope
|
||||
import org.jetbrains.kotlin.js.naming.isES5IdentifierPart
|
||||
import org.jetbrains.kotlin.js.naming.isES5IdentifierStart
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
|
||||
|
||||
class SimpleNameGenerator : NameGenerator {
|
||||
|
||||
@@ -18,24 +21,34 @@ class SimpleNameGenerator : NameGenerator {
|
||||
|
||||
override fun getNameForSymbol(symbol: IrSymbol, scope: JsScope): JsName = getNameForDescriptor(symbol.descriptor, scope)
|
||||
|
||||
override fun getSpecialRefForName(name: Name): JsExpression {
|
||||
assert(name.isSpecial)
|
||||
|
||||
val nameString = name.asString()
|
||||
return when (nameString) {
|
||||
Namer.THIS_SPECIAL_NAME -> JsThisRef()
|
||||
else -> JsNameRef(getSpecialNameString(nameString))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSpecialNameString(specNameString: String): String = when (specNameString) {
|
||||
Namer.SET_SPECIAL_NAME -> Namer.SETTER_ARGUMENT
|
||||
else -> TODO("for Name ${specNameString}")
|
||||
}
|
||||
|
||||
private fun getNameForDescriptor(descriptor: DeclarationDescriptor, scope: JsScope): JsName = nameCache.getOrPut(descriptor, {
|
||||
val nameBuilder = StringBuilder()
|
||||
when (descriptor) {
|
||||
is ReceiverParameterDescriptor -> {
|
||||
when (descriptor.value) {
|
||||
is ExtensionReceiver -> nameBuilder.append(Namer.EXTENSION_RECEIVER_NAME)
|
||||
is ImplicitClassReceiver -> nameBuilder.append(Namer.IMPLICIT_RECEIVER_NAME)
|
||||
else -> TODO("name for $descriptor")
|
||||
}
|
||||
}
|
||||
is ValueParameterDescriptor -> {
|
||||
if (descriptor.name.isSpecial) {
|
||||
// TODO: consider this case more carefully
|
||||
nameBuilder.append(Namer.IMPLICIT_RECEIVER_NAME)
|
||||
nameBuilder.append('_')
|
||||
nameBuilder.append(descriptor.index)
|
||||
} else {
|
||||
val declaredName = descriptor.name.identifier
|
||||
nameBuilder.append(declaredName)
|
||||
if (declaredName.startsWith("\$")) {
|
||||
nameBuilder.append('_')
|
||||
nameBuilder.append(descriptor.index)
|
||||
}
|
||||
}
|
||||
}
|
||||
is PropertyDescriptor -> {
|
||||
nameBuilder.append(descriptor.name.identifier)
|
||||
}
|
||||
is PropertyAccessorDescriptor -> {
|
||||
when (descriptor) {
|
||||
is PropertyGetterDescriptor -> nameBuilder.append(Namer.GETTER_PREFIX)
|
||||
@@ -43,6 +56,21 @@ class SimpleNameGenerator : NameGenerator {
|
||||
}
|
||||
nameBuilder.append(descriptor.correspondingProperty.name.asString())
|
||||
}
|
||||
is ClassDescriptor -> {
|
||||
if (descriptor.name.isSpecial) {
|
||||
nameBuilder.append(descriptor.name.asString().let {
|
||||
it.substring(1, it.length - 1) + "${descriptor.hashCode()}"
|
||||
})
|
||||
} else {
|
||||
nameBuilder.append(descriptor.name.identifier)
|
||||
}
|
||||
}
|
||||
is ConstructorDescriptor -> {
|
||||
nameBuilder.append(getNameForDescriptor(descriptor.constructedClass, scope))
|
||||
}
|
||||
is LocalVariableDescriptor -> {
|
||||
nameBuilder.append(descriptor.name.identifier)
|
||||
}
|
||||
is CallableDescriptor -> {
|
||||
nameBuilder.append(descriptor.name.asString())
|
||||
descriptor.typeParameters.forEach { nameBuilder.append("_${it.name.asString()}") }
|
||||
|
||||
+1
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.KnownClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
+1
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.KnownClassDescriptor
|
||||
import org.jetbrains.kotlin.codegen.descriptors.FileClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.SharedVariablesManager
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.*
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
|
||||
+36
-8
@@ -2,14 +2,42 @@
|
||||
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
inline fun foo(x: String, block: (String) -> String) = block(x)
|
||||
|
||||
fun run(r: () -> Any) = r()
|
||||
|
||||
|
||||
fun test(i: Int, j: Int, k: Int): String {
|
||||
|
||||
|
||||
var i = 0
|
||||
var j = 2
|
||||
val k = 4
|
||||
|
||||
fun f(): String = "OK"
|
||||
|
||||
val funVal = {
|
||||
println(k)
|
||||
}
|
||||
run(funVal)
|
||||
|
||||
val funLit = { i += 1
|
||||
j += k
|
||||
f() }
|
||||
val ret = run(funLit) as String
|
||||
if (i != 1 || j != 6 || k != 4) return "fail"
|
||||
return ret
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
fun bar(y: String) = y + "cde"
|
||||
|
||||
val res = foo("abc") { bar(it) }
|
||||
|
||||
assertEquals("abccde", res)
|
||||
|
||||
return "OK"
|
||||
return test(1, 2, 3)
|
||||
}
|
||||
|
||||
//fun box(): String {
|
||||
//// fun bar(y: String) = y + "cde"
|
||||
//
|
||||
//// val res = foo("abc") { bar(it) }
|
||||
//
|
||||
//// assertEquals("abccde", res)
|
||||
//
|
||||
// return "OK"
|
||||
//}
|
||||
|
||||
@@ -2,13 +2,54 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1113
|
||||
package foo
|
||||
|
||||
fun test(): String {
|
||||
fun f(): String = "OK"
|
||||
|
||||
val funLit = { f() }
|
||||
return funLit()
|
||||
class closureBox<T>(var v: T)
|
||||
|
||||
|
||||
|
||||
//fun run(r: () -> Any) = r()
|
||||
|
||||
fun <T1, T2, T3> wrapper(t1:T1, t2:T2, i1:Int, block: (t1:T1, t2:T2, i1:Int) -> T3): T3 {
|
||||
val f = { tt1:T1, tt2:T2, ii:Int -> block(tt1, tt2, ii) }
|
||||
return f(t1, t2, i1)
|
||||
}
|
||||
|
||||
fun test(ii: Int, jj: Int, kk: Int): String {
|
||||
|
||||
var i = ii
|
||||
var j = jj
|
||||
val k = kk
|
||||
var ggg: Int
|
||||
|
||||
fun f(): String = "OK"
|
||||
|
||||
// fun f() {}
|
||||
val funVal = {
|
||||
k
|
||||
}
|
||||
|
||||
// run(funVal)
|
||||
|
||||
val funLit = { x:Int, l:Int, a:Int, b:Int, c:Int, d:Int, g:Int -> i += 1
|
||||
j += k
|
||||
ggg = 333 + x
|
||||
f() }
|
||||
val ret = funLit(50, 77, 1, 2, 3, 4, 5)
|
||||
// funLit(50, 77L)
|
||||
if (i != 1 || j != 6 || k != 4) return "fail"
|
||||
return ret
|
||||
// return "OK"
|
||||
}
|
||||
|
||||
//fun test(aa:Int, bb:Int, cc:Int) : Int {
|
||||
// val c = cc
|
||||
// var d = 0
|
||||
// val f = { a:Int,b:Int -> d = a*b+c}
|
||||
// f(aa, bb)
|
||||
// return d
|
||||
//}
|
||||
|
||||
fun box(): String {
|
||||
return test()
|
||||
// val i_box = closureBox<Int>(99)
|
||||
return test(1, 2, 3).toString()
|
||||
}
|
||||
Reference in New Issue
Block a user