Refactoring and fixes

This commit is contained in:
Roman Artemev
2018-04-18 22:48:27 +03:00
parent deab0a017b
commit 997328f584
10 changed files with 83 additions and 126 deletions
@@ -11,8 +11,6 @@ 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")
}
@@ -6,14 +6,17 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.backend.js.utils.kind
import org.jetbrains.kotlin.ir.backend.js.utils.name
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.types.typeUtil.isUnit
import org.jetbrains.kotlin.util.OperatorNameConventions
class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsExpression, JsGenerationContext> {
@@ -35,7 +38,7 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
override fun visitFunctionReference(expression: IrFunctionReference, context: JsGenerationContext): JsExpression {
val irFunction = expression.symbol.owner as IrFunction
return irFunction.accept(IrFunctionToJsTransformer(), context)
return irFunction.accept(IrFunctionToJsTransformer(), context).apply { name = null }
}
override fun <T> visitConst(expression: IrConst<T>, context: JsGenerationContext): JsExpression {
@@ -125,10 +128,6 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
return JsInvocation(jsDispatchReceiver!!, arguments)
}
context.staticContext.intrinsics[symbol]?.let {
return it(expression, arguments)
}
return if (symbol is IrConstructorSymbol) {
JsNew(context.getNameForSymbol(symbol).makeRef(), arguments)
} else {
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.js.backend.ast.JsStatement
class IrFileToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatement, JsGenerationContext> {
override fun visitFile(declaration: IrFile, context: JsGenerationContext): JsStatement {
val fileContext = context.newDeclaration(JsDeclarationScope(context.currentScope, "scope for file ${declaration.name}"))
val fileContext = context.newDeclaration(JsDeclarationScope(context.currentScope, "scope for file ${declaration.name}"), null, declaration)
val block = fileContext.currentBlock
declaration.declarations.forEach {
@@ -5,12 +5,14 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.descriptors.ClassDescriptor
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
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.js.backend.ast.*
typealias IrCallTransformer = (IrCall, context: JsGenerationContext) -> JsExpression
@@ -61,9 +63,10 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
binOp(intrinsics.jsInstanceOf, JsBinaryOperator.INSTANCEOF)
add(intrinsics.jsObjectCreate) { call, _ ->
add(intrinsics.jsObjectCreate) { call, context ->
val classToCreate = call.getTypeArgument(0)!!
val prototype = prototypeOf(classToCreate.constructor.declarationDescriptor!!.name.toJsName().makeRef())
val className = context.getNameForSymbol(IrClassSymbolImpl(classToCreate.constructor.declarationDescriptor as ClassDescriptor))
val prototype = prototypeOf(className.makeRef())
JsInvocation(Namer.JS_OBJECT_CREATE_FUNCTION, prototype)
}
@@ -10,14 +10,6 @@ import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.name.Name
// TODO don't use JsDynamicScope
val dummyScope = JsDynamicScope
fun Name.toJsName() =
// TODO sanitize
dummyScope.declareName(asString())
fun jsVar(name: JsName, initializer: IrExpression?, context: JsGenerationContext): JsVars {
val jsInitializer = initializer?.accept(IrElementToJsExpressionTransformer(), context)
@@ -5,18 +5,21 @@
package org.jetbrains.kotlin.ir.backend.js.utils
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.js.backend.ast.*
class JsGenerationContext {
fun newDeclaration(scope: JsScope, func: IrFunction? = null): JsGenerationContext {
return JsGenerationContext(this, JsBlock(), scope, func)
fun newDeclaration(scope: JsScope, func: IrFunction? = null, file: IrFile? = null): JsGenerationContext {
return JsGenerationContext(this, JsBlock(), scope, func, file)
}
val currentBlock: JsBlock
val currentScope: JsScope
val currentFile: IrFile?
val currentFunction: IrFunction?
val parent: JsGenerationContext?
val staticContext: JsStaticContext
@@ -30,16 +33,21 @@ class JsGenerationContext {
this.currentScope = rootScope
this.currentBlock = program.globalBlock
this.currentFunction = null
this.currentFile = null
}
constructor(parent: JsGenerationContext, block: JsBlock, scope: JsScope, func: IrFunction?) {
constructor(parent: JsGenerationContext, block: JsBlock, scope: JsScope, func: IrFunction?, file: IrFile? = null) {
this.parent = parent
this.program = parent.program
this.staticContext = parent.staticContext
this.currentBlock = block
this.currentScope = scope
this.currentFunction = func
this.currentFile = file ?: parent.currentFile
}
fun getNameForSymbol(symbol: IrSymbol): JsName = staticContext.getNameForSymbol(symbol)
fun getNameForSymbol(symbol: IrSymbol): JsName = staticContext.getNameForSymbol(symbol, this)
val currentPackage: PackageFragmentDescriptor
get() = currentFile!!.packageFragmentDescriptor
}
@@ -8,10 +8,8 @@ package org.jetbrains.kotlin.ir.backend.js.utils
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIntrinsicTransformers
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.js.backend.ast.JsExpression
import org.jetbrains.kotlin.js.backend.ast.JsGlobalBlock
import org.jetbrains.kotlin.js.backend.ast.JsRootScope
import org.jetbrains.kotlin.name.Name
class JsStaticContext(
@@ -22,5 +20,5 @@ class JsStaticContext(
) {
val intrinsics = JsIntrinsicTransformers(backendContext)
fun getNameForSymbol(irSymbol: IrSymbol) = nameGenerator.getNameForSymbol(irSymbol, rootScope)
fun getNameForSymbol(irSymbol: IrSymbol, context: JsGenerationContext) = nameGenerator.getNameForSymbol(irSymbol, context)
}
@@ -7,8 +7,7 @@ package org.jetbrains.kotlin.ir.backend.js.utils
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.js.backend.ast.JsName
import org.jetbrains.kotlin.js.backend.ast.JsScope
interface NameGenerator {
fun getNameForSymbol(symbol: IrSymbol, scope: JsScope): JsName
fun getNameForSymbol(symbol: IrSymbol, context: JsGenerationContext): JsName
}
@@ -9,9 +9,9 @@ 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.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.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
@@ -19,67 +19,68 @@ class SimpleNameGenerator : NameGenerator {
private val nameCache = mutableMapOf<DeclarationDescriptor, JsName>()
override fun getNameForSymbol(symbol: IrSymbol, scope: JsScope): JsName = getNameForDescriptor(symbol.descriptor, scope)
override fun getNameForSymbol(symbol: IrSymbol, context: JsGenerationContext): JsName = getNameForDescriptor(symbol.descriptor, context)
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)
private fun getNameForDescriptor(descriptor: DeclarationDescriptor, context: JsGenerationContext): 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 PropertyDescriptor -> {
nameBuilder.append(descriptor.name.identifier)
}
is PropertyAccessorDescriptor -> {
when (descriptor) {
is PropertyGetterDescriptor -> nameBuilder.append(Namer.GETTER_PREFIX)
is PropertySetterDescriptor -> nameBuilder.append(Namer.SETTER_PREFIX)
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)
}
}
}
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 {
is PropertyDescriptor -> {
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()}") }
descriptor.valueParameters.forEach { nameBuilder.append("_${it.type}") }
}
is PropertyAccessorDescriptor -> {
when (descriptor) {
is PropertyGetterDescriptor -> nameBuilder.append(Namer.GETTER_PREFIX)
is PropertySetterDescriptor -> nameBuilder.append(Namer.SETTER_PREFIX)
}
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.fqNameSafe.asString().replace('.', '$'))
}
}
is ConstructorDescriptor -> {
nameBuilder.append(getNameForDescriptor(descriptor.constructedClass, context))
}
is LocalVariableDescriptor -> {
nameBuilder.append(descriptor.name.identifier)
}
is CallableDescriptor -> {
nameBuilder.append(descriptor.name.asString())
descriptor.typeParameters.forEach { nameBuilder.append("_${it.name.asString()}") }
descriptor.valueParameters.forEach { nameBuilder.append("_${it.type}") }
}
}
context.currentScope.declareName(sanitizeName(nameBuilder.toString()))
}
scope.declareName(sanitizeName(nameBuilder.toString()))
})
private fun sanitizeName(name: String): String {
if (name.isEmpty()) return "_"
@@ -2,54 +2,13 @@
// EXPECTED_REACHABLE_NODES: 1113
package foo
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 test(): String {
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"
val funLit = { f() }
return funLit()
}
//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 {
// val i_box = closureBox<Int>(99)
return test(1, 2, 3).toString()
return test()
}