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 JsLoweredDeclarationOrigin : IrDeclarationOrigin {
object CLASS_STATIC_INITIALIZER : IrDeclarationOriginImpl("CLASS_STATIC_INITIALIZER") 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_INTRINSICS_STUB : IrDeclarationOriginImpl("JS_INTRINSICS_STUB")
object JS_CLOSURE_BOX_CLASS : IrStatementOriginImpl("JS_CLOSURE_BOX_CLASS") 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 package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype 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.JsGenerationContext
import org.jetbrains.kotlin.ir.backend.js.utils.Namer 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.backend.js.utils.name
import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsExpression, JsGenerationContext> { class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsExpression, JsGenerationContext> {
@@ -35,7 +38,7 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
override fun visitFunctionReference(expression: IrFunctionReference, context: JsGenerationContext): JsExpression { override fun visitFunctionReference(expression: IrFunctionReference, context: JsGenerationContext): JsExpression {
val irFunction = expression.symbol.owner as IrFunction 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 { override fun <T> visitConst(expression: IrConst<T>, context: JsGenerationContext): JsExpression {
@@ -125,10 +128,6 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
return JsInvocation(jsDispatchReceiver!!, arguments) return JsInvocation(jsDispatchReceiver!!, arguments)
} }
context.staticContext.intrinsics[symbol]?.let {
return it(expression, arguments)
}
return if (symbol is IrConstructorSymbol) { return if (symbol is IrConstructorSymbol) {
JsNew(context.getNameForSymbol(symbol).makeRef(), arguments) JsNew(context.getNameForSymbol(symbol).makeRef(), arguments)
} else { } else {
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.js.backend.ast.JsStatement
class IrFileToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatement, JsGenerationContext> { class IrFileToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatement, JsGenerationContext> {
override fun visitFile(declaration: IrFile, context: JsGenerationContext): JsStatement { 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 val block = fileContext.currentBlock
declaration.declarations.forEach { declaration.declarations.forEach {
@@ -5,12 +5,14 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs 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.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext 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.Namer
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.*
typealias IrCallTransformer = (IrCall, context: JsGenerationContext) -> JsExpression typealias IrCallTransformer = (IrCall, context: JsGenerationContext) -> JsExpression
@@ -61,9 +63,10 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
binOp(intrinsics.jsInstanceOf, JsBinaryOperator.INSTANCEOF) binOp(intrinsics.jsInstanceOf, JsBinaryOperator.INSTANCEOF)
add(intrinsics.jsObjectCreate) { call, _ -> add(intrinsics.jsObjectCreate) { call, context ->
val classToCreate = call.getTypeArgument(0)!! 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) 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.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.js.backend.ast.* 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 { fun jsVar(name: JsName, initializer: IrExpression?, context: JsGenerationContext): JsVars {
val jsInitializer = initializer?.accept(IrElementToJsExpressionTransformer(), context) val jsInitializer = initializer?.accept(IrElementToJsExpressionTransformer(), context)
@@ -5,18 +5,21 @@
package org.jetbrains.kotlin.ir.backend.js.utils 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.backend.js.JsIrBackendContext
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.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.*
class JsGenerationContext { class JsGenerationContext {
fun newDeclaration(scope: JsScope, func: IrFunction? = null): JsGenerationContext { fun newDeclaration(scope: JsScope, func: IrFunction? = null, file: IrFile? = null): JsGenerationContext {
return JsGenerationContext(this, JsBlock(), scope, func) return JsGenerationContext(this, JsBlock(), scope, func, file)
} }
val currentBlock: JsBlock val currentBlock: JsBlock
val currentScope: JsScope val currentScope: JsScope
val currentFile: IrFile?
val currentFunction: IrFunction? val currentFunction: IrFunction?
val parent: JsGenerationContext? val parent: JsGenerationContext?
val staticContext: JsStaticContext val staticContext: JsStaticContext
@@ -30,16 +33,21 @@ class JsGenerationContext {
this.currentScope = rootScope this.currentScope = rootScope
this.currentBlock = program.globalBlock this.currentBlock = program.globalBlock
this.currentFunction = null 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.parent = parent
this.program = parent.program this.program = parent.program
this.staticContext = parent.staticContext this.staticContext = parent.staticContext
this.currentBlock = block this.currentBlock = block
this.currentScope = scope this.currentScope = scope
this.currentFunction = func 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.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIntrinsicTransformers import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIntrinsicTransformers
import org.jetbrains.kotlin.ir.symbols.IrSymbol 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.JsGlobalBlock
import org.jetbrains.kotlin.js.backend.ast.JsRootScope import org.jetbrains.kotlin.js.backend.ast.JsRootScope
import org.jetbrains.kotlin.name.Name
class JsStaticContext( class JsStaticContext(
@@ -22,5 +20,5 @@ class JsStaticContext(
) { ) {
val intrinsics = JsIntrinsicTransformers(backendContext) 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.ir.symbols.IrSymbol
import org.jetbrains.kotlin.js.backend.ast.JsName import org.jetbrains.kotlin.js.backend.ast.JsName
import org.jetbrains.kotlin.js.backend.ast.JsScope
interface NameGenerator { 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.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.js.backend.ast.JsName 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.isES5IdentifierPart
import org.jetbrains.kotlin.js.naming.isES5IdentifierStart 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.ExtensionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
@@ -19,67 +19,68 @@ class SimpleNameGenerator : NameGenerator {
private val nameCache = mutableMapOf<DeclarationDescriptor, JsName>() 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, { private fun getNameForDescriptor(descriptor: DeclarationDescriptor, context: JsGenerationContext): JsName =
val nameBuilder = StringBuilder() nameCache.getOrPut(descriptor) {
when (descriptor) { val nameBuilder = StringBuilder()
is ReceiverParameterDescriptor -> { when (descriptor) {
when (descriptor.value) { is ReceiverParameterDescriptor -> {
is ExtensionReceiver -> nameBuilder.append(Namer.EXTENSION_RECEIVER_NAME) when (descriptor.value) {
is ImplicitClassReceiver -> nameBuilder.append(Namer.IMPLICIT_RECEIVER_NAME) is ExtensionReceiver -> nameBuilder.append(Namer.EXTENSION_RECEIVER_NAME)
else -> TODO("name for $descriptor") 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 ValueParameterDescriptor -> {
is PropertyDescriptor -> { if (descriptor.name.isSpecial) {
nameBuilder.append(descriptor.name.identifier) // TODO: consider this case more carefully
} nameBuilder.append(Namer.IMPLICIT_RECEIVER_NAME)
is PropertyAccessorDescriptor -> { nameBuilder.append('_')
when (descriptor) { nameBuilder.append(descriptor.index)
is PropertyGetterDescriptor -> nameBuilder.append(Namer.GETTER_PREFIX) } else {
is PropertySetterDescriptor -> nameBuilder.append(Namer.SETTER_PREFIX) val declaredName = descriptor.name.identifier
nameBuilder.append(declaredName)
if (declaredName.startsWith("\$")) {
nameBuilder.append('_')
nameBuilder.append(descriptor.index)
}
}
} }
nameBuilder.append(descriptor.correspondingProperty.name.asString()) is PropertyDescriptor -> {
}
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) nameBuilder.append(descriptor.name.identifier)
} }
} is PropertyAccessorDescriptor -> {
is ConstructorDescriptor -> { when (descriptor) {
nameBuilder.append(getNameForDescriptor(descriptor.constructedClass, scope)) is PropertyGetterDescriptor -> nameBuilder.append(Namer.GETTER_PREFIX)
} is PropertySetterDescriptor -> nameBuilder.append(Namer.SETTER_PREFIX)
is LocalVariableDescriptor -> { }
nameBuilder.append(descriptor.name.identifier) nameBuilder.append(descriptor.correspondingProperty.name.asString())
} }
is CallableDescriptor -> { is ClassDescriptor -> {
nameBuilder.append(descriptor.name.asString()) if (descriptor.name.isSpecial) {
descriptor.typeParameters.forEach { nameBuilder.append("_${it.name.asString()}") } nameBuilder.append(descriptor.name.asString().let {
descriptor.valueParameters.forEach { nameBuilder.append("_${it.type}") } 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 { private fun sanitizeName(name: String): String {
if (name.isEmpty()) return "_" if (name.isEmpty()) return "_"
@@ -2,54 +2,13 @@
// EXPECTED_REACHABLE_NODES: 1113 // EXPECTED_REACHABLE_NODES: 1113
package foo package foo
fun test(): String {
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(): String = "OK"
// fun f() {} val funLit = { f() }
val funVal = { return funLit()
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 { fun box(): String {
// val i_box = closureBox<Int>(99) return test()
return test(1, 2, 3).toString()
} }