[IR BE] Support lateinit locals and isInitialized property
* update tests
This commit is contained in:
@@ -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")) }
|
||||
|
||||
+53
-11
@@ -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")) }
|
||||
}
|
||||
|
||||
|
||||
-2
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// WITH_RUNTIME
|
||||
|
||||
package test
|
||||
|
||||
Vendored
-2
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// LANGUAGE_VERSION: 1.2
|
||||
// WITH_RUNTIME
|
||||
|
||||
|
||||
-2
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// WITH_RUNTIME
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
|
||||
Vendored
-1
@@ -1,5 +1,4 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// LANGUAGE_VERSION: 1.2
|
||||
// WITH_RUNTIME
|
||||
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
// LANGUAGE_VERSION: 1.2
|
||||
// WITH_RUNTIME
|
||||
|
||||
Vendored
-2
@@ -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 {
|
||||
|
||||
Vendored
-2
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// LANGUAGE_VERSION: 1.2
|
||||
// WITH_RUNTIME
|
||||
|
||||
|
||||
-2
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// LANGUAGE_VERSION: 1.2
|
||||
// WITH_RUNTIME
|
||||
|
||||
|
||||
-2
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user