diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt index be72c1604b7..75ebbc5b542 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt @@ -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(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")) } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LateinitLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LateinitLowering.kt index 38254229985..bdc555de91c 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LateinitLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LateinitLowering.kt @@ -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) - } \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt index 226899b5669..d87ccc6ed00 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt @@ -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 diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt index 7ec46e1dbed..abe3f19b91e 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt @@ -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() diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt index 0bafb07868b..6b17cbbdb96 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt @@ -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")) } } diff --git a/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/emptyLhs.kt b/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/emptyLhs.kt index 0be19e3b022..4e5c78fdc56 100644 --- a/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/emptyLhs.kt +++ b/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/emptyLhs.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND: JS_IR // WITH_RUNTIME package test diff --git a/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/innerSubclass.kt b/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/innerSubclass.kt index 92a1a49cc00..ae96f730eab 100644 --- a/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/innerSubclass.kt +++ b/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/innerSubclass.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND: JS_IR // LANGUAGE_VERSION: 1.2 // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/propertyImportedFromObject.kt b/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/propertyImportedFromObject.kt index 8212b647fed..a61d790b09a 100644 --- a/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/propertyImportedFromObject.kt +++ b/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/propertyImportedFromObject.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND: JS_IR // WITH_RUNTIME // IGNORE_BACKEND: JS diff --git a/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/sideEffects.kt b/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/sideEffects.kt index 2f3d45f2443..9d26681fc3b 100644 --- a/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/sideEffects.kt +++ b/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/sideEffects.kt @@ -1,5 +1,4 @@ // IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND: JS_IR // LANGUAGE_VERSION: 1.2 // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/simpleIsInitialized.kt b/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/simpleIsInitialized.kt index 17a7129544c..a91306584e4 100644 --- a/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/simpleIsInitialized.kt +++ b/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/simpleIsInitialized.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // LANGUAGE_VERSION: 1.2 // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/topLevelProperty.kt b/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/topLevelProperty.kt index 76d61cfb6fb..ef928e74a5b 100644 --- a/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/topLevelProperty.kt +++ b/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/topLevelProperty.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND: JS_IR // LANGUAGE_VERSION: 1.2 // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/properties/lateinit/local/kt23260.kt b/compiler/testData/codegen/box/properties/lateinit/local/kt23260.kt index fe7c9ab5b31..422a501ba6d 100644 --- a/compiler/testData/codegen/box/properties/lateinit/local/kt23260.kt +++ b/compiler/testData/codegen/box/properties/lateinit/local/kt23260.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND: JS_IR // WITH_RUNTIME fun box(): String { diff --git a/compiler/testData/codegen/box/properties/lateinit/local/uninitializedCapturedMemberAccess.kt b/compiler/testData/codegen/box/properties/lateinit/local/uninitializedCapturedMemberAccess.kt index 347e92f3e30..2ec43b51f18 100644 --- a/compiler/testData/codegen/box/properties/lateinit/local/uninitializedCapturedMemberAccess.kt +++ b/compiler/testData/codegen/box/properties/lateinit/local/uninitializedCapturedMemberAccess.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND: JS_IR // LANGUAGE_VERSION: 1.2 // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/properties/lateinit/local/uninitializedCapturedRead.kt b/compiler/testData/codegen/box/properties/lateinit/local/uninitializedCapturedRead.kt index a3d062c44bf..1e66de74e9c 100644 --- a/compiler/testData/codegen/box/properties/lateinit/local/uninitializedCapturedRead.kt +++ b/compiler/testData/codegen/box/properties/lateinit/local/uninitializedCapturedRead.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND: JS_IR // LANGUAGE_VERSION: 1.2 // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/properties/lateinit/local/uninitializedMemberAccess.kt b/compiler/testData/codegen/box/properties/lateinit/local/uninitializedMemberAccess.kt index 9b576337ee3..bb44b6b553e 100644 --- a/compiler/testData/codegen/box/properties/lateinit/local/uninitializedMemberAccess.kt +++ b/compiler/testData/codegen/box/properties/lateinit/local/uninitializedMemberAccess.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND: JS_IR // LANGUAGE_VERSION: 1.2 // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/properties/lateinit/local/uninitializedRead.kt b/compiler/testData/codegen/box/properties/lateinit/local/uninitializedRead.kt index 9f0300911bc..c27563bdf75 100644 --- a/compiler/testData/codegen/box/properties/lateinit/local/uninitializedRead.kt +++ b/compiler/testData/codegen/box/properties/lateinit/local/uninitializedRead.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND: JS_IR // LANGUAGE_VERSION: 1.2 // WITH_RUNTIME