[JS IR BE] Support local delegated properties

This commit is contained in:
Svyatoslav Kuzmich
2018-08-13 17:02:22 +03:00
parent 392ad521fd
commit ff70b837ee
38 changed files with 89 additions and 40 deletions
@@ -8,14 +8,11 @@ package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.utils.addIfNotNull
import java.util.*
@@ -48,3 +45,25 @@ class PropertiesLowering : IrElementTransformerVoid(), FileLoweringPass {
else
null
}
class LocalDelegatedPropertiesLowering : IrElementTransformerVoid(), FileLoweringPass {
override fun lower(irFile: IrFile) {
irFile.accept(this, null)
}
override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty): IrStatement {
declaration.transformChildrenVoid(this)
val initializer = declaration.delegate.initializer!!
declaration.delegate.initializer = IrBlockImpl(
initializer.startOffset, initializer.endOffset, initializer.type, null,
listOfNotNull(
declaration.getter,
declaration.setter,
initializer
)
)
return declaration.delegate
}
}
@@ -97,6 +97,7 @@ private fun JsIrBackendContext.lower(moduleFragment: IrModuleFragment) {
moduleFragment.files.forEach(EnumClassLowering(this)::runOnFilePostfix)
moduleFragment.files.forEach(EnumUsageLowering(this)::lower)
moduleFragment.files.forEach(ReturnableBlockLowering(this)::lower)
moduleFragment.files.forEach(LocalDelegatedPropertiesLowering()::lower)
moduleFragment.files.forEach(LocalDeclarationsLowering(this)::runOnFilePostfix)
moduleFragment.files.forEach(InnerClassesLowering(this)::runOnFilePostfix)
moduleFragment.files.forEach(InnerClassConstructorCallsLowering(this)::runOnFilePostfix)
@@ -82,6 +82,10 @@ class CallableReferenceLowering(val context: JsIrBackendContext) {
collectedReferenceMap[makeCallableKey(expression.getter!!.owner, expression)] = expression
}
override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference) {
collectedReferenceMap[makeCallableKey(expression.getter!!.owner, expression)] = expression
}
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
@@ -111,6 +115,11 @@ class CallableReferenceLowering(val context: JsIrBackendContext) {
expression.getter!!.owner,
expression
) else emptyList()
override fun visitLocalDelegatedPropertyReference(
expression: IrLocalDelegatedPropertyReference,
data: Nothing?
) = lowerLocalKPropertyReference(expression)
}, null)
}
}
@@ -128,6 +137,12 @@ class CallableReferenceLowering(val context: JsIrBackendContext) {
} ?: expression
}
override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference): IrExpression {
return callableToGetterFunction[makeCallableKey(expression.getter!!.owner, expression)]!!.let {
redirectToFunction(expression, it)
}
}
private fun redirectToFunction(callable: IrCallableReference, newTarget: IrFunction) =
IrCallImpl(
callable.startOffset, callable.endOffset,
@@ -278,6 +293,55 @@ class CallableReferenceLowering(val context: JsIrBackendContext) {
return additionalDeclarations + listOf(refGetFunction)
}
private fun lowerLocalKPropertyReference(propertyReference: IrLocalDelegatedPropertyReference): List<IrDeclaration> {
// transform
// ::bar ->
// Foo_bar_KreferenceGet() : KPropertyN<Foo, PType> {
// if ($cache$ == null) {
// val x = fun Foo_bar_KreferenceClosure_get(): PType {
// throw IllegalStateException()
// }
// x.get = x
// x.callableName = "bar"
// $cache$ = x
// }
// return $cache$
// }
val getterName = createPropertyClosureGetterName(propertyReference.descriptor)
val refGetFunction = buildGetFunction(propertyReference.getter.owner, propertyReference, getterName)
val getterFunction = buildClosureFunction(context.irBuiltIns.throwIseFun, refGetFunction, propertyReference)
val additionalDeclarations = generateGetterBodyWithGuard(refGetFunction) {
val statements = mutableListOf<IrStatement>()
val getterFunctionType = context.builtIns.getFunction(getterFunction.valueParameters.size + 1)
val type = getterFunctionType.toIrType()
val irGetReference = JsIrBuilder.buildFunctionReference(type, getterFunction.symbol)
val irVarSymbol = JsSymbolBuilder.buildTempVar(refGetFunction.symbol, type)
statements += JsIrBuilder.buildVar(irVarSymbol, irGetReference, type = type)
statements += JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply {
putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol))
putValueArgument(1, getterConst)
putValueArgument(2, JsIrBuilder.buildGetValue(irVarSymbol))
}
statements += JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply {
putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol))
putValueArgument(1, callableNameConst)
putValueArgument(2, JsIrBuilder.buildString(context.irBuiltIns.stringType, getReferenceName(propertyReference.descriptor)))
}
Pair(statements, irVarSymbol)
}
callableToGetterFunction[makeCallableKey(propertyReference.getter.owner, propertyReference)] = refGetFunction
return additionalDeclarations + listOf(refGetFunction)
}
private fun generateGetterBodyWithGuard(
getterFunction: IrSimpleFunction,
builder: () -> Pair<List<IrStatement>, IrValueSymbol>
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: NATIVE
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: NATIVE
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: NATIVE
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
package foo
import kotlin.reflect.KProperty
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
package foo
import kotlin.reflect.KProperty
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
package foo
import kotlin.reflect.KProperty
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
package foo
import kotlin.reflect.KProperty
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
package foo
import kotlin.reflect.KProperty
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
package foo
import kotlin.reflect.KProperty
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
object Whatever {
operator fun getValue(thisRef: Any?, prop: Any?) = "OK"
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
package foo
import kotlin.reflect.KProperty
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
package foo
import kotlin.reflect.KProperty
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
package foo
import kotlin.reflect.KProperty
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
package foo
import kotlin.reflect.KProperty
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
import kotlin.test.*
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
import kotlin.test.*
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
import kotlin.test.*
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
// Enable when KT-14833 is fixed.
// IGNORE_BACKEND: JVM
import kotlin.reflect.KProperty
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
import kotlin.test.assertEquals
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
import kotlin.test.assertEquals
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
import kotlin.test.assertEquals
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
import kotlin.test.assertEquals
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
import kotlin.test.assertEquals
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1114
//TODO: reuse same tests from JVM backend
package foo
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1116
//TODO: reuse same tests from JVM backend
package foo
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1115
//TODO: reuse same tests from JVM backend
package foo
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1118
//TODO: reuse same tests from JVM backend
package foo
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1114
//TODO: reuse same tests from JVM backend
package foo
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1115
//TODO: reuse same tests from JVM backend
package foo
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1115
//TODO: reuse same tests from JVM backend
package foo
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1115
//TODO: reuse same tests from JVM backend
package foo
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1131
// PROPERTY_NOT_USED: PropertyMetadata
import kotlin.reflect.KProperty