[IR BE] Support lateinit locals and isInitialized property

* update tests
This commit is contained in:
Roman Artemev
2018-10-29 22:09:32 +03:00
committed by romanart
parent 535eea7f48
commit 2d03f87ea5
16 changed files with 72 additions and 32 deletions
@@ -4,7 +4,6 @@ import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.declarations.IrFunction
@@ -169,6 +168,8 @@ abstract class Symbols<out T : CommonBackendContext>(val context: T, private val
abstract val coroutineSuspendedGetter: IrSimpleFunctionSymbol
abstract val lateinitIsInitializedPropertyGetter: IrSimpleFunctionSymbol
fun getFunction(parameterCount: Int) = symbolTable.referenceClass(context.builtIns.getFunction(parameterCount))
val functionReference = calc { symbolTable.referenceClass(context.getInternalClass("FunctionReference")) }
@@ -22,13 +22,14 @@ import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrBlock
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetValue
import org.jetbrains.kotlin.ir.expressions.IrPropertyReference
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.isPrimitiveType
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
@@ -39,11 +40,55 @@ class LateinitLowering(
override fun lower(irFile: IrFile) {
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitProperty(declaration: IrProperty): IrStatement {
if (declaration.isLateinit && declaration.origin != IrDeclarationOrigin.FAKE_OVERRIDE)
declaration.transformChildrenVoid(this)
if (declaration.isLateinit && declaration.origin != IrDeclarationOrigin.FAKE_OVERRIDE) {
transformGetter(declaration.backingField!!, declaration.getter!!)
}
return declaration
}
override fun visitVariable(declaration: IrVariable): IrStatement {
declaration.transformChildrenVoid(this)
if (!declaration.isLateinit) return declaration
declaration.run { initializer = IrConstImpl.constNull(startOffset, endOffset, type) }
return declaration
}
override fun visitGetValue(expression: IrGetValue): IrExpression {
val irVar = expression.symbol.owner as? IrVariable ?: return expression
if (!irVar.isLateinit) return expression
val parent = irVar.parent as IrSymbolOwner
val irBuilder = context.createIrBuilder(parent.symbol, expression.startOffset, expression.endOffset)
return irBuilder.run {
irIfThenElse(
expression.type, irEqualsNull(irGet(irVar)),
throwUninitializedPropertyAccessException(irVar.name.asString()),
irGet(irVar)
)
}
}
override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this)
if (expression.symbol != context.ir.symbols.lateinitIsInitializedPropertyGetter) return expression
val receiver = expression.extensionReceiver as IrPropertyReference
val property = receiver.getter?.owner?.resolveFakeOverride()?.correspondingProperty!!.also { assert(it.isLateinit) }
return expression.run { context.createIrBuilder(symbol, startOffset, endOffset) }.run {
irNotEquals(irGetField(receiver.dispatchReceiver, property.backingField!!), irNull())
}
}
private fun transformGetter(backingField: IrField, getter: IrFunction) {
val type = backingField.type
assert(!type.isPrimitiveType()) { "'lateinit' modifier is not allowed on primitive types" }
@@ -60,7 +105,7 @@ class LateinitLowering(
context.irBuiltIns.nothingType,
irNotEquals(irGet(resultVar), irNull()),
irReturn(irGet(resultVar)),
throwUninitializedPropertyAccessException(backingField)
throwUninitializedPropertyAccessException(backingField.name.asString())
)
body.statements.add(throwIfNull)
getter.body = body
@@ -69,7 +114,7 @@ class LateinitLowering(
})
}
private fun IrBuilderWithScope.throwUninitializedPropertyAccessException(backingField: IrField) =
private fun IrBuilderWithScope.throwUninitializedPropertyAccessException(name: String) =
irCall(throwErrorFunction).apply {
if (generateParameterNameInAssertion) {
putValueArgument(
@@ -78,14 +123,11 @@ class LateinitLowering(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
context.irBuiltIns.stringType,
backingField.name.asString()
name
)
)
}
}
private val throwErrorFunction = context.ir.symbols.ThrowUninitializedPropertyAccessException.owner
private fun IrBuilderWithScope.irBlock(type: IrType): IrBlock = IrBlockImpl(startOffset, endOffset, type)
}
@@ -206,6 +206,14 @@ class JsIrBackendContext(
NoLookupLocation.FROM_BACKEND
).filterNot { it.isExpect }.single().getter!!
)
override val lateinitIsInitializedPropertyGetter = symbolTable.referenceSimpleFunction(
module.getPackage(kotlinPackageFqn).memberScope.getContributedVariables(
Name.identifier("isInitialized"), NoLookupLocation.FROM_BACKEND
).single {
it.extensionReceiverParameter != null && !it.isExternal
}.getter!!
)
}
override fun shouldGenerateHandlerParameterForDefaultBodyFun() = true
@@ -77,6 +77,7 @@ fun compile(
ExpectDeclarationsRemoving(context).lower(moduleFragment)
CoroutineIntrinsicLowering(context).lower(moduleFragment)
ArrayInlineConstructorLowering(context).lower(moduleFragment)
LateinitLowering(context, true).lower(moduleFragment)
val moduleFragmentCopy = moduleFragment.deepCopyWithSymbols()
@@ -124,6 +124,14 @@ class JvmBackendContext(
override val coroutineSuspendedGetter: IrSimpleFunctionSymbol
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
override val lateinitIsInitializedPropertyGetter= symbolTable.referenceSimpleFunction(
state.module.getPackage(FqName("kotlin")).memberScope.getContributedVariables(
Name.identifier("isInitialized"), NoLookupLocation.FROM_BACKEND
).single {
it.extensionReceiverParameter != null && !it.isExternal
}.getter!!
)
val lambdaClass = calc { symbolTable.referenceClass(context.getInternalClass("Lambda")) }
}
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
package test
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
// LANGUAGE_VERSION: 1.2
// WITH_RUNTIME
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
// IGNORE_BACKEND: JS
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
// LANGUAGE_VERSION: 1.2
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// LANGUAGE_VERSION: 1.2
// WITH_RUNTIME
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
// LANGUAGE_VERSION: 1.2
// WITH_RUNTIME
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
fun box(): String {
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
// LANGUAGE_VERSION: 1.2
// WITH_RUNTIME
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
// LANGUAGE_VERSION: 1.2
// WITH_RUNTIME
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
// LANGUAGE_VERSION: 1.2
// WITH_RUNTIME
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
// LANGUAGE_VERSION: 1.2
// WITH_RUNTIME