Compare commits

...

17 Commits

Author SHA1 Message Date
Anton Bannykh
919ab40569 wip (handle unbounds) 2018-04-13 19:21:52 +03:00
Anton Bannykh
68ad009abb wip (kinds works?) 2018-04-13 15:28:25 +03:00
Anton Bannykh
ee44521a22 wip (compiles) 2018-04-13 15:27:48 +03:00
Zalim Bashorov
2beb51eced ~~~ IntrinsicifyBuiltinOperationsLowering.kt -- more TODOs 2018-04-13 13:28:13 +03:00
Zalim Bashorov
715618110b ~~~ IntrinsicifyBuiltinOperationsLowering.kt -- use IrElementTransformerVoid instead of IrElementTransformer 2018-04-13 13:27:50 +03:00
Zalim Bashorov
0e458e4457 [JS IR BE] add new items to whitelist and regenerate tests 2018-04-12 20:35:29 +03:00
Zalim Bashorov
6d0222dfc3 ~~~ IntrinsicifyBuiltinOperationsLowering.kt -- add comments 2018-04-12 20:35:29 +03:00
Zalim Bashorov
ab556449ae ~~~ IntrinsicifyBuiltinOperationsLowering.kt 2018-04-12 20:35:29 +03:00
Zalim Bashorov
122effcfbd ~~~ JsIntrinsics.kt -- add comments 2018-04-12 20:35:28 +03:00
Zalim Bashorov
6b6e244424 [JS IR BE] don't materialize Unit for toplevel expressions 2018-04-12 20:35:28 +03:00
Zalim Bashorov
5e333e3a3b [JS IR BE] basic support for the case when IrBlock is used as expression
In this case compiler generates comma separated expressions.
2018-04-12 20:35:27 +03:00
Zalim Bashorov
543c0cfbe0 [JS IR BE] use most of new intrinsics in IR -> IR 2018-04-12 20:35:27 +03:00
Zalim Bashorov
a8a1e95421 [JS IR BE] support new intrinsics in IR -> JS 2018-04-12 20:35:27 +03:00
Zalim Bashorov
2b8bfa0ae2 [JS IR BE] declare more intrinsics
* jsGt
* jsGtEq
* jsLt
* jsLtEq
* jsUnaryPlus
* jsUnaryMinus
* jsPrefixInc
* jsPostfixInc
* jsPrefixDec
* jsPostfixDec
* jsAnd
* jsOr
* jsBitAnd
* jsBitOr
* jsBitXor
* jsBitNot
* jsBitShiftR
* jsBitShiftRU
* jsBitShiftL
* jsInstanceOf
2018-04-12 20:35:26 +03:00
Zalim Bashorov
45850e3a89 [JS IR BE] move intrinsic for Object.create calls to JsIntrinsics 2018-04-12 20:35:26 +03:00
Zalim Bashorov
e90b4822c9 [JS IR BE] add basic support for some binary and equality operations; add some intrinsic infrastructure 2018-04-12 20:35:26 +03:00
Zalim Bashorov
479150150f [JS IR BE] use IrMemberAccessExpression.valueArgumentsCount instead of descriptor based IrFunctionSymbol.parameterCount and remove last one 2018-04-12 20:35:25 +03:00
25 changed files with 3322 additions and 1177 deletions

View File

@@ -4,6 +4,7 @@
<w>ctor</w>
<w>inlining</w>
<w>interner</w>
<w>intrinsicify</w>
<w>kclass</w>
<w>lookups</w>
<w>minification</w>

View File

@@ -0,0 +1,410 @@
/*
* 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
import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.backend.js.lower.addChildren
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.visitors.*
@Deprecated("")
internal fun IrModuleFragment.replaceUnboundSymbols(context: JsIrBackendContext) {
val collector = DeclarationSymbolCollector()
with(collector) {
with(irBuiltins) {
for (op in arrayOf(eqeqeqFun, eqeqFun, throwNpeFun, booleanNotFun, noWhenBranchMatchedExceptionFun) +
lessFunByOperandType.values +
lessOrEqualFunByOperandType.values +
greaterOrEqualFunByOperandType.values +
greaterFunByOperandType.values +
ieee754equalsFunByOperandType.values) {
register(op.symbol)
}
}
}
this.acceptVoid(collector)
val symbolTable = context.symbolTable
this.transformChildrenVoid(IrUnboundSymbolReplacer(symbolTable, collector.descriptorToSymbol))
// Generate missing external stubs:
// TODO: ModuleGenerator::generateUnboundSymbolsAsDependencies(IRModuleFragment) is private function :/
@Suppress("DEPRECATION")
ExternalDependenciesGenerator(symbolTable = context.symbolTable, irBuiltIns = context.irBuiltIns).generateUnboundSymbolsAsDependencies(this)
// Merge duplicated module and package declarations:
this.acceptVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {}
override fun visitModuleFragment(declaration: IrModuleFragment) {
declaration.dependencyModules.forEach { it.acceptVoid(this) }
val dependencyModules = declaration.dependencyModules.groupBy { it.descriptor }.map { (_, fragments) ->
fragments.reduce { firstModule, nextModule ->
firstModule.apply {
mergeFrom(nextModule)
}
}
}
declaration.dependencyModules.clear()
declaration.dependencyModules.addAll(dependencyModules)
}
})
}
private fun IrModuleFragment.mergeFrom(other: IrModuleFragment): Unit {
assert(this.files.isEmpty())
assert(other.files.isEmpty())
val thisPackages = this.externalPackageFragments.groupBy { it.packageFragmentDescriptor }
other.externalPackageFragments.forEach {
val thisPackage = thisPackages[it.packageFragmentDescriptor]?.single()
if (thisPackage == null) {
this.externalPackageFragments.add(it)
} else {
thisPackage.addChildren(it.declarations)
}
}
}
private class DeclarationSymbolCollector : IrElementVisitorVoid {
val descriptorToSymbol = mutableMapOf<DeclarationDescriptor, IrSymbol>()
fun register(symbol: IrSymbol) {
descriptorToSymbol[symbol.descriptor] = symbol
}
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
if (element is IrSymbolOwner && element !is IrAnonymousInitializer) {
register(element.symbol)
}
}
}
private class IrUnboundSymbolReplacer(
val symbolTable: SymbolTable,
val descriptorToSymbol: Map<DeclarationDescriptor, IrSymbol>
) : IrElementTransformerVoid() {
private val localDescriptorToSymbol = mutableMapOf<DeclarationDescriptor, MutableList<IrSymbol>>()
private inline fun <R> withLocal(symbol: IrSymbol?, block: () -> R): R {
if (symbol == null) return block()
val locals = localDescriptorToSymbol.getOrPut(symbol.descriptor) { mutableListOf() }
locals.add(symbol)
return try {
block()
} finally {
locals.removeAt(locals.lastIndex)
}
}
private inline fun <reified D : DeclarationDescriptor, reified S : IrSymbol> S.replace(
referenceSymbol: (SymbolTable, D) -> S): S? {
if (this.isBound) {
return null
}
localDescriptorToSymbol[this.descriptor]?.lastOrNull()?.let {
return it as S
}
descriptorToSymbol[this.descriptor]?.let {
return it as S
}
return referenceSymbol(symbolTable, this.descriptor as D)
}
private inline fun <reified D : DeclarationDescriptor, reified S : IrSymbol> S.replaceOrSame(
referenceSymbol: (SymbolTable, D) -> S): S = this.replace(referenceSymbol) ?: this
private inline fun <reified S : IrSymbol> S.replaceLocal(): S? {
return if (this.isBound) {
null
} else {
(localDescriptorToSymbol[this.descriptor]?.lastOrNull() ?: descriptorToSymbol[this.descriptor]) as S
}
}
override fun visitGetValue(expression: IrGetValue): IrExpression {
val symbol = expression.symbol.replaceLocal() ?: return super.visitGetValue(expression)
expression.transformChildrenVoid(this)
return with(expression) {
IrGetValueImpl(startOffset, endOffset, symbol, origin)
}
}
override fun visitSetVariable(expression: IrSetVariable): IrExpression {
val symbol = expression.symbol.replaceLocal() ?: return super.visitSetVariable(expression)
expression.transformChildrenVoid(this)
return with(expression) {
IrSetVariableImpl(startOffset, endOffset, symbol, value, origin)
}
}
override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression {
val symbol = expression.symbol.replace(SymbolTable::referenceClass) ?:
return super.visitGetObjectValue(expression)
expression.transformChildrenVoid(this)
return with(expression) {
IrGetObjectValueImpl(startOffset, endOffset, type, symbol)
}
}
override fun visitGetEnumValue(expression: IrGetEnumValue): IrExpression {
val symbol = expression.symbol.replace(SymbolTable::referenceEnumEntry) ?:
return super.visitGetEnumValue(expression)
expression.transformChildrenVoid(this)
return with(expression) {
IrGetEnumValueImpl(startOffset, endOffset, type, symbol)
}
}
override fun visitClassReference(expression: IrClassReference): IrExpression {
val symbol = expression.symbol.replace(SymbolTable::referenceClassifier)
?: return super.visitClassReference(expression)
expression.transformChildrenVoid(this)
return with(expression) {
IrClassReferenceImpl(startOffset, endOffset, type, symbol, symbol.descriptor.defaultType)
}
}
override fun visitClass(declaration: IrClass): IrStatement {
declaration.superClasses.forEachIndexed { index, symbol ->
val newSymbol = symbol.replace(SymbolTable::referenceClass)
if (newSymbol != null) {
declaration.superClasses[index] = newSymbol
}
}
withLocal(declaration.thisReceiver?.symbol) {
return super.visitClass(declaration)
}
}
override fun visitGetField(expression: IrGetField): IrExpression {
val symbol = expression.symbol.replaceOrSame(SymbolTable::referenceField)
val superQualifierSymbol = expression.superQualifierSymbol?.replaceOrSame(SymbolTable::referenceClass)
if (symbol == expression.symbol && superQualifierSymbol == expression.superQualifierSymbol) {
return super.visitGetField(expression)
}
expression.transformChildrenVoid(this)
return with(expression) {
IrGetFieldImpl(startOffset, endOffset, symbol, receiver, origin, superQualifierSymbol)
}
}
override fun visitSetField(expression: IrSetField): IrExpression {
val symbol = expression.symbol.replaceOrSame(SymbolTable::referenceField)
val superQualifierSymbol = expression.superQualifierSymbol?.replaceOrSame(SymbolTable::referenceClass)
if (symbol == expression.symbol && superQualifierSymbol == expression.superQualifierSymbol) {
return super.visitSetField(expression)
}
expression.transformChildrenVoid(this)
return with(expression) {
IrSetFieldImpl(startOffset, endOffset, symbol, receiver, value, origin, superQualifierSymbol)
}
}
override fun visitCall(expression: IrCall): IrExpression {
val symbol = expression.symbol.replace(SymbolTable::referenceFunction) ?: expression.symbol
val superQualifierSymbol = expression.superQualifierSymbol?.replaceOrSame(SymbolTable::referenceClass)
if (symbol == expression.symbol && superQualifierSymbol == expression.superQualifierSymbol) {
return super.visitCall(expression)
}
expression.transformChildrenVoid()
return with(expression) {
IrCallImpl(startOffset, endOffset, symbol, descriptor,
getTypeArgumentsMap(),
origin, superQualifierSymbol).also {
it.copyArgumentsFrom(this)
}
}
}
private fun IrMemberAccessExpression.getTypeArgumentsMap() =
descriptor.original.typeParameters.associate { it to getTypeArgumentOrDefault(it) }
private fun IrMemberAccessExpressionBase.copyArgumentsFrom(original: IrMemberAccessExpression) {
dispatchReceiver = original.dispatchReceiver
extensionReceiver = original.extensionReceiver
original.descriptor.valueParameters.forEachIndexed { index, _ ->
putValueArgument(index, original.getValueArgument(index))
}
}
override fun visitEnumConstructorCall(expression: IrEnumConstructorCall): IrExpression {
val symbol = expression.symbol.replace(SymbolTable::referenceConstructor) ?:
return super.visitEnumConstructorCall(expression)
return with(expression) {
IrEnumConstructorCallImpl(startOffset, endOffset, symbol, null).also {
it.copyArgumentsFrom(this)
}
}
}
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
val symbol = expression.symbol.replace(SymbolTable::referenceConstructor) ?:
return super.visitDelegatingConstructorCall(expression)
expression.transformChildrenVoid()
return with(expression) {
IrDelegatingConstructorCallImpl(startOffset, endOffset, symbol, descriptor, getTypeArgumentsMap()).also {
it.copyArgumentsFrom(this)
}
}
}
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
val symbol = expression.symbol.replace(SymbolTable::referenceFunction) ?:
return super.visitFunctionReference(expression)
expression.transformChildrenVoid(this)
return with(expression) {
IrFunctionReferenceImpl(startOffset, endOffset, type, symbol, descriptor, getTypeArgumentsMap()).also {
it.copyArgumentsFrom(this)
}
}
}
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
val field = expression.field?.replaceOrSame(SymbolTable::referenceField)
val getter = expression.getter?.replace(SymbolTable::referenceFunction) ?: expression.getter
val setter = expression.setter?.replace(SymbolTable::referenceFunction) ?: expression.setter
if (field == expression.field && getter == expression.getter && setter == expression.setter) {
return super.visitPropertyReference(expression)
}
expression.transformChildrenVoid(this)
return with(expression) {
IrPropertyReferenceImpl(startOffset, endOffset, type, descriptor,
field,
getter,
setter,
getTypeArgumentsMap(), origin).also {
it.copyArgumentsFrom(this)
}
}
}
override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference): IrExpression {
val delegate = expression.delegate.replaceOrSame(SymbolTable::referenceVariable)
val getter = expression.getter.replace(SymbolTable::referenceFunction) ?: expression.getter
val setter = expression.setter?.replace(SymbolTable::referenceFunction) ?: expression.setter
if (delegate == expression.delegate && getter == expression.getter && setter == expression.setter) {
return super.visitLocalDelegatedPropertyReference(expression)
}
expression.transformChildrenVoid(this)
return with(expression) {
IrLocalDelegatedPropertyReferenceImpl(startOffset, endOffset, type, descriptor,
delegate, getter, setter, origin).also {
it.copyArgumentsFrom(this)
}
}
}
private val returnTargetStack = mutableListOf<IrFunctionSymbol>()
override fun visitFunction(declaration: IrFunction): IrStatement {
returnTargetStack.push(declaration.symbol)
try {
if (declaration is IrSimpleFunction) {
declaration.overriddenSymbols.forEachIndexed { index, symbol ->
val newSymbol = symbol.replace(SymbolTable::referenceSimpleFunction)
if (newSymbol != null) {
declaration.overriddenSymbols[index] = newSymbol
}
}
}
withLocal(declaration.dispatchReceiverParameter?.symbol) {
withLocal(declaration.extensionReceiverParameter?.symbol) {
return super.visitFunction(declaration)
}
}
} finally {
returnTargetStack.pop()
}
}
override fun visitBlock(expression: IrBlock): IrExpression {
if (expression is IrReturnableBlock) {
returnTargetStack.push(expression.symbol)
try {
return super.visitBlock(expression)
} finally {
returnTargetStack.pop()
}
} else {
return super.visitBlock(expression)
}
}
override fun visitReturn(expression: IrReturn): IrExpression {
if (expression.returnTargetSymbol.isBound) {
return super.visitReturn(expression)
}
val returnTargetSymbol = returnTargetStack.last { it.descriptor == expression.returnTarget }
expression.transformChildrenVoid(this)
return with(expression) {
IrReturnImpl(startOffset, endOffset, type, returnTargetSymbol, value)
}
}
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression {
val classSymbol = expression.classSymbol.replace(SymbolTable::referenceClass) ?:
return super.visitInstanceInitializerCall(expression)
expression.transformChildrenVoid(this)
return with(expression) {
IrInstanceInitializerCallImpl(startOffset, endOffset, classSymbol)
}
}
}

View File

@@ -0,0 +1,123 @@
/*
* 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
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.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.js.resolve.JsPlatform.builtIns
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.KotlinTypeFactory
import org.jetbrains.kotlin.types.Variance
class JsIntrinsics(private val module: ModuleDescriptor, private val irBuiltIns: IrBuiltIns, symbolTable: SymbolTable) {
private val stubBuilder = DeclarationStubGenerator(symbolTable, JsLoweredDeclarationOrigin.JS_INTRINSICS_STUB)
// Equality operations:
val jsEqeq = binOpBool("jsEqeq")
val jsNotEq = binOpBool("jsNotEq")
val jsEqeqeq = binOpBool("jsEqeqeq")
val jsNotEqeq = binOpBool("jsNotEqeq")
val jsGt = binOpBool("jsGt")
val jsGtEq = binOpBool("jsGtEq")
val jsLt = binOpBool("jsLt")
val jsLtEq = binOpBool("jsLtEq")
// Unary operations:
val jsNot = unOpBool("jsNot")
val jsUnaryPlus = unOp("jsUnaryPlus")
val jsUnaryMinus = unOp("jsUnaryMinus")
val jsPrefixInc = unOp("jsPrefixInc")
val jsPostfixInc = unOp("jsPostfixInc")
val jsPrefixDec = unOp("jsPrefixDec")
val jsPostfixDec = unOp("jsPostfixDec")
// Binary operations:
val jsPlus = binOp("jsPlus")
val jsMinus = binOp("jsMinus")
val jsMult = binOp("jsMult")
val jsDiv = binOp("jsDiv")
val jsMod = binOp("jsMod")
val jsAnd = binOp("jsAnd")
val jsOr = binOp("jsOr")
// Bit operations:
val jsBitAnd = binOpInt("jsBitAnd")
val jsBitOr = binOpInt("jsBitOr")
val jsBitXor = binOpInt("jsBitXor")
val jsBitNot = unOpInt("jsBitNot")
val jsBitShiftR = binOpInt("jsBitShiftR")
val jsBitShiftRU = binOpInt("jsBitShiftRU")
val jsBitShiftL = binOpInt("jsBitShiftL")
// Other:
val jsInstanceOf = binOpBool("jsInstanceOf")
val jsObjectCreate: IrSimpleFunction = defineObjectCreateIntrinsic()
// Helpers:
// TODO: unify how we create intrinsic symbols -- avoid using `defineOperator`
private fun defineObjectCreateIntrinsic(): IrSimpleFunction {
val typeParam = TypeParameterDescriptorImpl.createWithDefaultBound(
builtIns.any,
Annotations.EMPTY,
true,
Variance.INVARIANT,
Name.identifier("T"),
0
)
val returnType = KotlinTypeFactory.simpleType(Annotations.EMPTY, typeParam.typeConstructor, emptyList(), false)
val desc = SimpleFunctionDescriptorImpl.create(
module,
Annotations.EMPTY,
Name.identifier("Object\$create"),
CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE
).apply {
initialize(null, null, listOf(typeParam), emptyList(), returnType, Modality.FINAL, Visibilities.PUBLIC)
isInline = true
}
return stubBuilder.generateFunctionStub(desc)
}
private fun unOp(name: String, returnType: KotlinType = irBuiltIns.anyN) =
irBuiltIns.run { defineOperator(name, returnType, listOf(anyN)) }
private fun unOpBool(name: String) = unOp(name, irBuiltIns.bool)
private fun unOpInt(name: String) = unOp(name, irBuiltIns.int)
private fun binOp(name: String, returnType: KotlinType = irBuiltIns.anyN) =
irBuiltIns.run { defineOperator(name, returnType, listOf(anyN, anyN)) }
private fun binOpBool(name: String) = binOp(name, irBuiltIns.bool)
private fun binOpInt(name: String) = binOp(name, irBuiltIns.int)
}

View File

@@ -9,31 +9,32 @@ import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.ReflectionTypes
import org.jetbrains.kotlin.backend.common.ir.Ir
import org.jetbrains.kotlin.backend.common.ir.Symbols
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.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
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.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,
override val irBuiltIns: IrBuiltIns,
irModuleFragment: IrModuleFragment,
symbolTable: SymbolTable
val symbolTable: SymbolTable
) : CommonBackendContext {
val intrinsics = JsIntrinsics(module, irBuiltIns, symbolTable)
override val builtIns = module.builtIns
override val sharedVariablesManager = JsSharedVariablesManager(builtIns)
@@ -42,6 +43,8 @@ class JsIrBackendContext(
ReflectionTypes(module, FqName("kotlin.reflect"))
}
val originalModuleIndex = ModuleIndex(irModuleFragment)
override val ir: Ir<CommonBackendContext> = object : Ir<CommonBackendContext>(this, irModuleFragment) {
override val symbols: Symbols<CommonBackendContext> = object : Symbols<CommonBackendContext>(this@JsIrBackendContext, symbolTable) {
@@ -91,37 +94,6 @@ class JsIrBackendContext(
val secondaryConstructorsMap = mutableMapOf<IrConstructorSymbol, SecondaryCtorPair>()
private val stubBuilder = DeclarationStubGenerator(symbolTable, JsLoweredDeclarationOrigin.JS_INTRINSICS_STUB)
val objectCreate: IrSimpleFunction = defineObjectCreateIntrinsic()
private fun defineObjectCreateIntrinsic(): IrSimpleFunction {
val typeParam = TypeParameterDescriptorImpl.createWithDefaultBound(
builtIns.any,
Annotations.EMPTY,
true,
Variance.INVARIANT,
Name.identifier("T"),
0
)
val returnType = KotlinTypeFactory.simpleType(Annotations.EMPTY, typeParam.typeConstructor, emptyList(), false)
val desc = SimpleFunctionDescriptorImpl.create(
module,
Annotations.EMPTY,
Name.identifier("Object\$create"),
CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE
).apply {
initialize(null, null, listOf(typeParam), emptyList(), returnType, Modality.FINAL, Visibilities.PUBLIC)
isInline = true
}
return stubBuilder.generateFunctionStub(desc)
}
private fun find(memberScope: MemberScope, className: String): ClassDescriptor {
return find(memberScope, Name.identifier(className))
}

View File

@@ -0,0 +1,72 @@
/*
* 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
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
class ModuleIndex(val module: IrModuleFragment) {
var currentFile: IrFile? = null
/**
* Contains all classes declared in [module]
*/
val classes: Map<ClassDescriptor, IrClass>
val enumEntries: Map<ClassDescriptor, IrEnumEntry>
/**
* Contains all functions declared in [module]
*/
val functions = mutableMapOf<FunctionDescriptor, IrFunction>()
val declarationToFile = mutableMapOf<DeclarationDescriptor, String>()
init {
val map = mutableMapOf<ClassDescriptor, IrClass>()
enumEntries = mutableMapOf()
module.acceptVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitFile(declaration: IrFile) {
currentFile = declaration
super.visitFile(declaration)
}
override fun visitClass(declaration: IrClass) {
super.visitClass(declaration)
map[declaration.descriptor] = declaration
}
override fun visitEnumEntry(declaration: IrEnumEntry) {
super.visitEnumEntry(declaration)
enumEntries[declaration.descriptor] = declaration
}
override fun visitFunction(declaration: IrFunction) {
super.visitFunction(declaration)
functions[declaration.descriptor] = declaration
}
override fun visitDeclaration(declaration: IrDeclaration) {
super.visitDeclaration(declaration)
declarationToFile[declaration.descriptor] = currentFile!!.name
}
})
classes = map
}
}

