[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.PrimitiveType
|
||||||
import org.jetbrains.kotlin.builtins.UnsignedType
|
import org.jetbrains.kotlin.builtins.UnsignedType
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
|
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
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 coroutineSuspendedGetter: IrSimpleFunctionSymbol
|
||||||
|
|
||||||
|
abstract val lateinitIsInitializedPropertyGetter: IrSimpleFunctionSymbol
|
||||||
|
|
||||||
fun getFunction(parameterCount: Int) = symbolTable.referenceClass(context.builtIns.getFunction(parameterCount))
|
fun getFunction(parameterCount: Int) = symbolTable.referenceClass(context.builtIns.getFunction(parameterCount))
|
||||||
|
|
||||||
val functionReference = calc { symbolTable.referenceClass(context.getInternalClass("FunctionReference")) }
|
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.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
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.IrBlockBodyImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
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.types.isPrimitiveType
|
||||||
|
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
|
||||||
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
|
||||||
|
|
||||||
@@ -39,11 +40,55 @@ class LateinitLowering(
|
|||||||
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.isLateinit && declaration.origin != IrDeclarationOrigin.FAKE_OVERRIDE)
|
declaration.transformChildrenVoid(this)
|
||||||
|
if (declaration.isLateinit && declaration.origin != IrDeclarationOrigin.FAKE_OVERRIDE) {
|
||||||
transformGetter(declaration.backingField!!, declaration.getter!!)
|
transformGetter(declaration.backingField!!, declaration.getter!!)
|
||||||
|
}
|
||||||
return declaration
|
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) {
|
private fun transformGetter(backingField: IrField, getter: IrFunction) {
|
||||||
val type = backingField.type
|
val type = backingField.type
|
||||||
assert(!type.isPrimitiveType()) { "'lateinit' modifier is not allowed on primitive types" }
|
assert(!type.isPrimitiveType()) { "'lateinit' modifier is not allowed on primitive types" }
|
||||||
@@ -60,7 +105,7 @@ class LateinitLowering(
|
|||||||
context.irBuiltIns.nothingType,
|
context.irBuiltIns.nothingType,
|
||||||
irNotEquals(irGet(resultVar), irNull()),
|
irNotEquals(irGet(resultVar), irNull()),
|
||||||
irReturn(irGet(resultVar)),
|
irReturn(irGet(resultVar)),
|
||||||
throwUninitializedPropertyAccessException(backingField)
|
throwUninitializedPropertyAccessException(backingField.name.asString())
|
||||||
)
|
)
|
||||||
body.statements.add(throwIfNull)
|
body.statements.add(throwIfNull)
|
||||||
getter.body = body
|
getter.body = body
|
||||||
@@ -69,7 +114,7 @@ class LateinitLowering(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrBuilderWithScope.throwUninitializedPropertyAccessException(backingField: IrField) =
|
private fun IrBuilderWithScope.throwUninitializedPropertyAccessException(name: String) =
|
||||||
irCall(throwErrorFunction).apply {
|
irCall(throwErrorFunction).apply {
|
||||||
if (generateParameterNameInAssertion) {
|
if (generateParameterNameInAssertion) {
|
||||||
putValueArgument(
|
putValueArgument(
|
||||||
@@ -78,14 +123,11 @@ class LateinitLowering(
|
|||||||
UNDEFINED_OFFSET,
|
UNDEFINED_OFFSET,
|
||||||
UNDEFINED_OFFSET,
|
UNDEFINED_OFFSET,
|
||||||
context.irBuiltIns.stringType,
|
context.irBuiltIns.stringType,
|
||||||
backingField.name.asString()
|
name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val throwErrorFunction = context.ir.symbols.ThrowUninitializedPropertyAccessException.owner
|
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
|
NoLookupLocation.FROM_BACKEND
|
||||||
).filterNot { it.isExpect }.single().getter!!
|
).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
|
override fun shouldGenerateHandlerParameterForDefaultBodyFun() = true
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ fun compile(
|
|||||||
ExpectDeclarationsRemoving(context).lower(moduleFragment)
|
ExpectDeclarationsRemoving(context).lower(moduleFragment)
|
||||||
CoroutineIntrinsicLowering(context).lower(moduleFragment)
|
CoroutineIntrinsicLowering(context).lower(moduleFragment)
|
||||||
ArrayInlineConstructorLowering(context).lower(moduleFragment)
|
ArrayInlineConstructorLowering(context).lower(moduleFragment)
|
||||||
|
LateinitLowering(context, true).lower(moduleFragment)
|
||||||
|
|
||||||
val moduleFragmentCopy = moduleFragment.deepCopyWithSymbols()
|
val moduleFragmentCopy = moduleFragment.deepCopyWithSymbols()
|
||||||
|
|
||||||
|
|||||||
@@ -124,6 +124,14 @@ class JvmBackendContext(
|
|||||||
override val coroutineSuspendedGetter: IrSimpleFunctionSymbol
|
override val coroutineSuspendedGetter: IrSimpleFunctionSymbol
|
||||||
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
|
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")) }
|
val lambdaClass = calc { symbolTable.referenceClass(context.getInternalClass("Lambda")) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-2
@@ -1,5 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|||||||
Vendored
-2
@@ -1,5 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
|||||||
-2
@@ -1,5 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IGNORE_BACKEND: JS
|
// IGNORE_BACKEND: JS
|
||||||
|
|
||||||
|
|||||||
Vendored
-1
@@ -1,5 +1,4 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
// IGNORE_BACKEND: JVM_IR
|
||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|||||||
Vendored
-2
@@ -1,5 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
|
|||||||
Vendored
-2
@@ -1,5 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
|||||||
-2
@@ -1,5 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
|||||||
-2
@@ -1,5 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user