Generate parameter name in assertion for lateinit properties

This commit is contained in:
Mikhael Bogdanov
2018-01-10 16:11:59 +01:00
parent e58558dffd
commit 28f4cc5b18
2 changed files with 34 additions and 12 deletions
@@ -18,24 +18,28 @@ package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrProperty import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.expressions.IrBlock import org.jetbrains.kotlin.ir.expressions.IrBlock
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl 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.expressions.impl.IrExpressionBodyImpl
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
class LateinitLowering(val context: CommonBackendContext): FileLoweringPass { class LateinitLowering(
val context: CommonBackendContext,
private val generateParameterNameInAssertion: Boolean = false
) : FileLoweringPass {
override fun lower(irFile: IrFile) { override fun lower(irFile: IrFile) {
irFile.transformChildrenVoid(object: IrElementTransformerVoid() { irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitProperty(declaration: IrProperty): IrStatement { override fun visitProperty(declaration: IrProperty): IrStatement {
if (declaration.descriptor.isLateInit && declaration.descriptor.kind.isReal) if (declaration.descriptor.isLateInit && declaration.descriptor.kind.isReal)
transformGetter(declaration.backingField!!.symbol, declaration.getter!!) transformGetter(declaration.backingField!!.symbol, declaration.getter!!)
@@ -44,20 +48,22 @@ class LateinitLowering(val context: CommonBackendContext): FileLoweringPass {
private fun transformGetter(backingFieldSymbol: IrFieldSymbol, getter: IrFunction) { private fun transformGetter(backingFieldSymbol: IrFieldSymbol, getter: IrFunction) {
val type = backingFieldSymbol.descriptor.type val type = backingFieldSymbol.descriptor.type
assert (!KotlinBuiltIns.isPrimitiveType(type), { "'lateinit' modifier is not allowed on primitive types" }) assert(!KotlinBuiltIns.isPrimitiveType(type), { "'lateinit' modifier is not allowed on primitive types" })
val startOffset = getter.startOffset val startOffset = getter.startOffset
val endOffset = getter.endOffset val endOffset = getter.endOffset
val irBuilder = context.createIrBuilder(getter.symbol, startOffset, endOffset) val irBuilder = context.createIrBuilder(getter.symbol, startOffset, endOffset)
irBuilder.run { irBuilder.run {
val block = irBlock(type) val block = irBlock(type)
val resultVar = scope.createTemporaryVariable( val resultVar = scope.createTemporaryVariable(
irGetField(getter.dispatchReceiverParameter?.let { irGet(it.symbol) }, backingFieldSymbol) irGetField(getter.dispatchReceiverParameter?.let { irGet(it.symbol) }, backingFieldSymbol)
) )
block.statements.add(resultVar) block.statements.add(resultVar)
val throwIfNull = irIfThenElse(context.builtIns.nothingType, val throwIfNull = irIfThenElse(
irNotEquals(irGet(resultVar.symbol), irNull()), context.builtIns.nothingType,
irReturn(irGet(resultVar.symbol)), irNotEquals(irGet(resultVar.symbol), irNull()),
irCall(throwErrorFunction)) irReturn(irGet(resultVar.symbol)),
throwUninitializedPropertyAccessException(backingFieldSymbol)
)
block.statements.add(throwIfNull) block.statements.add(throwIfNull)
getter.body = IrExpressionBodyImpl(startOffset, endOffset, block) getter.body = IrExpressionBodyImpl(startOffset, endOffset, block)
} }
@@ -65,9 +71,23 @@ class LateinitLowering(val context: CommonBackendContext): FileLoweringPass {
}) })
} }
private fun IrBuilderWithScope.throwUninitializedPropertyAccessException(backingFieldSymbol: IrFieldSymbol) =
irCall(throwErrorFunction).apply {
if (generateParameterNameInAssertion) {
putValueArgument(
0,
IrConstImpl.string(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
context.builtIns.stringType,
backingFieldSymbol.descriptor.name.asString()
)
)
}
}
private val throwErrorFunction = context.ir.symbols.ThrowUninitializedPropertyAccessException private val throwErrorFunction = context.ir.symbols.ThrowUninitializedPropertyAccessException
private fun IrBuilderWithScope.irBlock(type: KotlinType): IrBlock private fun IrBuilderWithScope.irBlock(type: KotlinType): IrBlock = IrBlockImpl(startOffset, endOffset, type)
= IrBlockImpl(startOffset, endOffset, type)
} }
@@ -28,7 +28,9 @@ class JvmLower(val context: JvmBackendContext) {
// TODO run lowering passes as callbacks in bottom-up visitor // TODO run lowering passes as callbacks in bottom-up visitor
FileClassLowering(context).lower(irFile) FileClassLowering(context).lower(irFile)
KCallableNamePropertyLowering(context).lower(irFile) KCallableNamePropertyLowering(context).lower(irFile)
LateinitLowering(context).lower(irFile)
LateinitLowering(context, true).lower(irFile)
ConstAndJvmFieldPropertiesLowering().lower(irFile) ConstAndJvmFieldPropertiesLowering().lower(irFile)
PropertiesLowering().lower(irFile) PropertiesLowering().lower(irFile)