View File

@@ -0,0 +1,265 @@
/*
* 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
import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.getTypeArgumentOrDefault
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
val IrConstructor.constructedClass get() = this.parent as IrClass
val <T : IrDeclaration> T.original get() = this
val IrDeclaration.containingDeclaration get() = this.parent
val IrDeclarationParent.fqNameSafe: FqName
get() = when (this) {
is IrPackageFragment -> this.fqName
is IrDeclaration -> this.parent.fqNameSafe.child(this.name)
else -> error(this)
}
val IrDeclaration.name: Name
get() = when (this) {
is IrSimpleFunction -> this.name
is IrClass -> this.name
is IrEnumEntry -> this.name
is IrProperty -> this.name
is IrLocalDelegatedProperty -> this.name
is IrField -> this.name
is IrVariable -> this.name
is IrConstructor -> SPECIAL_INIT_NAME
is IrValueParameter -> this.name
else -> error(this)
}
private val SPECIAL_INIT_NAME = Name.special("<init>")
val IrField.fqNameSafe: FqName get() = this.parent.fqNameSafe.child(this.name)
/**
* @return naturally-ordered list of all parameters available inside the function body.
*/
val IrFunction.allParameters: List<IrValueParameter>
get() = if (this is IrConstructor) {
listOf(this.constructedClass.thisReceiver
?: error(this.descriptor)
) + explicitParameters
} else {
explicitParameters
}
/**
* @return naturally-ordered list of the parameters that can have values specified at call site.
*/
val IrFunction.explicitParameters: List<IrValueParameter>
get() {
val result = ArrayList<IrValueParameter>(valueParameters.size + 2)
this.dispatchReceiverParameter?.let {
result.add(it)
}
this.extensionReceiverParameter?.let {
result.add(it)
}
result.addAll(valueParameters)
return result
}
val IrValueParameter.isVararg get() = this.varargElementType != null
val IrFunction.isSuspend get() = this is IrSimpleFunction && this.isSuspend
fun IrClass.isUnit() = this.fqNameSafe == KotlinBuiltIns.FQ_NAMES.unit.toSafe()
//fun IrClass.getSuperClassNotAny() = this.superClasses.map { it.owner }.atMostOne { !it.isInterface && !it.isAny() }
fun IrClass.isAny() = this.fqNameSafe == KotlinBuiltIns.FQ_NAMES.any.toSafe()
fun IrClass.isNothing() = this.fqNameSafe == KotlinBuiltIns.FQ_NAMES.nothing.toSafe()
//fun IrClass.getSuperInterfaces() = this.superClasses.map { it.owner }.filter { it.isInterface }
//val IrProperty.konanBackingField: IrField?
// get() {
// this.backingField?.let { return it }
//
// (this.descriptor as? DeserializedPropertyDescriptor)?.backingField?.let { backingFieldDescriptor ->
// val result = IrFieldImpl(
// this.startOffset,
// this.endOffset,
// IrDeclarationOrigin.PROPERTY_BACKING_FIELD,
// backingFieldDescriptor
// ).also {
// it.parent = this.parent
// }
// this.backingField = result
// return result
// }
//
// return null
// }
val IrClass.defaultType: KotlinType
get() = this.thisReceiver!!.type
val IrField.containingClass get() = this.parent as? IrClass
val IrFunction.isReal get() = this.origin != IrDeclarationOrigin.FAKE_OVERRIDE
val IrSimpleFunction.isOverridable: Boolean
get() = visibility != Visibilities.PRIVATE
&& modality != Modality.FINAL
&& (parent as? IrClass)?.isFinalClass != true
val IrFunction.isOverridable get() = this is IrSimpleFunction && this.isOverridable
val IrFunction.isOverridableOrOverrides
get() = this is IrSimpleFunction && (this.isOverridable || this.overriddenSymbols.isNotEmpty())
val IrClass.isFinalClass: Boolean
get() = modality == Modality.FINAL && kind != ClassKind.ENUM_CLASS
fun IrSimpleFunction.overrides(other: IrSimpleFunction): Boolean {
if (this == other) return true
this.overriddenSymbols.forEach {
if (it.owner.overrides(other)) {
return true
}
}
return false
}
fun IrClass.isSpecialClassWithNoSupertypes() = this.isAny() || this.isNothing()
val IrClass.constructors get() = this.declarations.filterIsInstance<IrConstructor>()
internal val IrValueParameter.isValueParameter get() = this.index >= 0
fun IrModuleFragment.referenceAllTypeExternalClassifiers(symbolTable: SymbolTable) {
val moduleDescriptor = this.descriptor
fun KotlinType.referenceAllClassifiers() {
TypeUtils.getClassDescriptor(this)?.let {
if (!ErrorUtils.isError(it) && it.module != moduleDescriptor) {
if (it.kind == ClassKind.ENUM_ENTRY) {
symbolTable.referenceEnumEntry(it)
} else {
symbolTable.referenceClass(it)
}
}
}
this.constructor.supertypes.forEach {
it.referenceAllClassifiers()
}
}
val visitor = object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitValueParameter(declaration: IrValueParameter) {
super.visitValueParameter(declaration)
declaration.type.referenceAllClassifiers()
}
override fun visitVariable(declaration: IrVariable) {
super.visitVariable(declaration)
declaration.type.referenceAllClassifiers()
}
override fun visitExpression(expression: IrExpression) {
super.visitExpression(expression)
expression.type.referenceAllClassifiers()
}
override fun visitDeclaration(declaration: IrDeclaration) {
super.visitDeclaration(declaration)
declaration.descriptor.annotations.getAllAnnotations().forEach {
handleClassReferences(it.annotation)
}
}
private fun handleClassReferences(annotation: AnnotationDescriptor) {
annotation.allValueArguments.values.forEach {
it.accept(object : AnnotationArgumentVisitor<Unit, Nothing?> {
override fun visitKClassValue(p0: KClassValue?, p1: Nothing?) {
p0?.value?.referenceAllClassifiers()
}
override fun visitArrayValue(p0: ArrayValue?, p1: Nothing?) {
p0?.value?.forEach { it.accept(this, null) }
}
override fun visitAnnotationValue(p0: AnnotationValue?, p1: Nothing?) {
p0?.let { handleClassReferences(p0.value) }
}
override fun visitBooleanValue(p0: BooleanValue?, p1: Nothing?) {}
override fun visitShortValue(p0: ShortValue?, p1: Nothing?) {}
override fun visitByteValue(p0: ByteValue?, p1: Nothing?) {}
override fun visitNullValue(p0: NullValue?, p1: Nothing?) {}
override fun visitDoubleValue(p0: DoubleValue?, p1: Nothing?) {}
override fun visitLongValue(p0: LongValue, p1: Nothing?) {}
override fun visitCharValue(p0: CharValue?, p1: Nothing?) {}
override fun visitIntValue(p0: IntValue?, p1: Nothing?) {}
override fun visitErrorValue(p0: ErrorValue?, p1: Nothing?) {}
override fun visitFloatValue(p0: FloatValue?, p1: Nothing?) {}
override fun visitEnumValue(p0: EnumValue?, p1: Nothing?) {}
override fun visitStringValue(p0: StringValue?, p1: Nothing?) {}
}, null)
}
}
override fun visitFunction(declaration: IrFunction) {
super.visitFunction(declaration)
declaration.returnType.referenceAllClassifiers()
}
override fun visitFunctionAccess(expression: IrFunctionAccessExpression) {
super.visitFunctionAccess(expression)
expression.descriptor.original.typeParameters.forEach {
expression.getTypeArgumentOrDefault(it).referenceAllClassifiers()
}
}
}
this.acceptVoid(visitor)
this.dependencyModules.forEach { module ->
module.externalPackageFragments.forEach {
it.acceptVoid(visitor)
}
}
}

View File

@@ -9,10 +9,14 @@ 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.IntrinsicifyBuiltinOperationsLowering
import org.jetbrains.kotlin.ir.backend.js.lower.FunctionInlining
import org.jetbrains.kotlin.ir.backend.js.lower.SecondaryCtorLowering
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
@@ -44,6 +48,23 @@ fun compile(
ExternalDependenciesGenerator(psi2IrContext.symbolTable, psi2IrContext.irBuiltIns).generateUnboundSymbolsAsDependencies(moduleFragment)
println(moduleFragment.dump())
FunctionInlining(context).inline(moduleFragment)
println(moduleFragment.dump())
val symbolTable = context.symbolTable
moduleFragment.referenceAllTypeExternalClassifiers(symbolTable)
do {
@Suppress("DEPRECATION")
moduleFragment.replaceUnboundSymbols(context)
moduleFragment.referenceAllTypeExternalClassifiers(symbolTable)
} while (symbolTable.unboundClasses.isNotEmpty())
moduleFragment.patchDeclarationParents()
moduleFragment.files.forEach { context.lower(it) }
val transformer = SecondaryCtorLowering.CallsiteRedirectionTransformer(context)
moduleFragment.files.forEach { it.accept(transformer, null) }
@@ -60,4 +81,6 @@ fun JsIrBackendContext.lower(file: IrFile) {
PropertiesLowering().lower(file)
InitializersLowering(this, JsLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, false).runOnFilePostfix(file)
SecondaryCtorLowering(this).lower(file)
IntrinsicifyBuiltinOperationsLowering(this).lower(file)
}

View File

@@ -0,0 +1,764 @@
/*
* 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.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.IrElementVisitorVoidWithContext
import org.jetbrains.kotlin.backend.common.lower.SimpleMemberScope
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.impl.createClassSymbolOrNull
import org.jetbrains.kotlin.ir.symbols.impl.createFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.createValueSymbol
import org.jetbrains.kotlin.ir.util.DeepCopyIrTree
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.typeUtil.makeNullable
internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor,
val parentDescriptor: DeclarationDescriptor,
val context: JsIrBackendContext) {
private val descriptorSubstituteMap: MutableMap<DeclarationDescriptor, DeclarationDescriptor> = mutableMapOf()
private var typeSubstitutor: TypeSubstitutor? = null
private var nameIndex = 0
//-------------------------------------------------------------------------//
fun copy(irElement: IrElement, typeSubstitutor: TypeSubstitutor?): IrElement {
this.typeSubstitutor = typeSubstitutor
// Create all class descriptors and all necessary descriptors in order to create KotlinTypes.
irElement.acceptChildrenVoid(DescriptorCollectorCreatePhase())
// Initialize all created descriptors possibly using previously created types.
irElement.acceptChildrenVoid(DescriptorCollectorInitPhase())
return irElement.accept(InlineCopyIr(), null)
}
inner class DescriptorCollectorCreatePhase : IrElementVisitorVoidWithContext() {
override fun visitElement(element: IrElement) {
element.acceptChildren(this, null)
}
//---------------------------------------------------------------------//
override fun visitClassNew(declaration: IrClass) {
val oldDescriptor = declaration.descriptor
val newDescriptor = copyClassDescriptor(oldDescriptor)
descriptorSubstituteMap[oldDescriptor] = newDescriptor
descriptorSubstituteMap[oldDescriptor.thisAsReceiverParameter] = newDescriptor.thisAsReceiverParameter
super.visitClassNew(declaration)
val constructors = oldDescriptor.constructors.map { oldConstructorDescriptor ->
descriptorSubstituteMap[oldConstructorDescriptor] as ClassConstructorDescriptor
}.toSet()
val oldPrimaryConstructor = oldDescriptor.unsubstitutedPrimaryConstructor
val primaryConstructor = oldPrimaryConstructor?.let { descriptorSubstituteMap[it] as ClassConstructorDescriptor }
val contributedDescriptors = oldDescriptor.unsubstitutedMemberScope
.getContributedDescriptors()
.map { descriptorSubstituteMap[it]!! }
newDescriptor.initialize(
SimpleMemberScope(contributedDescriptors),
constructors,
primaryConstructor
)
}
//---------------------------------------------------------------------//
override fun visitPropertyNew(declaration: IrProperty) {
copyPropertyOrField(declaration.descriptor)
super.visitPropertyNew(declaration)
}
//---------------------------------------------------------------------//
override fun visitFieldNew(declaration: IrField) {
val oldDescriptor = declaration.descriptor
if (descriptorSubstituteMap[oldDescriptor] == null) {
copyPropertyOrField(oldDescriptor) // A field without a property or a field of a delegated property.
}
super.visitFieldNew(declaration)
}
//---------------------------------------------------------------------//
override fun visitFunctionNew(declaration: IrFunction) {
val oldDescriptor = declaration.descriptor
if (oldDescriptor !is PropertyAccessorDescriptor) { // Property accessors are copied along with their property.
val oldContainingDeclaration =
if (oldDescriptor.visibility == Visibilities.LOCAL)
parentDescriptor
else
oldDescriptor.containingDeclaration
descriptorSubstituteMap[oldDescriptor] = copyFunctionDescriptor(oldDescriptor, oldContainingDeclaration)
}
super.visitFunctionNew(declaration)
}
//--- Copy descriptors ------------------------------------------------//
private fun generateCopyName(name: Name): Name {
val declarationName = name.toString() // Name of declaration
val indexStr = (nameIndex++).toString() // Unique for inline target index
return Name.identifier(declarationName + "_" + indexStr)
}
//---------------------------------------------------------------------//
private fun copyFunctionDescriptor(oldDescriptor: CallableDescriptor, oldContainingDeclaration: DeclarationDescriptor) =
when (oldDescriptor) {
is ConstructorDescriptor -> copyConstructorDescriptor(oldDescriptor)
is SimpleFunctionDescriptor -> copySimpleFunctionDescriptor(oldDescriptor, oldContainingDeclaration)
else -> TODO("Unsupported FunctionDescriptor subtype: $oldDescriptor")
}
//---------------------------------------------------------------------//
private fun copySimpleFunctionDescriptor(oldDescriptor: SimpleFunctionDescriptor, oldContainingDeclaration: DeclarationDescriptor) : FunctionDescriptor {
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
return SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ newContainingDeclaration,
/* annotations = */ oldDescriptor.annotations,
/* name = */ generateCopyName(oldDescriptor.name),
/* kind = */ oldDescriptor.kind,
/* source = */ oldDescriptor.source
)
}
//---------------------------------------------------------------------//
private fun copyConstructorDescriptor(oldDescriptor: ConstructorDescriptor) : FunctionDescriptor {
val oldContainingDeclaration = oldDescriptor.containingDeclaration
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
return ClassConstructorDescriptorImpl.create(
/* containingDeclaration = */ newContainingDeclaration as ClassDescriptor,
/* annotations = */ oldDescriptor.annotations,
/* isPrimary = */ oldDescriptor.isPrimary,
/* source = */ oldDescriptor.source
)
}
//---------------------------------------------------------------------//
private fun copyPropertyOrField(oldDescriptor: PropertyDescriptor) {
val oldContainingDeclaration = oldDescriptor.containingDeclaration
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration) as ClassDescriptor
@Suppress("DEPRECATION")
val newDescriptor = PropertyDescriptorImpl.create(
/* containingDeclaration = */ newContainingDeclaration,
/* annotations = */ oldDescriptor.annotations,
/* modality = */ oldDescriptor.modality,
/* visibility = */ oldDescriptor.visibility,
/* isVar = */ oldDescriptor.isVar,
/* name = */ oldDescriptor.name,
/* kind = */ oldDescriptor.kind,
/* source = */ oldDescriptor.source,
/* lateInit = */ oldDescriptor.isLateInit,
/* isConst = */ oldDescriptor.isConst,
/* isExpect = */ oldDescriptor.isExpect,
/* isActual = */ oldDescriptor.isActual,
/* isExternal = */ oldDescriptor.isExternal,
/* isDelegated = */ oldDescriptor.isDelegated
)
descriptorSubstituteMap[oldDescriptor] = newDescriptor
}
//---------------------------------------------------------------------//
private fun copyClassDescriptor(oldDescriptor: ClassDescriptor): ClassDescriptorImpl {
val oldSuperClass = oldDescriptor.getSuperClassOrAny()
val newSuperClass = descriptorSubstituteMap.getOrDefault(oldSuperClass, oldSuperClass) as ClassDescriptor
val oldInterfaces = oldDescriptor.getSuperInterfaces()
val newInterfaces = oldInterfaces.map { descriptorSubstituteMap.getOrDefault(it, it) as ClassDescriptor }
val oldContainingDeclaration = oldDescriptor.containingDeclaration
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
val newName = if (DescriptorUtils.isAnonymousObject(oldDescriptor)) // Anonymous objects are identified by their name.
oldDescriptor.name // We need to preserve it for LocalDeclarationsLowering.
else
generateCopyName(oldDescriptor.name)
val visibility = oldDescriptor.visibility
return object : ClassDescriptorImpl(
/* containingDeclaration = */ newContainingDeclaration,
/* name = */ newName,
/* modality = */ oldDescriptor.modality,
/* kind = */ oldDescriptor.kind,
/* supertypes = */ listOf(newSuperClass.defaultType) + newInterfaces.map { it.defaultType },
/* source = */ oldDescriptor.source,
/* isExternal = */ oldDescriptor.isExternal,
LockBasedStorageManager.NO_LOCKS
) {
override fun getVisibility() = visibility
}
}
}
//-------------------------------------------------------------------------//
inner class DescriptorCollectorInitPhase : IrElementVisitorVoidWithContext() {
private val initializedProperties = mutableSetOf<PropertyDescriptor>()
override fun visitElement(element: IrElement) {
element.acceptChildren(this, null)
}
//---------------------------------------------------------------------//
override fun visitPropertyNew(declaration: IrProperty) {
initPropertyOrField(declaration.descriptor)
super.visitPropertyNew(declaration)
}
//---------------------------------------------------------------------//
override fun visitFieldNew(declaration: IrField) {
val oldDescriptor = declaration.descriptor
if (!initializedProperties.contains(oldDescriptor)) {
initPropertyOrField(oldDescriptor) // A field without a property or a field of a delegated property.
}
super.visitFieldNew(declaration)
}
//---------------------------------------------------------------------//
override fun visitFunctionNew(declaration: IrFunction) {
val oldDescriptor = declaration.descriptor
if (oldDescriptor !is PropertyAccessorDescriptor) { // Property accessors are copied along with their property.
val newDescriptor = initFunctionDescriptor(oldDescriptor)
oldDescriptor.extensionReceiverParameter?.let {
descriptorSubstituteMap[it] = newDescriptor.extensionReceiverParameter!!
}
}
super.visitFunctionNew(declaration)
}
//---------------------------------------------------------------------//
override fun visitVariable(declaration: IrVariable) {
declaration.descriptor.let { descriptorSubstituteMap[it] = copyVariableDescriptor(it) }
super.visitVariable(declaration)
}
//---------------------------------------------------------------------//
override fun visitCatch(aCatch: IrCatch) {
aCatch.parameter.let { descriptorSubstituteMap[it] = copyVariableDescriptor(it) }
super.visitCatch(aCatch)
}
//--- Copy descriptors ------------------------------------------------//
private fun generateCopyName(name: Name): Name {
val declarationName = name.toString() // Name of declaration
val indexStr = (nameIndex++).toString() // Unique for inline target index
return Name.identifier(declarationName + "_" + indexStr)
}
//---------------------------------------------------------------------//
private fun copyVariableDescriptor(oldDescriptor: VariableDescriptor): VariableDescriptor {
val oldContainingDeclaration = oldDescriptor.containingDeclaration
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
return IrTemporaryVariableDescriptorImpl(
containingDeclaration = newContainingDeclaration,
name = generateCopyName(oldDescriptor.name),
outType = substituteTypeAndTryGetCopied(oldDescriptor.type)!!,
isMutable = oldDescriptor.isVar
)
}
//---------------------------------------------------------------------//
private fun initFunctionDescriptor(oldDescriptor: CallableDescriptor): CallableDescriptor =
when (oldDescriptor) {
is ConstructorDescriptor -> initConstructorDescriptor(oldDescriptor)
is SimpleFunctionDescriptor -> initSimpleFunctionDescriptor(oldDescriptor)
else -> TODO("Unsupported FunctionDescriptor subtype: $oldDescriptor")
}
//---------------------------------------------------------------------//
private fun initSimpleFunctionDescriptor(oldDescriptor: SimpleFunctionDescriptor): FunctionDescriptor =
(descriptorSubstituteMap[oldDescriptor] as SimpleFunctionDescriptorImpl).apply {
val oldDispatchReceiverParameter = oldDescriptor.dispatchReceiverParameter
val newDispatchReceiverParameter = oldDispatchReceiverParameter?.let { descriptorSubstituteMap.getOrDefault(it, it) as ReceiverParameterDescriptor }
val newTypeParameters = oldDescriptor.typeParameters // TODO substitute types
val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this)
val newReceiverParameterType = substituteTypeAndTryGetCopied(oldDescriptor.extensionReceiverParameter?.type)
val newReturnType = substituteTypeAndTryGetCopied(oldDescriptor.returnType)
initialize(
/* receiverParameterType = */ newReceiverParameterType,
/* dispatchReceiverParameter = */ newDispatchReceiverParameter,
/* typeParameters = */ newTypeParameters,
/* unsubstitutedValueParameters = */ newValueParameters,
/* unsubstitutedReturnType = */ newReturnType,
/* modality = */ oldDescriptor.modality,
/* visibility = */ oldDescriptor.visibility
)
isTailrec = oldDescriptor.isTailrec
isSuspend = oldDescriptor.isSuspend
overriddenDescriptors += oldDescriptor.overriddenDescriptors
}
//---------------------------------------------------------------------//
private fun initConstructorDescriptor(oldDescriptor: ConstructorDescriptor): FunctionDescriptor =
(descriptorSubstituteMap[oldDescriptor] as ClassConstructorDescriptorImpl).apply {
val newTypeParameters = oldDescriptor.typeParameters
val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this)
val receiverParameterType = substituteTypeAndTryGetCopied(oldDescriptor.dispatchReceiverParameter?.type)
val returnType = substituteTypeAndTryGetCopied(oldDescriptor.returnType)
initialize(
/* receiverParameterType = */ receiverParameterType,
/* dispatchReceiverParameter = */ null, // For constructor there is no explicit dispatch receiver.
/* typeParameters = */ newTypeParameters,
/* unsubstitutedValueParameters = */ newValueParameters,
/* unsubstitutedReturnType = */ returnType,
/* modality = */ oldDescriptor.modality,
/* visibility = */ oldDescriptor.visibility
)
}
//---------------------------------------------------------------------//
private fun initPropertyOrField(oldDescriptor: PropertyDescriptor) {
val newDescriptor = (descriptorSubstituteMap[oldDescriptor] as PropertyDescriptorImpl).apply {
setType(
/* outType = */ substituteTypeAndTryGetCopied(oldDescriptor.type)!!,
/* typeParameters = */ oldDescriptor.typeParameters,
/* dispatchReceiverParameter = */ (containingDeclaration as ClassDescriptor).thisAsReceiverParameter,
/* receiverType = */ substituteTypeAndTryGetCopied(oldDescriptor.extensionReceiverParameter?.type))
initialize(
/* getter = */ oldDescriptor.getter?.let { copyPropertyGetterDescriptor(it, this) },
/* setter = */ oldDescriptor.setter?.let { copyPropertySetterDescriptor(it, this) })
overriddenDescriptors += oldDescriptor.overriddenDescriptors
}
oldDescriptor.getter?.let { descriptorSubstituteMap[it] = newDescriptor.getter!! }
oldDescriptor.setter?.let { descriptorSubstituteMap[it] = newDescriptor.setter!! }
oldDescriptor.extensionReceiverParameter?.let {
descriptorSubstituteMap[it] = newDescriptor.extensionReceiverParameter!!
}
initializedProperties.add(oldDescriptor)
}
//---------------------------------------------------------------------//
private fun copyPropertyGetterDescriptor(oldDescriptor: PropertyGetterDescriptor, newPropertyDescriptor: PropertyDescriptor) =
PropertyGetterDescriptorImpl(
/* correspondingProperty = */ newPropertyDescriptor,
/* annotations = */ oldDescriptor.annotations,
/* modality = */ oldDescriptor.modality,
/* visibility = */ oldDescriptor.visibility,
/* isDefault = */ oldDescriptor.isDefault,
/* isExternal = */ oldDescriptor.isExternal,
/* isInline = */ oldDescriptor.isInline,
/* kind = */ oldDescriptor.kind,
/* original = */ null,
/* source = */ oldDescriptor.source).apply {
initialize(substituteTypeAndTryGetCopied(oldDescriptor.returnType))
}
//---------------------------------------------------------------------//
private fun copyPropertySetterDescriptor(oldDescriptor: PropertySetterDescriptor, newPropertyDescriptor: PropertyDescriptor) =
PropertySetterDescriptorImpl(
/* correspondingProperty = */ newPropertyDescriptor,
/* annotations = */ oldDescriptor.annotations,
/* modality = */ oldDescriptor.modality,
/* visibility = */ oldDescriptor.visibility,
/* isDefault = */ oldDescriptor.isDefault,
/* isExternal = */ oldDescriptor.isExternal,
/* isInline = */ oldDescriptor.isInline,
/* kind = */ oldDescriptor.kind,
/* original = */ null,
/* source = */ oldDescriptor.source).apply {
initialize(copyValueParameters(oldDescriptor.valueParameters, this).single())
}
//-------------------------------------------------------------------------//
private fun copyValueParameters(oldValueParameters: List <ValueParameterDescriptor>, containingDeclaration: CallableDescriptor) =
oldValueParameters.map { oldDescriptor ->
val newDescriptor = ValueParameterDescriptorImpl(
containingDeclaration = containingDeclaration,
original = oldDescriptor.original,
index = oldDescriptor.index,
annotations = oldDescriptor.annotations,
name = oldDescriptor.name,
outType = substituteTypeAndTryGetCopied(oldDescriptor.type)!!,
declaresDefaultValue = oldDescriptor.declaresDefaultValue(),
isCrossinline = oldDescriptor.isCrossinline,
isNoinline = oldDescriptor.isNoinline,
varargElementType = substituteTypeAndTryGetCopied(oldDescriptor.varargElementType),
source = oldDescriptor.source
)
descriptorSubstituteMap[oldDescriptor] = newDescriptor
newDescriptor
}
private fun substituteTypeAndTryGetCopied(type: KotlinType?): KotlinType? {
val substitutedType = substituteType(type) ?: return null
val oldClassDescriptor = TypeUtils.getClassDescriptor(substitutedType) ?: return substitutedType
return descriptorSubstituteMap[oldClassDescriptor]?.let { (it as ClassDescriptor).defaultType } ?: substitutedType
}
}
//-----------------------------------------------------------------------------//
@Suppress("DEPRECATION")
inner class InlineCopyIr : DeepCopyIrTree() {
override fun mapClassDeclaration (descriptor: ClassDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassDescriptor
override fun mapTypeAliasDeclaration (descriptor: TypeAliasDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as TypeAliasDescriptor
override fun mapFunctionDeclaration (descriptor: FunctionDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as FunctionDescriptor
override fun mapConstructorDeclaration (descriptor: ClassConstructorDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassConstructorDescriptor
override fun mapPropertyDeclaration (descriptor: PropertyDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as PropertyDescriptor
override fun mapLocalPropertyDeclaration (descriptor: VariableDescriptorWithAccessors) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptorWithAccessors
override fun mapEnumEntryDeclaration (descriptor: ClassDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassDescriptor
override fun mapVariableDeclaration (descriptor: VariableDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptor
override fun mapErrorDeclaration (descriptor: DeclarationDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor)
override fun mapClassReference (descriptor: ClassDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassDescriptor
override fun mapValueReference (descriptor: ValueDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ValueDescriptor
override fun mapVariableReference (descriptor: VariableDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptor
override fun mapPropertyReference (descriptor: PropertyDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as PropertyDescriptor
override fun mapCallee (descriptor: FunctionDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as FunctionDescriptor
override fun mapDelegatedConstructorCallee (descriptor: ClassConstructorDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassConstructorDescriptor
override fun mapEnumConstructorCallee (descriptor: ClassConstructorDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassConstructorDescriptor
override fun mapLocalPropertyReference (descriptor: VariableDescriptorWithAccessors) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptorWithAccessors
override fun mapClassifierReference (descriptor: ClassifierDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassifierDescriptor
override fun mapReturnTarget (descriptor: FunctionDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as FunctionDescriptor
//---------------------------------------------------------------------//
override fun mapSuperQualifier(qualifier: ClassDescriptor?): ClassDescriptor? {
if (qualifier == null) return null
return descriptorSubstituteMap.getOrDefault(qualifier, qualifier) as ClassDescriptor
}
//--- Visits ----------------------------------------------------------//
override fun visitCall(expression: IrCall): IrCall {
if (expression !is IrCallImpl) return super.visitCall(expression)
val newDescriptor = mapCallee(expression.descriptor)
return IrCallImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = newDescriptor.returnType!!,
descriptor = newDescriptor,
typeArgumentsCount = expression.typeArgumentsCount,
origin = expression.origin,
superQualifierDescriptor = mapSuperQualifier(expression.superQualifier)
).apply {
transformValueArguments(expression)
substituteTypeArguments(expression)
}
}
//---------------------------------------------------------------------//
override fun visitFunction(declaration: IrFunction): IrFunction =
IrFunctionImpl(
startOffset = declaration.startOffset,
endOffset = declaration.endOffset,
origin = mapDeclarationOrigin(declaration.origin),
descriptor = mapFunctionDeclaration(declaration.descriptor),
body = declaration.body?.transform(this, null)
).also {
it.setOverrides(context.symbolTable)
}.transformParameters(declaration)
//---------------------------------------------------------------------//
private fun <T : IrFunction> T.transformDefaults(original: T): T {
for (originalValueParameter in original.descriptor.valueParameters) {
val valueParameter = descriptor.valueParameters[originalValueParameter.index]
original.getDefault(originalValueParameter)?.let { irDefaultParameterValue ->
putDefault(valueParameter, irDefaultParameterValue.transform(this@InlineCopyIr, null))
}
}
return this
}
//---------------------------------------------------------------------//
fun getTypeOperatorReturnType(operator: IrTypeOperator, type: KotlinType) : KotlinType {
return when (operator) {
IrTypeOperator.CAST,
IrTypeOperator.IMPLICIT_CAST,
IrTypeOperator.IMPLICIT_NOTNULL,
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT,
IrTypeOperator.IMPLICIT_INTEGER_COERCION -> type
IrTypeOperator.SAFE_CAST -> type.makeNullable()
IrTypeOperator.INSTANCEOF,
IrTypeOperator.NOT_INSTANCEOF -> context.builtIns.booleanType
}
}
//---------------------------------------------------------------------//
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrTypeOperatorCall {
val typeOperand = substituteType(expression.typeOperand)!!
val returnType = getTypeOperatorReturnType(expression.operator, typeOperand)
return IrTypeOperatorCallImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = returnType,
operator = expression.operator,
typeOperand = typeOperand,
argument = expression.argument.transform(this, null)
)
}
//---------------------------------------------------------------------//
override fun visitReturn(expression: IrReturn): IrReturn =
IrReturnImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = substituteType(expression.type)!!,
returnTargetDescriptor = mapReturnTarget(expression.returnTarget),
value = expression.value.transform(this, null)
)
//---------------------------------------------------------------------//
override fun visitBlock(expression: IrBlock): IrBlock {
return if (expression is IrReturnableBlock) {
IrReturnableBlockImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = expression.type,
descriptor = expression.descriptor,
origin = mapStatementOrigin(expression.origin),
statements = expression.statements.map { it.transform(this, null) },
sourceFileName = expression.sourceFileName
)
} else {
super.visitBlock(expression)
}
}
//-------------------------------------------------------------------------//
override fun visitClassReference(expression: IrClassReference): IrClassReference {
val newExpressionType = substituteType(expression.type)!! // Substituted expression type.
val newDescriptorType = substituteType(expression.descriptor.defaultType)!! // Substituted type of referenced class.
val classDescriptor = newDescriptorType.constructor.declarationDescriptor!! // Get ClassifierDescriptor of the referenced class.
return IrClassReferenceImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = newExpressionType,
descriptor = classDescriptor,
classType = expression.classType
)
}
//-------------------------------------------------------------------------//
override fun visitGetClass(expression: IrGetClass): IrGetClass {
val type = substituteType(expression.type)!!
return IrGetClassImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = type,
argument = expression.argument.transform(this, null)
)
}
//-------------------------------------------------------------------------//
override fun getNonTransformedLoop(irLoop: IrLoop): IrLoop {
return irLoop
}
}
//-------------------------------------------------------------------------//
private fun substituteType(oldType: KotlinType?): KotlinType? {
if (typeSubstitutor == null) return oldType
if (oldType == null) return oldType
return typeSubstitutor!!.substitute(oldType, Variance.INVARIANT) ?: oldType
}
//-------------------------------------------------------------------------//
private fun IrMemberAccessExpression.substituteTypeArguments(original: IrMemberAccessExpression) {
for (index in 0 until original.typeArgumentsCount) {
val originalTypeArgument = original.getTypeArgument(index)
val newTypeArgument = substituteType(originalTypeArgument)!!
this.putTypeArgument(index, newTypeArgument)
}
}
//-------------------------------------------------------------------------//
fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>) {
descriptorSubstituteMap.forEach { t, u ->
globalSubstituteMap.put(t, SubstitutedDescriptor(targetDescriptor, u))
}
}
}
class SubstitutedDescriptor(val inlinedFunction: FunctionDescriptor, val descriptor: DeclarationDescriptor)
class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>)
: IrElementTransformerVoidWithContext() {
private val variableSubstituteMap = mutableMapOf<VariableDescriptor, VariableDescriptor>()
fun run(element: IrElement) {
collectVariables(element)
element.transformChildrenVoid(this)
}
private fun collectVariables(element: IrElement) {
element.acceptChildrenVoid(object: IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitVariable(declaration: IrVariable) {
declaration.acceptChildrenVoid(this)
val oldDescriptor = declaration.descriptor
val oldClassDescriptor = oldDescriptor.type.constructor.declarationDescriptor as? ClassDescriptor
val substitutedDescriptor = oldClassDescriptor?.let { globalSubstituteMap[it] }
if (substitutedDescriptor == null || allScopes.any { it.scope.scopeOwner == substitutedDescriptor.inlinedFunction })
return
val newDescriptor = IrTemporaryVariableDescriptorImpl(
containingDeclaration = oldDescriptor.containingDeclaration,
name = oldDescriptor.name,
outType = (substitutedDescriptor.descriptor as ClassDescriptor).defaultType,
isMutable = oldDescriptor.isVar)
variableSubstituteMap[oldDescriptor] = newDescriptor
}
})
}
override fun visitCall(expression: IrCall): IrExpression {
val oldExpression = super.visitCall(expression) as IrCall
val substitutedDescriptor = globalSubstituteMap[expression.descriptor.original]
?: return oldExpression
if (allScopes.any { it.scope.scopeOwner == substitutedDescriptor.inlinedFunction })
return oldExpression
return when (oldExpression) {
is IrCallImpl -> copyIrCallImpl(oldExpression, substitutedDescriptor)
is IrCallWithShallowCopy -> copyIrCallWithShallowCopy(oldExpression, substitutedDescriptor)
else -> oldExpression
}
}
//---------------------------------------------------------------------//
override fun visitVariable(declaration: IrVariable): IrDeclaration {
declaration.transformChildrenVoid(this)
val oldDescriptor = declaration.descriptor
val newDescriptor = variableSubstituteMap[oldDescriptor] ?: return declaration
return IrVariableImpl(
startOffset = declaration.startOffset,
endOffset = declaration.endOffset,
origin = declaration.origin,
descriptor = newDescriptor,
initializer = declaration.initializer
)
}
//-------------------------------------------------------------------------//
override fun visitGetValue(expression: IrGetValue): IrExpression {
expression.transformChildrenVoid(this)
val oldDescriptor = expression.descriptor
val newDescriptor = variableSubstituteMap[oldDescriptor] ?: return expression
return IrGetValueImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
origin = expression.origin,
symbol = createValueSymbol(newDescriptor)
)
}
//-------------------------------------------------------------------------//
private fun copyIrCallImpl(oldExpression: IrCallImpl, substitutedDescriptor: SubstitutedDescriptor): IrCallImpl {
val oldDescriptor = oldExpression.descriptor
val newDescriptor = substitutedDescriptor.descriptor as FunctionDescriptor
if (newDescriptor == oldDescriptor)
return oldExpression
return IrCallImpl(
startOffset = oldExpression.startOffset,
endOffset = oldExpression.endOffset,
type = newDescriptor.returnType!!,
symbol = createFunctionSymbol(newDescriptor),
descriptor = newDescriptor,
typeArgumentsCount = oldExpression.typeArgumentsCount,
origin = oldExpression.origin,
superQualifierSymbol = createClassSymbolOrNull(oldExpression.superQualifier)
).apply {
copyTypeArgumentsFrom(oldExpression)
oldExpression.descriptor.valueParameters.forEach {
val valueArgument = oldExpression.getValueArgument(it)
putValueArgument(it.index, valueArgument)
}
extensionReceiver = oldExpression.extensionReceiver
dispatchReceiver = oldExpression.dispatchReceiver
}
}
//-------------------------------------------------------------------------//
private fun copyIrCallWithShallowCopy(oldExpression: IrCallWithShallowCopy, substitutedDescriptor: SubstitutedDescriptor): IrCall {
val oldDescriptor = oldExpression.descriptor
val newDescriptor = substitutedDescriptor.descriptor as FunctionDescriptor
if (newDescriptor == oldDescriptor)
return oldExpression
return oldExpression.shallowCopy(oldExpression.origin, createFunctionSymbol(newDescriptor), oldExpression.superQualifierSymbol)
}
}

View File

@@ -0,0 +1,373 @@
/*
* 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.
*/
@file:Suppress("FoldInitializerAndIfToElvis")
package org.jetbrains.kotlin.ir.backend.js.lower
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.ScopeWithIr
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.reportWarning
import org.jetbrains.kotlin.descriptors.*
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.builders.irCall
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.builders.irReturn
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.getDefault
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.createValueSymbol
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.TypeProjection
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.TypeSubstitutor
//-----------------------------------------------------------------------------//
typealias Context = JsIrBackendContext
internal class FunctionInlining(val context: Context): IrElementTransformerVoidWithContext() {
// TODO private val deserializer = DeserializerDriver(context)
private val globalSubstituteMap = mutableMapOf<DeclarationDescriptor, SubstitutedDescriptor>()
//-------------------------------------------------------------------------//
fun inline(irModule: IrModuleFragment): IrElement {
val transformedModule = irModule.accept(this, null)
DescriptorSubstitutorForExternalScope(globalSubstituteMap).run(transformedModule) // Transform calls to object that might be returned from inline function call.
return transformedModule
}
//-------------------------------------------------------------------------//
override fun visitCall(expression: IrCall): IrExpression {
val irCall = super.visitCall(expression) as IrCall
val functionDescriptor = irCall.descriptor
if (!functionDescriptor.needsInlining) return irCall // This call does not need inlining.
val functionDeclaration = getFunctionDeclaration(irCall) // Get declaration of the function to be inlined.
if (functionDeclaration == null) { // We failed to get the declaration.
val message = "Inliner failed to obtain function declaration: " +
functionDescriptor.fqNameSafe.toString()
context.reportWarning(message, currentFile, irCall) // Report warning.
return irCall
}
functionDeclaration.transformChildrenVoid(this) // Process recursive inline.
val inliner = Inliner(globalSubstituteMap, functionDeclaration, currentScope!!, context) // Create inliner for this scope.
return inliner.inline(irCall ) // Return newly created IrInlineBody instead of IrCall.
}
//-------------------------------------------------------------------------//
private fun getFunctionDeclaration(irCall: IrCall): IrFunction? {
val functionDescriptor = irCall.descriptor
val originalDescriptor = functionDescriptor.resolveFakeOverride().original
val functionDeclaration =
context.originalModuleIndex.functions[originalDescriptor] // ?: // If function is declared in the current module.
// TODO deserializer.deserializeInlineBody(originalDescriptor) // Function is declared in another module.
return functionDeclaration as IrFunction?
}
//-------------------------------------------------------------------------//
override fun visitElement(element: IrElement) = element.accept(this, null)
}
private val inlineConstructor = FqName("konan.internal.InlineConstructor")
private val FunctionDescriptor.isInlineConstructor get() = annotations.hasAnnotation(inlineConstructor)
//-----------------------------------------------------------------------------//
private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>,
val functionDeclaration: IrFunction, // Function to substitute.
val currentScope: ScopeWithIr,
val context: Context) {
val copyIrElement = DeepCopyIrTreeWithDescriptors(functionDeclaration.descriptor, currentScope.scope.scopeOwner, context) // Create DeepCopy for current scope.
val substituteMap = mutableMapOf<ValueDescriptor, IrExpression>()
//-------------------------------------------------------------------------//
fun inline(irCall: IrCall): IrReturnableBlockImpl { // Call to be substituted.
val inlineFunctionBody = inlineFunction(irCall, functionDeclaration)
copyIrElement.addCurrentSubstituteMap(globalSubstituteMap)
return inlineFunctionBody
}
//-------------------------------------------------------------------------//
private fun inlineFunction(callee: IrCall, // Call to be substituted.
caller: IrFunction): IrReturnableBlockImpl { // Function to substitute.
val copyFunctionDeclaration = copyIrElement.copy( // Create copy of original function.
irElement = caller, // Descriptors declared inside the function will be copied.
typeSubstitutor = createTypeSubstitutor(callee) // Type parameters will be substituted with type arguments.
) as IrFunction
val irReturnableBlockSymbol = IrReturnableBlockSymbolImpl(copyFunctionDeclaration.descriptor.original)
val evaluationStatements = evaluateArguments(callee, copyFunctionDeclaration) // And list of evaluation statements.
val statements = (copyFunctionDeclaration.body as IrBlockBody).statements // IR statements from function copy.
val startOffset = caller.startOffset
val endOffset = caller.endOffset
val descriptor = caller.descriptor.original
if (descriptor.isInlineConstructor) {
val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall
val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset)
irBuilder.run {
val constructorDescriptor = delegatingConstructorCall.descriptor.original
val constructorCall = irCall(delegatingConstructorCall.symbol,
constructorDescriptor.typeParameters.associate { it to delegatingConstructorCall.getTypeArgument(it)!! }).apply {
constructorDescriptor.valueParameters.forEach { putValueArgument(it, delegatingConstructorCall.getValueArgument(it)) }
}
val oldThis = delegatingConstructorCall.descriptor.constructedClass.thisAsReceiverParameter
val newThis = currentScope.scope.createTemporaryVariable(
irExpression = constructorCall,
nameHint = delegatingConstructorCall.descriptor.fqNameSafe.toString() + ".this"
)
statements[0] = newThis
substituteMap[oldThis] = irGet(newThis.symbol)
statements.add(irReturn(irGet(newThis.symbol)))
}
}
val returnType = copyFunctionDeclaration.descriptor.returnType!! // Substituted return type.
val sourceFileName = context.originalModuleIndex.declarationToFile[caller.descriptor.original] ?: ""
val inlineFunctionBody = IrReturnableBlockImpl( // Create new IR element to replace "call".
startOffset = startOffset,
endOffset = endOffset,
type = returnType,
symbol = irReturnableBlockSymbol,
origin = null,
statements = statements,
sourceFileName = sourceFileName
)
val transformer = ParameterSubstitutor()
inlineFunctionBody.transformChildrenVoid(transformer) // Replace value parameters with arguments.
inlineFunctionBody.statements.addAll(0, evaluationStatements) // Insert evaluation statements.
return inlineFunctionBody // Replace call site with InlineFunctionBody.
}
//---------------------------------------------------------------------//
private inner class ParameterSubstitutor: IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression {
val newExpression = super.visitGetValue(expression) as IrGetValue
val descriptor = newExpression.descriptor
val argument = substituteMap[descriptor] // Find expression to replace this parameter.
if (argument == null) return newExpression // If there is no such expression - do nothing.
argument.transformChildrenVoid(this) // Default argument can contain subjects for substitution.
return copyIrElement.copy( // Make copy of argument expression.
irElement = argument,
typeSubstitutor = null
) as IrExpression
}
//-----------------------------------------------------------------//
override fun visitCall(expression: IrCall): IrExpression {
if (!isLambdaCall(expression)) return super.visitCall(expression) // If it is not lambda call - return.
val dispatchReceiver = expression.dispatchReceiver as IrGetValue // Here we can have only GetValue as dispatch receiver.
val functionArgument = substituteMap[dispatchReceiver.descriptor] // Try to find lambda representation. // TODO original?
if (functionArgument == null) return super.visitCall(expression) // It is not call of argument lambda - nothing to substitute.
if (functionArgument !is IrBlock) return super.visitCall(expression)
val dispatchDescriptor = dispatchReceiver.descriptor // Check if this functional parameter has "noInline" tag
if (dispatchDescriptor is ValueParameterDescriptor &&
dispatchDescriptor.isNoinline) return super.visitCall(expression)
val functionDeclaration = getLambdaFunction(functionArgument)
val newExpression = inlineFunction(expression, functionDeclaration) // Inline the lambda. Lambda parameters will be substituted with lambda arguments.
return newExpression.transform(this, null) // Substitute lambda arguments with target function arguments.
}
//-----------------------------------------------------------------//
override fun visitElement(element: IrElement) = element.accept(this, null)
}
//--- Helpers -------------------------------------------------------------//
private fun isLambdaCall(irCall: IrCall) : Boolean {
if (!irCall.descriptor.isFunctionInvoke) return false // Lambda mast be called by "invoke".
if (irCall.dispatchReceiver !is IrGetValue) return false // Dispatch receiver mast be IrGetValue.
return true // It is lambda call.
}
//-------------------------------------------------------------------------//
private fun getLambdaFunction(lambdaArgument: IrBlock): IrFunction {
val statements = lambdaArgument.statements
return statements[0] as IrFunction
}
//-------------------------------------------------------------------------//
private fun createTypeSubstitutor(irCall: IrCall): TypeSubstitutor? {
if (irCall.typeArgumentsCount == 0) return null
val descriptor = irCall.descriptor.resolveFakeOverride().original
val typeParameters = descriptor.propertyIfAccessor.typeParameters
val substitutionContext = mutableMapOf<TypeConstructor, TypeProjection>()
for (index in 0 until irCall.typeArgumentsCount) {
val typeArgument = irCall.getTypeArgument(index) ?: continue
substitutionContext[typeParameters[index].typeConstructor] = TypeProjectionImpl(typeArgument)
}
return TypeSubstitutor.create(substitutionContext)
}
//-------------------------------------------------------------------------//
private class ParameterToArgument(val parameterDescriptor: ParameterDescriptor,
val argumentExpression : IrExpression) {
val isInlinableLambda : Boolean
get() {
if (!InlineUtil.isInlineParameter(parameterDescriptor)) return false
if (argumentExpression !is IrBlock) return false // Lambda must be represented with IrBlock.
if (argumentExpression.origin != IrStatementOrigin.LAMBDA && // Origin must be LAMBDA or ANONYMOUS.
argumentExpression.origin != IrStatementOrigin.ANONYMOUS_FUNCTION) return false
val statements = argumentExpression.statements
val irFunction = statements[0] // Lambda function declaration.
val irCallableReference = statements[1] // Lambda callable reference.
if (irFunction !is IrFunction) return false // First statement of the block must be lambda declaration.
if (irCallableReference !is IrCallableReference) return false // Second statement of the block must be CallableReference.
return true // The expression represents lambda.
}
}
//-------------------------------------------------------------------------//
private fun buildParameterToArgument(irCall : IrCall, // Call site.
irFunction: IrFunction // Function to be called.
): List<ParameterToArgument> {
val parameterToArgument = mutableListOf<ParameterToArgument>() // Result list.
val functionDescriptor = irFunction.descriptor.original // Descriptor of function to be called.
if (irCall.dispatchReceiver != null && // Only if there are non null dispatch receivers both
functionDescriptor.dispatchReceiverParameter != null) // on call site and in function declaration.
parameterToArgument += ParameterToArgument(
parameterDescriptor = functionDescriptor.dispatchReceiverParameter!!,
argumentExpression = irCall.dispatchReceiver!!
)
val valueArguments =
irCall.descriptor.valueParameters.map { irCall.getValueArgument(it) }.toMutableList()
if (functionDescriptor.extensionReceiverParameter != null) {
parameterToArgument += ParameterToArgument(
parameterDescriptor = functionDescriptor.extensionReceiverParameter!!,
argumentExpression = if (irCall.extensionReceiver != null) {
irCall.extensionReceiver!!
} else {
// Special case: lambda with receiver is called as usual lambda:
valueArguments.removeAt(0)!!
}
)
} else if (irCall.extensionReceiver != null) {
// Special case: usual lambda is called as lambda with receiver:
valueArguments.add(0, irCall.extensionReceiver!!)
}
val parametersWithDefaultToArgument = mutableListOf<ParameterToArgument>()
functionDescriptor.valueParameters.forEach { parameterDescriptor -> // Iterate value parameter descriptors.
val argument = valueArguments[parameterDescriptor.index] // Get appropriate argument from call site.
when {
argument != null -> { // Argument is good enough.
parameterToArgument += ParameterToArgument( // Associate current parameter with the argument.
parameterDescriptor = parameterDescriptor,
argumentExpression = argument
)
}
parameterDescriptor.hasDefaultValue() -> { // There is no argument - try default value.
val defaultArgument = irFunction.getDefault(parameterDescriptor)!!
parametersWithDefaultToArgument += ParameterToArgument(
parameterDescriptor = parameterDescriptor,
argumentExpression = defaultArgument.expression
)
}
parameterDescriptor.varargElementType != null -> {
val emptyArray = IrVarargImpl(
startOffset = irCall.startOffset,
endOffset = irCall.endOffset,
type = parameterDescriptor.type,
varargElementType = parameterDescriptor.varargElementType!!
)
parameterToArgument += ParameterToArgument(
parameterDescriptor = parameterDescriptor,
argumentExpression = emptyArray
)
}
else -> {
val message = "Incomplete expression: call to $functionDescriptor " +
"has no argument at index ${parameterDescriptor.index}"
throw Error(message)
}
}
}
return parameterToArgument + parametersWithDefaultToArgument // All arguments except default are evaluated at callsite,
// but default arguments are evaluated inside callee.
}
//-------------------------------------------------------------------------//
private fun evaluateArguments(irCall : IrCall, // Call site.
functionDeclaration: IrFunction // Function to be called.
): List<IrStatement> {
val parameterToArgumentOld = buildParameterToArgument(irCall, functionDeclaration) // Create map parameter_descriptor -> original_argument_expression.
val evaluationStatements = mutableListOf<IrStatement>() // List of evaluation statements.
val substitutor = ParameterSubstitutor()
parameterToArgumentOld.forEach {
val parameterDescriptor = it.parameterDescriptor
if (it.isInlinableLambda || it.argumentExpression is IrGetValue) { // If argument is inlinable lambda. IrGetValue is skipped because of recursive inline.
substituteMap[parameterDescriptor] = it.argumentExpression // Associate parameter with lambda argument.
return@forEach
}
val newVariable = currentScope.scope.createTemporaryVariable( // Create new variable and init it with the parameter expression.
irExpression = it.argumentExpression.transform(substitutor, data = null), // Arguments may reference the previous ones - substitute them.
nameHint = functionDeclaration.descriptor.name.toString(),
isMutable = false)
evaluationStatements.add(newVariable) // Add initialization of the new variable in statement list.
val getVal = IrGetValueImpl( // Create new expression, representing access the new variable.
startOffset = currentScope.irElement.startOffset,
endOffset = currentScope.irElement.endOffset,
symbol = createValueSymbol(newVariable.descriptor)
)
substituteMap[parameterDescriptor] = getVal // Parameter will be replaced with the new variable.
}
return evaluationStatements
}
}

View File

@@ -0,0 +1,171 @@
/*
* 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.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.utils.name
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
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.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.util.OperatorNameConventions
class IntrinsicifyBuiltinOperationsLowering(private val context: JsIrBackendContext) : FileLoweringPass {
// TODO: should/can we unify these maps?
private val primitiveNumberIntrinsics: Map<SimpleMemberKey, IrSimpleFunction>
private val comparisonIntrinsics: Map<IrFunctionSymbol, IrSimpleFunction>
init {
primitiveNumberIntrinsics = mutableMapOf()
comparisonIntrinsics = mutableMapOf()
primitiveNumberIntrinsics.run {
val primitiveNumbers = context.irBuiltIns.run { listOf(int, short, byte, float, double) }
for (type in primitiveNumbers) {
op(type, OperatorNameConventions.UNARY_PLUS, context.intrinsics.jsUnaryPlus)
op(type, OperatorNameConventions.UNARY_MINUS, context.intrinsics.jsUnaryMinus)
// TODO: inc & dec are mapped wrongly
op(type, OperatorNameConventions.INC, context.intrinsics.jsPrefixInc)
op(type, OperatorNameConventions.DEC, context.intrinsics.jsPrefixDec)
op(type, OperatorNameConventions.PLUS, context.intrinsics.jsPlus)
op(type, OperatorNameConventions.MINUS, context.intrinsics.jsMinus)
op(type, OperatorNameConventions.TIMES, context.intrinsics.jsMult)
op(type, OperatorNameConventions.DIV, context.intrinsics.jsDiv)
op(type, OperatorNameConventions.MOD, context.intrinsics.jsMod)
op(type, OperatorNameConventions.REM, context.intrinsics.jsMod)
}
context.irBuiltIns.int.let {
op(it, "shl", context.intrinsics.jsBitShiftL)
op(it, "shr", context.intrinsics.jsBitShiftR)
op(it, "ushr", context.intrinsics.jsBitShiftRU)
op(it, "and", context.intrinsics.jsBitAnd)
op(it, "or", context.intrinsics.jsBitOr)
op(it, "xor", context.intrinsics.jsBitXor)
op(it, "inv", context.intrinsics.jsBitNot)
}
context.irBuiltIns.bool.let {
op(it, OperatorNameConventions.AND, context.intrinsics.jsAnd)
op(it, OperatorNameConventions.OR, context.intrinsics.jsOr)
op(it, OperatorNameConventions.NOT, context.intrinsics.jsNot)
op(it, "xor", context.intrinsics.jsBitXor)
}
}
comparisonIntrinsics.run {
add(context.irBuiltIns.eqeqeqSymbol, context.intrinsics.jsEqeqeq)
// TODO: implement it a right way
add(context.irBuiltIns.eqeqSymbol, context.intrinsics.jsEqeq)
// TODO: implement it a right way
add(context.irBuiltIns.ieee754equalsFunByOperandType, context.intrinsics.jsEqeqeq)
add(context.irBuiltIns.booleanNotSymbol, context.intrinsics.jsNot)
add(context.irBuiltIns.lessFunByOperandType, context.intrinsics.jsLt)
add(context.irBuiltIns.lessOrEqualFunByOperandType, context.intrinsics.jsLtEq)
add(context.irBuiltIns.greaterFunByOperandType, context.intrinsics.jsGt)
add(context.irBuiltIns.greaterOrEqualFunByOperandType, context.intrinsics.jsGtEq)
}
}
override fun lower(irFile: IrFile) {
irFile.transform(object : IrElementTransformerVoid() {
override fun visitCall(expression: IrCall): IrExpression {
val call = super.visitCall(expression)
if (call is IrCall) {
val symbol = call.symbol
comparisonIntrinsics[symbol]?.let {
return irCall(call, it.symbol)
}
(symbol.owner as? IrFunction)?.dispatchReceiverParameter?.let {
val key = SimpleMemberKey(it.type, symbol.name)
primitiveNumberIntrinsics[key]?.let {
// TODO: don't apply intrinsics when type of receiver or argument is Long
return irCall(call, it.symbol, dispatchReceiverAsFirstArgument = true)
}
}
}
return call
}
}, null)
}
}
// TODO extract to common place?
private fun irCall(call: IrCall, newSymbol: IrFunctionSymbol, dispatchReceiverAsFirstArgument: Boolean = false): IrCall =
call.run {
IrCallImpl(
startOffset,
endOffset,
type,
newSymbol,
newSymbol.descriptor,
typeArgumentsCount,
origin,
superQualifierSymbol
).apply {
copyTypeAndValueArgumentsFrom(call, dispatchReceiverAsFirstArgument)
}
}
// TODO extract to common place?
private fun IrCall.copyTypeAndValueArgumentsFrom(call: IrCall, dispatchReceiverAsFirstArgument: Boolean = false) {
copyTypeArgumentsFrom(call)
var j = 0
if (!dispatchReceiverAsFirstArgument) {
dispatchReceiver = call.dispatchReceiver
} else {
putValueArgument(j++, call.dispatchReceiver)
}
extensionReceiver = call.extensionReceiver
for (i in 0 until call.valueArgumentsCount) {
putValueArgument(j++, call.getValueArgument(i))
}
}
private fun <V> MutableMap<SimpleMemberKey, V>.op(type: KotlinType, name: Name, v: V) {
put(SimpleMemberKey(type, name), v)
}
// TODO issue: marked as unused, but used; rename works wrongly.
private fun <V> MutableMap<SimpleMemberKey, V>.op(type: KotlinType, name: String, v: V) {
put(SimpleMemberKey(type, Name.identifier(name)), v)
}
private fun <V> MutableMap<IrFunctionSymbol, V>.add(from: Map<SimpleType, IrSimpleFunction>, to: V) {
from.forEach { _, func ->
add(func.symbol, to)
}
}
private fun <V> MutableMap<IrFunctionSymbol, V>.add(from: IrFunctionSymbol, to: V) {
put(from, to)
}
private data class SimpleMemberKey(val klass: KotlinType, val name: Name)

View File

@@ -0,0 +1,365 @@
/*
* 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.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.expressions.IrConstKind
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.endOffset
import org.jetbrains.kotlin.ir.util.startOffset
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.resolve.OverridingStrategy
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.types.KotlinType
import java.lang.reflect.Proxy
//TODO: delete file on next kotlin dependency update
internal fun IrExpression.isNullConst() = this is IrConst<*> && this.kind == IrConstKind.Null
private var topLevelInitializersCounter = 0
//internal fun IrFile.addTopLevelInitializer(expression: IrExpression) {
// val fieldDescriptor = PropertyDescriptorImpl.create(
// this.packageFragmentDescriptor,
// Annotations.EMPTY,
// Modality.FINAL,
// Visibilities.PRIVATE,
// false,
// "topLevelInitializer${topLevelInitializersCounter++}".synthesizedName,
// CallableMemberDescriptor.Kind.DECLARATION,
// SourceElement.NO_SOURCE,
// false,
// false,
// false,
// false,
// false,
// false
// )
//
// val builtIns = fieldDescriptor.builtIns
// fieldDescriptor.setType(builtIns.unitType, emptyList(), null, null as KotlinType?)
// fieldDescriptor.initialize(null, null)
//
// val irField = IrFieldImpl(
// expression.startOffset, expression.endOffset,
// IrDeclarationOrigin.DEFINED, fieldDescriptor
// )
//
// val initializer = IrTypeOperatorCallImpl(
// expression.startOffset, expression.endOffset, builtIns.unitType,
// IrTypeOperator.IMPLICIT_COERCION_TO_UNIT, builtIns.unitType, expression
// )
//
// irField.initializer = IrExpressionBodyImpl(expression.startOffset, expression.endOffset, initializer)
//
// this.addChild(irField)
//}
fun IrClass.addFakeOverrides() {
val startOffset = this.startOffset
val endOffset = this.endOffset
descriptor.unsubstitutedMemberScope.getContributedDescriptors()
.filterIsInstance<CallableMemberDescriptor>()
.filter { it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE }
.forEach {
this.addChild(createFakeOverride(it, startOffset, endOffset))
}
}
private fun createFakeOverride(descriptor: CallableMemberDescriptor, startOffset: Int, endOffset: Int): IrDeclaration {
fun FunctionDescriptor.createFunction(): IrFunction = IrFunctionImpl(
startOffset, endOffset,
IrDeclarationOrigin.FAKE_OVERRIDE, this
).apply {
createParameterDeclarations()
}
return when (descriptor) {
is FunctionDescriptor -> descriptor.createFunction()
is PropertyDescriptor ->
IrPropertyImpl(startOffset, endOffset, IrDeclarationOrigin.FAKE_OVERRIDE, descriptor).apply {
// TODO: add field if getter is missing?
getter = descriptor.getter?.createFunction()
setter = descriptor.setter?.createFunction()
}
else -> TODO(descriptor.toString())
}
}
fun IrFunction.createParameterDeclarations() {
fun ParameterDescriptor.irValueParameter() = IrValueParameterImpl(
innerStartOffset(this), innerEndOffset(this),
IrDeclarationOrigin.DEFINED,
this
).also {
it.parent = this@createParameterDeclarations
}
dispatchReceiverParameter = descriptor.dispatchReceiverParameter?.irValueParameter()
extensionReceiverParameter = descriptor.extensionReceiverParameter?.irValueParameter()
assert(valueParameters.isEmpty())
descriptor.valueParameters.mapTo(valueParameters) { it.irValueParameter() }
assert(typeParameters.isEmpty())
descriptor.typeParameters.mapTo(typeParameters) {
IrTypeParameterImpl(
innerStartOffset(it), innerEndOffset(it),
IrDeclarationOrigin.DEFINED,
it
).also { typeParameter ->
typeParameter.parent = this
}
}
}
fun IrSimpleFunction.setOverrides(symbolTable: SymbolTable) {
assert(this.overriddenSymbols.isEmpty())
this.descriptor.overriddenDescriptors.mapTo(this.overriddenSymbols) {
symbolTable.referenceSimpleFunction(it.original)
}
this.typeParameters.forEach { it.setSupers(symbolTable) }
}
fun IrClass.simpleFunctions(): List<IrSimpleFunction> = this.declarations.flatMap {
when (it) {
is IrSimpleFunction -> listOf(it)
is IrProperty -> listOfNotNull(it.getter as IrSimpleFunction?, it.setter as IrSimpleFunction?)
else -> emptyList()
}
}
fun IrClass.createParameterDeclarations() {
descriptor.thisAsReceiverParameter.let {
thisReceiver = IrValueParameterImpl(
innerStartOffset(it), innerEndOffset(it),
IrDeclarationOrigin.INSTANCE_RECEIVER,
it
).also { valueParameter ->
valueParameter.parent = this
}
}
assert(typeParameters.isEmpty())
descriptor.declaredTypeParameters.mapTo(typeParameters) {
IrTypeParameterImpl(
innerStartOffset(it), innerEndOffset(it),
IrDeclarationOrigin.DEFINED,
it
).also { typeParameter ->
typeParameter.parent = this
}
}
}
fun IrClass.setSuperSymbols(supers: List<IrClass>) {
assert(this.superDescriptors().toSet() == supers.map { it.descriptor }.toSet())
assert(this.superClasses.isEmpty())
supers.mapTo(this.superClasses) { it.symbol }
val superMembers = supers.flatMap {
it.simpleFunctions()
}.associateBy { it.descriptor }
this.simpleFunctions().forEach {
assert(it.overriddenSymbols.isEmpty())
it.descriptor.overriddenDescriptors.mapTo(it.overriddenSymbols) {
val superMember = superMembers[it.original] ?: error(it.original)
superMember.symbol
}
}
}
private fun IrClass.superDescriptors() =
this.descriptor.typeConstructor.supertypes.map { it.constructor.declarationDescriptor as ClassDescriptor }
fun IrClass.setSuperSymbols(symbolTable: SymbolTable) {
assert(this.superClasses.isEmpty())
this.superDescriptors().mapTo(this.superClasses) { symbolTable.referenceClass(it) }
this.simpleFunctions().forEach {
it.setOverrides(symbolTable)
}
this.typeParameters.forEach {
it.setSupers(symbolTable)
}
}
fun IrTypeParameter.setSupers(symbolTable: SymbolTable) {
assert(this.superClassifiers.isEmpty())
this.descriptor.upperBounds.mapNotNullTo(this.superClassifiers) {
it.constructor.declarationDescriptor?.let {
if (it is TypeParameterDescriptor) {
IrTypeParameterSymbolImpl(it) // Workaround for deserialized inline functions
} else {
symbolTable.referenceClassifier(it)
}
}
}
}
fun IrClass.setSuperSymbolsAndAddFakeOverrides(supers: List<IrClass>) {
val overriddenSuperMembers = this.declarations.map { it.descriptor }
.filterIsInstance<CallableMemberDescriptor>().flatMap { it.overriddenDescriptors.map { it.original } }
val unoverriddenSuperMembers = supers.flatMap {
it.declarations.mapNotNull {
when (it) {
is IrSimpleFunction -> it.descriptor
is IrProperty -> it.descriptor
else -> null
}
}
} - overriddenSuperMembers
val irClass = this
val overridingStrategy = object : OverridingStrategy() {
override fun addFakeOverride(fakeOverride: CallableMemberDescriptor) {
irClass.addChild(createFakeOverride(fakeOverride, startOffset, endOffset))
}
override fun inheritanceConflict(first: CallableMemberDescriptor, second: CallableMemberDescriptor) {
error("inheritance conflict in synthesized class ${irClass.descriptor}:\n $first\n $second")
}
override fun overrideConflict(fromSuper: CallableMemberDescriptor, fromCurrent: CallableMemberDescriptor) {
error("override conflict in synthesized class ${irClass.descriptor}:\n $fromSuper\n $fromCurrent")
}
}
unoverriddenSuperMembers.groupBy { it.name }.forEach { (name, members) ->
OverridingUtil.generateOverridesInFunctionGroup(
name,
members,
emptyList(),
this.descriptor,
overridingStrategy
)
}
this.setSuperSymbols(supers)
}
private fun IrElement.innerStartOffset(descriptor: DeclarationDescriptorWithSource): Int =
descriptor.startOffset ?: this.startOffset
private fun IrElement.innerEndOffset(descriptor: DeclarationDescriptorWithSource): Int =
descriptor.endOffset ?: this.endOffset
inline fun <reified T> stub(name: String): T {
return Proxy.newProxyInstance(T::class.java.classLoader, arrayOf(T::class.java)) {
_ /* proxy */, method, _ /* methodArgs */ ->
if (method.name == "toString" && method.parameterCount == 0) {
"${T::class.simpleName} stub for $name"
} else {
error("${T::class.simpleName}.${method.name} is not supported for $name")
}
} as T
}
fun IrDeclarationContainer.addChildren(declarations: List<IrDeclaration>) {
declarations.forEach { this.addChild(it) }
}
fun IrDeclarationContainer.addChild(declaration: IrDeclaration) {
this.declarations += declaration
declaration.accept(SetDeclarationsParentVisitor, this)
}
object SetDeclarationsParentVisitor : IrElementVisitor<Unit, IrDeclarationParent> {
override fun visitElement(element: IrElement, data: IrDeclarationParent) {
if (element !is IrDeclarationParent) {
element.acceptChildren(this, data)
}
}
override fun visitDeclaration(declaration: IrDeclaration, data: IrDeclarationParent) {
declaration.parent = data
super.visitDeclaration(declaration, data)
}
}
fun IrModuleFragment.checkDeclarationParents() {
this.accept(CheckDeclarationParentsVisitor, null)
this.dependencyModules.forEach { dependencyModule ->
dependencyModule.externalPackageFragments.forEach {
it.accept(CheckDeclarationParentsVisitor, null)
}
}
}
object CheckDeclarationParentsVisitor : IrElementVisitor<Unit, IrDeclarationParent?> {
override fun visitElement(element: IrElement, data: IrDeclarationParent?) {
element.acceptChildren(this, element as? IrDeclarationParent ?: data)
}
override fun visitDeclaration(declaration: IrDeclaration, data: IrDeclarationParent?) {
if (declaration !is IrVariable) {
checkParent(declaration, data)
} else {
// Don't check IrVariable parent.
}
super.visitDeclaration(declaration, data)
}
private fun checkParent(declaration: IrDeclaration, expectedParent: IrDeclarationParent?) {
val parent = try {
declaration.parent
} catch (e: Throwable) {
error("$declaration for ${declaration.descriptor} has no parent")
}
if (parent != expectedParent) {
error("$declaration for ${declaration.descriptor} has unexpected parent $parent")
}
}
}
tailrec fun IrDeclaration.getContainingFile(): IrFile? {
val parent = this.parent
return when (parent) {
is IrFile -> parent
is IrDeclaration -> parent.getContainingFile()
else -> null
}
}
//internal fun KonanBackendContext.report(declaration: IrDeclaration, message: String, isError: Boolean) {
// val irFile = declaration.getContainingFile()
// this.report(
// declaration,
// irFile,
// if (irFile != null) {
// message
// } else {
// val renderer = org.jetbrains.kotlin.renderer.DescriptorRenderer.COMPACT_WITH_SHORT_TYPES
// "$message\n${renderer.render(declaration.descriptor)}"
// },
// isError
// )
// if (isError) throw KonanCompilationException()
//}

View File

@@ -0,0 +1,173 @@
/*
* 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.atMostOne
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.builtins.getFunctionalClassKind
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.util.OperatorNameConventions
/**
* Implementation of given method.
*
* TODO: this method is actually a part of resolve and probably duplicates another one
*/
internal fun <T : CallableMemberDescriptor> T.resolveFakeOverride(): T {
if (this.kind.isReal) {
return this
} else {
val overridden = OverridingUtil.getOverriddenDeclarations(this)
val filtered = OverridingUtil.filterOutOverridden(overridden)
// TODO: is it correct to take first?
@Suppress("UNCHECKED_CAST")
return filtered.first { it.modality != Modality.ABSTRACT } as T
}
}
//internal val ClassDescriptor.isArray: Boolean
// get() = this.fqNameSafe.asString() in arrayTypes
internal val ClassDescriptor.isInterface: Boolean
get() = (this.kind == ClassKind.INTERFACE)
private val konanInternalPackageName = FqName.fromSegments(listOf("konan", "internal"))
/**
* @return `konan.internal` member scope
*/
//internal val KonanBuiltIns.konanInternal: MemberScope
// get() = this.builtInsModule.getPackage(konanInternalPackageName).memberScope
internal val KotlinType.isKFunctionType: Boolean
get() {
val kind = constructor.declarationDescriptor?.getFunctionalClassKind()
return kind == FunctionClassDescriptor.Kind.KFunction
}
internal val FunctionDescriptor.isFunctionInvoke: Boolean
get() {
val dispatchReceiver = dispatchReceiverParameter ?: return false
assert(!dispatchReceiver.type.isKFunctionType)
return dispatchReceiver.type.isFunctionType &&
this.isOperator && this.name == OperatorNameConventions.INVOKE
}
internal fun ClassDescriptor.isUnit() = this.defaultType.isUnit()
internal val <T : CallableMemberDescriptor> T.allOverriddenDescriptors: List<T>
get() {
val result = mutableListOf<T>()
fun traverse(descriptor: T) {
result.add(descriptor)
@Suppress("UNCHECKED_CAST")
descriptor.overriddenDescriptors.forEach { traverse(it as T) }
}
traverse(this)
return result
}
internal val ClassDescriptor.contributedMethods: List<FunctionDescriptor>
get () = unsubstitutedMemberScope.contributedMethods
internal val MemberScope.contributedMethods: List<FunctionDescriptor>
get () {
val contributedDescriptors = this.getContributedDescriptors()
val functions = contributedDescriptors.filterIsInstance<FunctionDescriptor>()
val properties = contributedDescriptors.filterIsInstance<PropertyDescriptor>()
val getters = properties.mapNotNull { it.getter }
val setters = properties.mapNotNull { it.setter }
return functions + getters + setters
}
fun ClassDescriptor.isAbstract() = this.modality == Modality.SEALED || this.modality == Modality.ABSTRACT
|| this.kind == ClassKind.ENUM_CLASS
internal val FunctionDescriptor.target: FunctionDescriptor
get() = (if (modality == Modality.ABSTRACT) this else resolveFakeOverride()).original
tailrec internal fun DeclarationDescriptor.findPackage(): PackageFragmentDescriptor {
return if (this is PackageFragmentDescriptor) this
else this.containingDeclaration!!.findPackage()
}
internal fun DeclarationDescriptor.allContainingDeclarations(): List<DeclarationDescriptor> {
var list = mutableListOf<DeclarationDescriptor>()
var current = this.containingDeclaration
while (current != null) {
list.add(current)
current = current.containingDeclaration
}
return list
}
// It is possible to declare "external inline fun",
// but it doesn't have much sense for native,
// since externals don't have IR bodies.
// Enforce inlining of constructors annotated with @InlineConstructor.
private val inlineConstructor = FqName("konan.internal.InlineConstructor")
internal val FunctionDescriptor.needsInlining: Boolean
get() {
val inlineConstructor = annotations.hasAnnotation(inlineConstructor)
if (inlineConstructor) return true
return (this.isInline && !this.isExternal)
}
//internal val FunctionDescriptor.needsSerializedIr: Boolean
// get() = (this.needsInlining && this.isExported())
fun AnnotationDescriptor.getStringValueOrNull(name: String): String? {
val constantValue = this.allValueArguments.entries.atMostOne {
it.key.asString() == name
}?.value
return constantValue?.value as String?
}
fun AnnotationDescriptor.getStringValue(name: String): String = this.getStringValueOrNull(name)!!
private fun getPackagesFqNames(module: ModuleDescriptor): Set<FqName> {
val result = mutableSetOf<FqName>()
fun getSubPackages(fqName: FqName) {
result.add(fqName)
module.getSubPackagesOf(fqName) { true }.forEach { getSubPackages(it) }
}
getSubPackages(FqName.ROOT)
return result
}
fun ModuleDescriptor.getPackageFragments(): List<PackageFragmentDescriptor> =
getPackagesFqNames(this).flatMap {
getPackage(it).fragments.filter { it.module == this }
}
val ClassDescriptor.enumEntries: List<ClassDescriptor>
get() {
assert(this.kind == ClassKind.ENUM_CLASS)
return this.unsubstitutedMemberScope.getContributedDescriptors()
.filterIsInstance<ClassDescriptor>()
.filter { it.kind == ClassKind.ENUM_ENTRY }
}
internal val DeclarationDescriptor.isExpectMember: Boolean
get() = this is MemberDescriptor && this.isExpect

View File

@@ -0,0 +1,94 @@
/*
* 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.backend.common.lower.IrBuildingTransformer
import org.jetbrains.kotlin.backend.common.lower.at
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
/**
* This pass runs after inlining and performs the following additional transformations over some operations:
* - Convert immutableBinaryBlobOf() arguments to special IrConst.
* - Convert `obj::class` and `Class::class` to calls.
*/
//internal class PostInlineLowering(val context: JsIrBackendContext) : FileLoweringPass {
//
// private val symbols get() = context.ir.symbols
//
// override fun lower(irFile: IrFile) {
// irFile.transformChildrenVoid(object : IrBuildingTransformer(context) {
//
// override fun visitClassReference(expression: IrClassReference): IrExpression {
// expression.transformChildrenVoid()
// builder.at(expression)
//
// val typeArgument = expression.descriptor.defaultType
//
// return builder.irCall(symbols.kClassImplConstructor, listOf(typeArgument)).apply {
// putValueArgument(0, builder.irCall(symbols.getClassTypeInfo, listOf(typeArgument)))
// }
// }
//
// override fun visitGetClass(expression: IrGetClass): IrExpression {
// expression.transformChildrenVoid()
// builder.at(expression)
//
// val typeArgument = expression.type.arguments.single().type
// return builder.irCall(symbols.kClassImplConstructor, listOf(typeArgument)).apply {
// val typeInfo = builder.irCall(symbols.getObjectTypeInfo).apply {
// putValueArgument(0, expression.argument)
// }
//
// putValueArgument(0, typeInfo)
// }
// }
//
// override fun visitCall(expression: IrCall): IrExpression {
// expression.transformChildrenVoid(this)
//
// if (expression.symbol == context.ir.symbols.immutableBinaryBlobOf) {
// // Convert arguments of the binary blob to special IrConst<String> structure, so that
// // vararg lowering will not affect it.
// val args = expression.getValueArgument(0) as? IrVararg
// if (args == null) throw Error("varargs shall not be lowered yet")
// if (args.elements.any { it is IrSpreadElement }) {
// context.reportCompilationError("no spread elements allowed here", irFile, args)
// }
// val builder = StringBuilder()
// args.elements.forEach {
// if (it !is IrConst<*>) {
// context.reportCompilationError(
// "all elements of binary blob must be constants", irFile, it)
// }
// val value = when (it.kind) {
// IrConstKind.Short -> (it.value as Short).toInt()
// else ->
// context.reportCompilationError("incorrect value for binary data: $it.value", irFile, it)
// }
// if (value < 0 || value > 0xff)
// context.reportCompilationError("incorrect value for binary data: $value", irFile, it)
// // Luckily, all values in range 0x00 .. 0xff represent valid UTF-16 symbols,
// // block 0 (Basic Latin) and block 1 (Latin-1 Supplement) in
// // Basic Multilingual Plane, so we could just append data "as is".
// builder.append(value.toChar())
// }
// expression.putValueArgument(0, IrConstImpl<String>(
// expression.startOffset, expression.endOffset,
// context.ir.symbols.immutableBinaryBlob.descriptor.defaultType,
// IrConstKind.String, builder.toString()))
// }
//
// return expression
// }
// })
// }
//}

View File

@@ -0,0 +1,44 @@
/*
* 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.backend.common.lower.IrBuildingTransformer
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.types.typeUtil.isUnit
/**
* This pass runs before inlining and performs the following additional transformations over some operations:
* - Assertion call removal.
*/
//internal class PreInlineLowering(val context: Context) : FileLoweringPass {
//
// private val symbols get() = context.ir.symbols
//
// private val asserts = symbols.asserts
// private val enableAssertions = context.config.configuration.getBoolean(KonanConfigKeys.ENABLE_ASSERTIONS)
//
// override fun lower(irFile: IrFile) {
// irFile.transformChildrenVoid(object : IrBuildingTransformer(context) {
//
// override fun visitCall(expression: IrCall): IrExpression {
// expression.transformChildrenVoid(this)
//
// // Replace assert() call with an empty composite if assertions are not enabled.
// if (!enableAssertions && expression.symbol in asserts) {
// assert(expression.type.isUnit())
// return IrCompositeImpl(expression.startOffset, expression.endOffset, expression.type)
// }
//
// return expression
// }
// })
// }
//}

View File

@@ -232,7 +232,7 @@ class SecondaryCtorLowering(val context: JsIrBackendContext) : IrElementTransfor
ctorOrig.origin, functionSymbol
)
val createFunctionIntrinsic = context.objectCreate
val createFunctionIntrinsic = context.intrinsics.jsObjectCreate
val irBuilder = context.createIrBuilder(functionSymbol, ctorOrig.startOffset, ctorOrig.endOffset).irBlockBody {
val thisVar = irTemporaryVar(
IrCallImpl(

View File

@@ -0,0 +1,50 @@
/*
* 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.descriptors.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
//val DeserializedPropertyDescriptor.backingField: PropertyDescriptor?
// get() =
// if (this.proto.getExtension(KonanLinkData.hasBackingField))
// this
// else null
//fun DeclarationDescriptor.deepPrint() {
// this.accept(DeepPrintVisitor(PrintVisitor()), 0)
//}
internal val String.synthesizedName get() = Name.identifier(this.synthesizedString)
internal val String.synthesizedString get() = "\$$this"
internal val DeclarationDescriptor.propertyIfAccessor
get() = if (this is PropertyAccessorDescriptor)
this.correspondingProperty
else this
internal val CallableMemberDescriptor.propertyIfAccessor
get() = if (this is PropertyAccessorDescriptor)
this.correspondingProperty
else this
internal val FunctionDescriptor.deserializedPropertyIfAccessor: DeserializedCallableMemberDescriptor
get() {
val member = this.propertyIfAccessor
if (member is DeserializedCallableMemberDescriptor)
return member
else
error("Unexpected deserializable callable descriptor")
}
internal val CallableMemberDescriptor.isDeserializableCallable
get () = (this.propertyIfAccessor is DeserializedCallableMemberDescriptor)

View File

@@ -5,16 +5,38 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.builtins.extractParameterNameFromFunctionTypeArgument
import org.jetbrains.kotlin.ir.backend.js.utils.*
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.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.js.backend.ast.*
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)
}
return expression.statements
.map { it.accept(this, context) }
.reduce { left, right -> JsBinaryOperation(JsBinaryOperator.COMMA, left, right) }
}
override fun visitReturn(expression: IrReturn, context: JsGenerationContext): JsExpression {
return JsBinaryOperation(JsBinaryOperator.COMMA, JsStringLiteral("<return>"), expression.value.accept(IrElementToJsExpressionTransformer(), context))
}
override fun visitTypeOperator(expression: IrTypeOperatorCall, context: JsGenerationContext): JsExpression {
return expression.argument.accept(IrElementToJsExpressionTransformer(), context)
}
override fun visitExpressionBody(body: IrExpressionBody, context: JsGenerationContext): JsExpression {
return body.expression.accept(this, context)
}
@@ -77,34 +99,21 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
val callFuncRef = JsNameRef(Namer.CALL_FUNCTION, classNameRef)
val fromPrimary = context.currentFunction is IrConstructor
val thisRef = if (fromPrimary) JsThisRef() else JsNameRef("\$this")
val arguments = translateCallArguments(expression, expression.symbol.parameterCount, context)
val arguments = translateCallArguments(expression, context)
return JsInvocation(callFuncRef, listOf(thisRef) + arguments)
}
override fun visitCall(expression: IrCall, context: JsGenerationContext): JsExpression {
// TODO rewrite more accurately, right now it just copy-pasted and adopted from old version
// TODO support:
// * ir intrinsics
// * js be intrinsics
// * js function
// * getters and setters
// * binary and unary operations
if (expression.symbol == context.staticContext.backendContext.objectCreate.symbol) {
// TODO: temporary workaround until there is no an intrinsic infrastructure
assert(expression.typeArgumentsCount == 1 && expression.valueArgumentsCount == 0)
val classToCreate = expression.getTypeArgument(0)!!
val prototype = prototypeOf(classToCreate.constructor.declarationDescriptor!!.name.toJsName().makeRef())
return JsInvocation(Namer.JS_OBJECT_CREATE_FUNCTION, prototype)
}
val symbol = expression.symbol
val dispatchReceiver = expression.dispatchReceiver?.accept(this, context)
val extensionReceiver = expression.extensionReceiver?.accept(this, context)
val arguments = translateCallArguments(expression, context)
val arguments = translateCallArguments(expression, expression.symbol.parameterCount, context)
context.staticContext.intrinsics[symbol]?.let {
return it(expression, arguments)
}
return if (symbol is IrConstructorSymbol) {
JsNew(JsNameRef((symbol.owner.parent as IrClass).name.asString()), arguments)
@@ -120,4 +129,4 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
// TODO check when w/o else branch and empty when
return expression.toJsNode(this, context, ::JsConditional)!!
}
}
}

View File

@@ -6,13 +6,22 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.ir.backend.js.utils.*
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
import org.jetbrains.kotlin.ir.backend.js.utils.constructedClass
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.js.backend.ast.*
class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsStatement, JsGenerationContext> {
// TODO: is it right place for this logic? Or should it be implemented as a separate lowering?
override fun visitTypeOperator(expression: IrTypeOperatorCall, context: JsGenerationContext): JsStatement {
if (expression.operator == IrTypeOperator.IMPLICIT_COERCION_TO_UNIT) {
return expression.argument.accept(this, context)
}
return super.visitTypeOperator(expression, context)
}
override fun visitBlockBody(body: IrBlockBody, context: JsGenerationContext): JsStatement {
return JsBlock(body.statements.map { it.accept(this, context) })
}
@@ -39,7 +48,15 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
}
override fun visitReturn(expression: IrReturn, context: JsGenerationContext): JsStatement {
return JsReturn(expression.value.accept(IrElementToJsExpressionTransformer(), context))
val returnValue = expression.value.let {
if (it is IrBlock) {
JsInvocation(JsFunction(context.currentScope, IrElementToJsStatementTransformer().visitBlock(it, context), ""))
} else {
it.accept(IrElementToJsExpressionTransformer(), context)
}
}
return JsReturn(returnValue)
}
override fun visitThrow(expression: IrThrow, context: JsGenerationContext): JsStatement {

View File

@@ -0,0 +1,87 @@
/*
* 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.transformers.irToJs
import org.jetbrains.kotlin.ir.backend.js.JsIntrinsics
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.js.backend.ast.*
typealias IrCallTransformer = (IrCall, List<JsExpression>) -> JsExpression
class JsIntrinsicTransformers(intrinsics: JsIntrinsics) {
private val transformers: Map<IrSymbol, IrCallTransformer>
init {
transformers = mutableMapOf()
transformers.apply {
binOp(intrinsics.jsEqeqeq, JsBinaryOperator.REF_EQ)
binOp(intrinsics.jsNotEqeq, JsBinaryOperator.REF_NEQ)
binOp(intrinsics.jsEqeq, JsBinaryOperator.EQ)
binOp(intrinsics.jsNotEq, JsBinaryOperator.NEQ)
binOp(intrinsics.jsGt, JsBinaryOperator.GT)
binOp(intrinsics.jsGtEq, JsBinaryOperator.GTE)
binOp(intrinsics.jsLt, JsBinaryOperator.LT)
binOp(intrinsics.jsLtEq, JsBinaryOperator.LTE)
prefixOp(intrinsics.jsNot, JsUnaryOperator.NOT)
prefixOp(intrinsics.jsUnaryPlus, JsUnaryOperator.POS)
prefixOp(intrinsics.jsUnaryMinus, JsUnaryOperator.NEG)
prefixOp(intrinsics.jsPrefixInc, JsUnaryOperator.INC)
postfixOp(intrinsics.jsPostfixInc, JsUnaryOperator.INC)
prefixOp(intrinsics.jsPrefixDec, JsUnaryOperator.DEC)
postfixOp(intrinsics.jsPostfixDec, JsUnaryOperator.DEC)
binOp(intrinsics.jsPlus, JsBinaryOperator.ADD)
binOp(intrinsics.jsMinus, JsBinaryOperator.SUB)
binOp(intrinsics.jsMult, JsBinaryOperator.MUL)
binOp(intrinsics.jsDiv, JsBinaryOperator.DIV)
binOp(intrinsics.jsMod, JsBinaryOperator.MOD)
binOp(intrinsics.jsBitAnd, JsBinaryOperator.BIT_AND)
binOp(intrinsics.jsBitOr, JsBinaryOperator.BIT_OR)
binOp(intrinsics.jsBitXor, JsBinaryOperator.BIT_XOR)
prefixOp(intrinsics.jsBitNot, JsUnaryOperator.BIT_NOT)
binOp(intrinsics.jsBitShiftR, JsBinaryOperator.SHR)
binOp(intrinsics.jsBitShiftRU, JsBinaryOperator.SHRU)
binOp(intrinsics.jsBitShiftL, JsBinaryOperator.SHL)
binOp(intrinsics.jsInstanceOf, JsBinaryOperator.INSTANCEOF)
add(intrinsics.jsObjectCreate) { call, _ ->
val classToCreate = call.getTypeArgument(0)!!
val prototype = prototypeOf(classToCreate.constructor.declarationDescriptor!!.name.toJsName().makeRef())
JsInvocation(Namer.JS_OBJECT_CREATE_FUNCTION, prototype)
}
}
}
operator fun get(symbol: IrSymbol): IrCallTransformer? = transformers[symbol]
}
private fun MutableMap<IrSymbol, IrCallTransformer>.add(function: IrFunction, t: IrCallTransformer) {
put(function.symbol, t)
}
private fun MutableMap<IrSymbol, IrCallTransformer>.binOp(function: IrFunction, op: JsBinaryOperator) {
put(function.symbol, { _, args -> JsBinaryOperation(op, args[0], args[1]) })
}
private fun MutableMap<IrSymbol, IrCallTransformer>.prefixOp(function: IrFunction, op: JsUnaryOperator) {
put(function.symbol, { _, args -> JsPrefixOperation(op, args[0]) })
}
private fun MutableMap<IrSymbol, IrCallTransformer>.postfixOp(function: IrFunction, op: JsUnaryOperator) {
put(function.symbol, { _, args -> JsPostfixOperation(op, args[0]) })
}

View File

@@ -63,15 +63,15 @@ fun translateFunction(declaration: IrFunction, name: JsName?, context: JsGenerat
return function
}
fun translateCallArguments(
expression: IrMemberAccessExpression,
parameterCount: Int,
context: JsGenerationContext
): List<JsExpression> {
fun translateCallArguments(expression: IrMemberAccessExpression, context: JsGenerationContext): List<JsExpression> {
val transformer = IrElementToJsExpressionTransformer()
// TODO: map to?
return (0 until parameterCount).map {
val argument = expression.getValueArgument(it)
argument?.accept(transformer, context) ?: JsPrefixOperation(JsUnaryOperator.VOID, JsIntLiteral(1))
val result = ArrayList<JsExpression>(expression.valueArgumentsCount)
for (i in 0 until expression.valueArgumentsCount) {
val argument = expression.getValueArgument(i)
result += argument?.accept(transformer, context) ?: JsPrefixOperation(JsUnaryOperator.VOID, JsIntLiteral(1))
}
return result
}

View File

@@ -5,10 +5,12 @@
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.JsIntrinsicTransformers
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.js.backend.ast.*
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
@@ -18,6 +20,7 @@ class JsStaticContext(
private val nameGenerator: NameGenerator,
val backendContext: JsIrBackendContext
) {
val intrinsics = JsIntrinsicTransformers(backendContext.intrinsics)
fun getNameForSymbol(irSymbol: IrSymbol) = nameGenerator.getNameForSymbol(irSymbol, rootScope)
fun getSpecialRefForName(name: Name): JsExpression = nameGenerator.getSpecialRefForName(name)

View File

@@ -8,8 +8,6 @@ package org.jetbrains.kotlin.ir.backend.js.utils
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.ir.symbols.*
val IrFunctionSymbol.parameterCount get() = descriptor.valueParameters.size
val IrFunctionSymbol.kind get() = descriptor.kind
val IrFunctionSymbol.modality get() = descriptor.modality

View File

@@ -8,29 +8,144 @@ package org.jetbrains.kotlin.test
import java.io.File
val JS_IR_BACKEND_TEST_WHITELIST = listOf(
"js/js.translator/testData/box/package/nestedPackage.kt",
"js/js.translator/testData/box/examples/funDelegation.kt",
"js/js.translator/testData/box/examples/incrementProperty.kt",
"js/js.translator/testData/box/examples/inheritedMethod.kt",
"js/js.translator/testData/box/examples/initializerBlock.kt",
"js/js.translator/testData/box/examples/kt242.kt",
"js/js.translator/testData/box/examples/newInstanceDefaultConstructor.kt",
"js/js.translator/testData/box/examples/propertyDelegation.kt",
"js/js.translator/testData/box/examples/rightHandOverride.kt",
"js/js.translator/testData/box/expression/equals/stringsEqual.kt",
"js/js.translator/testData/box/expression/evaluationOrder/ifAsPlusArgument.kt",
"js/js.translator/testData/box/expression/evaluationOrder/secondaryConstructorTemporaryVars.kt",
"js/js.translator/testData/box/expression/identifierClash/overloadedFun.kt",
"js/js.translator/testData/box/expression/identifierClash/useVariableOfNameOfFunction.kt",
"js/js.translator/testData/box/expression/identityEquals/identityEqualsMethod.kt",
"js/js.translator/testData/box/expression/invoke/internalFunctionFromSuperclass.kt",
"js/js.translator/testData/box/expression/invoke/invokeWithDispatchReceiver.kt",
"js/js.translator/testData/box/expression/misc/classWithoutPackage.kt",
"js/js.translator/testData/box/expression/misc/KT-740-3.kt",
"js/js.translator/testData/box/expression/misc/localProperty.kt",
"js/js.translator/testData/box/expression/misc/propertiesWithExplicitlyDefinedAccessorsWithoutBodies.kt",
"js/js.translator/testData/box/expression/stringClass/kt2227_2.kt",
"js/js.translator/testData/box/expression/stringClass/kt2227.kt",
"js/js.translator/testData/box/expression/stringClass/objectToStringCallInTemplate.kt",
"js/js.translator/testData/box/expression/stringClass/stringAssignment.kt",
"js/js.translator/testData/box/expression/stringClass/stringConstant.kt",
"js/js.translator/testData/box/expression/stringTemplates/nonStrings.kt",
"js/js.translator/testData/box/expression/when/doWhileWithOneStmWhen.kt",
"js/js.translator/testData/box/expression/when/empty.kt",
"js/js.translator/testData/box/expression/when/ifWithOneStmWhen.kt",
"js/js.translator/testData/box/expression/when/kt1665.kt",
"js/js.translator/testData/box/expression/when/whenValue.kt",
"js/js.translator/testData/box/expression/when/whenWithOneStmWhen.kt",
"js/js.translator/testData/box/expression/when/whenWithOnlyElse.kt",
"js/js.translator/testData/box/expression/when/whenWithoutExpression.kt",
"js/js.translator/testData/box/extensionFunction/extensionFunctionCalledFromExtensionFunction.kt",
"js/js.translator/testData/box/extensionProperty/inClass.kt",
"js/js.translator/testData/box/inheritance/abstractVarOverride.kt",
"js/js.translator/testData/box/inheritance/baseCall.kt",
"js/js.translator/testData/box/inheritance/initializersOfBasicClassExecute.kt",
"js/js.translator/testData/box/inheritance/methodOverride.kt",
"js/js.translator/testData/box/inheritance/valOverride.kt",
"js/js.translator/testData/box/inheritance/valuePassedToAncestorConstructor.kt",
"js/js.translator/testData/box/inheritance/withInitializeMethod.kt",
"js/js.translator/testData/box/initialize/rootPackageValInit.kt",
"js/js.translator/testData/box/initialize/rootValInit.kt",
"js/js.translator/testData/box/inline/sameNameOfDeclarationsInSameModule.kt",
"js/js.translator/testData/box/multideclaration/multiValOrVar.kt",
"js/js.translator/testData/box/multiFile/functionsVisibleFromOtherFile.kt",
"js/js.translator/testData/box/multiPackage/createClassFromOtherPackage.kt",
"js/js.translator/testData/box/multiPackage/createClassFromOtherPackageUsingImport.kt",
"js/js.translator/testData/box/multiPackage/functionsVisibleFromOtherPackage.kt",
"js/js.translator/testData/box/multiPackage/nestedPackageFunctionCalledFromOtherPackage.kt",
"js/js.translator/testData/box/multiPackage/subpackagesWithClashingNames.kt",
"js/js.translator/testData/box/multiPackage/subpackagesWithClashingNamesUsingImport.kt",
"js/js.translator/testData/box/nameClashes/differenceInCapitalization.kt",
"js/js.translator/testData/box/nameClashes/methodOverload.kt",
"js/js.translator/testData/box/operatorOverloading/binaryDivOverload.kt",
"js/js.translator/testData/box/operatorOverloading/compareTo.kt",
"js/js.translator/testData/box/operatorOverloading/compareToByName.kt",
"js/js.translator/testData/box/operatorOverloading/notOverload.kt",
"js/js.translator/testData/box/operatorOverloading/plusOverload.kt",
"js/js.translator/testData/box/operatorOverloading/postfixInc.kt",
"js/js.translator/testData/box/operatorOverloading/prefixDecOverload.kt",
"js/js.translator/testData/box/operatorOverloading/prefixIncReturnsCorrectValue.kt",
"js/js.translator/testData/box/operatorOverloading/unaryOnIntPropertyAsStatement.kt",
"js/js.translator/testData/box/operatorOverloading/usingModInCaseModAssignNotAvailable.kt",
"js/js.translator/testData/box/package/classCreatedInDeeplyNestedPackage.kt",
"js/js.translator/testData/box/package/deeplyNestedPackage.kt",
"js/js.translator/testData/box/package/deeplyNestedPackageFunctionCalled.kt",
"js/js.translator/testData/box/multiPackage/nestedPackageFunctionCalledFromOtherPackage.kt",
"js/js.translator/testData/box/expression/identifierClash/useVariableOfNameOfFunction.kt",
"js/js.translator/testData/box/expression/stringClass/stringConstant.kt",
"js/js.translator/testData/box/expression/when/empty.kt",
"js/js.translator/testData/box/package/initializersOfNestedPackagesExecute.kt",
"js/js.translator/testData/box/package/nestedPackage.kt",
"js/js.translator/testData/box/propertyAccess/accessToInstanceProperty.kt",
"js/js.translator/testData/box/propertyAccess/customGetter.kt",
"js/js.translator/testData/box/propertyAccess/customSetter.kt",
"js/js.translator/testData/box/propertyAccess/field.kt",
"js/js.translator/testData/box/propertyAccess/initInstanceProperties.kt",
"js/js.translator/testData/box/propertyAccess/initValInConstructor.kt",
"js/js.translator/testData/box/propertyAccess/packageCustomAccessors.kt",
"js/js.translator/testData/box/propertyAccess/packagePropertyInitializer.kt",
"js/js.translator/testData/box/propertyAccess/packagePropertySet.kt",
"js/js.translator/testData/box/propertyAccess/twoClassesWithProperties.kt",
"js/js.translator/testData/box/propertyOverride/overrideExtensionProperty.kt",
"js/js.translator/testData/box/safeCall/safeCall.kt",
"js/js.translator/testData/box/simple/assign.kt",
"js/js.translator/testData/box/simple/breakDoWhile.kt",
"js/js.translator/testData/box/simple/breakWhile.kt",
"js/js.translator/testData/box/simple/classInstantiation.kt",
"js/js.translator/testData/box/simple/comparison.kt",
"js/js.translator/testData/box/simple/complexExpressionAsConstructorParameter.kt",
"js/js.translator/testData/box/simple/constructorWithParameter.kt",
"js/js.translator/testData/box/simple/constructorWithPropertiesAsParameters.kt",
"js/js.translator/testData/box/simple/continueDoWhile.kt",
"js/js.translator/testData/box/simple/continueWhile.kt",
"js/js.translator/testData/box/simple/doWhile.kt",
"js/js.translator/testData/box/simple/doWhile2.kt",
"js/js.translator/testData/box/simple/elseif.kt",
"js/js.translator/testData/box/simple/if.kt",
"js/js.translator/testData/box/simple/ifElseAsExpression.kt",
"js/js.translator/testData/box/simple/methodDeclarationAndCall.kt",
"js/js.translator/testData/box/simple/minusAssignOnProperty.kt",
"js/js.translator/testData/box/simple/notBoolean.kt",
"js/js.translator/testData/box/simple/plusAssign.kt",
"js/js.translator/testData/box/simple/positiveAndNegativeNumbers.kt",
"js/js.translator/testData/box/simple/prefixIntOperations.kt",
"js/js.translator/testData/box/simple/primCtorDelegation1.kt",
"js/js.translator/testData/box/simple/propertiesAsParametersInitialized.kt",
"js/js.translator/testData/box/simple/propertyAccess.kt",
"js/js.translator/testData/box/simple/secCtorDelegation1.kt",
"js/js.translator/testData/box/simple/secCtorDelegation2.kt",
"js/js.translator/testData/box/simple/secCtorDelegation3.kt",
"js/js.translator/testData/box/simple/secCtorDelegation4.kt",
"js/js.translator/testData/box/operatorOverloading/notOverload.kt",
"js/js.translator/testData/box/operatorOverloading/binaryDivOverload.kt",
"js/js.translator/testData/box/package/initializersOfNestedPackagesExecute.kt",
"js/js.translator/testData/box/package/classCreatedInDeeplyNestedPackage.kt",
"js/js.translator/testData/box/extensionProperty/inClass.kt",
"js/js.translator/testData/box/multiPackage/createClassFromOtherPackage.kt",
"js/js.translator/testData/box/multiPackage/createClassFromOtherPackageUsingImport.kt",
"js/js.translator/testData/box/simple/methodDeclarationAndCall.kt",
"js/js.translator/testData/box/simple/propertyAccess.kt",
"js/js.translator/testData/box/simple/classInstantiation.kt",
"js/js.translator/testData/box/expression/invoke/internalFunctionFromSuperclass.kt",
"js/js.translator/testData/box/inheritance/withInitializeMethod.kt"
"js/js.translator/testData/box/simple/simpleInitializer.kt",
"js/js.translator/testData/box/simple/while.kt",
"js/js.translator/testData/box/simple/while2.kt",
"js/js.translator/testData/box/trait/funDelegation.kt"
).map { File(it) }

View File

@@ -1,4 +1,10 @@
// EXPECTED_REACHABLE_NODES: 1108
package foo.bar
fun box() = "OK"
inline fun <T> run(block: () -> T) = block()
fun box(): String {
return run {
"OK"
}
}