Fix lateinit isInitialized check in multi-file case
This commit is contained in:
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.backend.common.ir.DeclarationFactory
|
||||
import org.jetbrains.kotlin.backend.common.ir.Ir
|
||||
import org.jetbrains.kotlin.backend.common.ir.SharedVariablesManager
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
@@ -33,4 +34,5 @@ interface BackendContext {
|
||||
val declarationFactory: DeclarationFactory
|
||||
val internalPackageFqn: FqName
|
||||
val transformedFunction: MutableMap<IrFunctionSymbol, IrSimpleFunctionSymbol>
|
||||
val lateinitNullableFields: MutableMap<IrField, IrField>
|
||||
}
|
||||
|
||||
+24
-12
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.isMarkedNullable
|
||||
import org.jetbrains.kotlin.ir.types.isPrimitiveType
|
||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
|
||||
@@ -36,8 +37,24 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
class LateinitLowering(val context: CommonBackendContext) : FileLoweringPass {
|
||||
|
||||
private val nullableFields = context.lateinitNullableFields
|
||||
private fun buildOrGetNullableField(originalField: IrField): IrField {
|
||||
if (originalField.type.isMarkedNullable()) return originalField
|
||||
return nullableFields.getOrPut(originalField) {
|
||||
buildField {
|
||||
updateFrom(originalField)
|
||||
type = originalField.type.makeNullable()
|
||||
name = originalField.name
|
||||
}.apply {
|
||||
parent = originalField.parent
|
||||
correspondingPropertySymbol = originalField.correspondingPropertySymbol
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
val nullableFields = mutableMapOf<IrField, IrField>()
|
||||
|
||||
val nullableVariables = mutableMapOf<IrVariable, IrVariable>()
|
||||
|
||||
// Transform declarations
|
||||
@@ -46,17 +63,9 @@ class LateinitLowering(val context: CommonBackendContext) : FileLoweringPass {
|
||||
declaration.transformChildrenVoid(this)
|
||||
if (declaration.isLateinit && declaration.origin != IrDeclarationOrigin.FAKE_OVERRIDE) {
|
||||
val oldField = declaration.backingField!!
|
||||
val newField = buildField {
|
||||
updateFrom(oldField)
|
||||
type = oldField.type.makeNullable()
|
||||
name = oldField.name
|
||||
}.also { newField ->
|
||||
newField.parent = oldField.parent
|
||||
newField.correspondingPropertySymbol = declaration.symbol
|
||||
declaration.backingField = newField
|
||||
}
|
||||
val newField = buildOrGetNullableField(oldField)
|
||||
|
||||
nullableFields[oldField] = newField
|
||||
declaration.backingField = newField
|
||||
|
||||
transformGetter(newField, declaration.getter!!)
|
||||
}
|
||||
@@ -166,8 +175,11 @@ class LateinitLowering(val context: CommonBackendContext) : FileLoweringPass {
|
||||
|
||||
val property = receiver.getter?.owner?.resolveFakeOverride()?.correspondingProperty!!.also { assert(it.isLateinit) }
|
||||
|
||||
val nullableField =
|
||||
buildOrGetNullableField(property.backingField ?: error("Lateinit property is supposed to have backing field"))
|
||||
|
||||
return expression.run { context.createIrBuilder(symbol, startOffset, endOffset) }.run {
|
||||
irNotEquals(irGetField(receiver.dispatchReceiver, property.backingField!!), irNull())
|
||||
irNotEquals(irGetField(receiver.dispatchReceiver, nullableField), irNull())
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -48,6 +48,7 @@ class JsIrBackendContext(
|
||||
override val scriptMode: Boolean = false
|
||||
) : CommonBackendContext {
|
||||
override val transformedFunction = mutableMapOf<IrFunctionSymbol, IrSimpleFunctionSymbol>()
|
||||
override val lateinitNullableFields = mutableMapOf<IrField, IrField>()
|
||||
|
||||
override val builtIns = module.builtIns
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ class JvmBackendContext(
|
||||
override val transformedFunction: MutableMap<IrFunctionSymbol, IrSimpleFunctionSymbol>
|
||||
get() = TODO("not implemented")
|
||||
override val scriptMode: Boolean = false
|
||||
override val lateinitNullableFields = mutableMapOf<IrField, IrField>()
|
||||
|
||||
override val builtIns = state.module.builtIns
|
||||
val typeMapper = IrTypeMapper(this)
|
||||
|
||||
@@ -38,6 +38,7 @@ class WasmBackendContext(
|
||||
override var inVerbosePhase: Boolean = false
|
||||
override val scriptMode = false
|
||||
override val transformedFunction = mutableMapOf<IrFunctionSymbol, IrSimpleFunctionSymbol>()
|
||||
override val lateinitNullableFields = mutableMapOf<IrField, IrField>()
|
||||
|
||||
// Place to store declarations excluded from code generation
|
||||
val excludedDeclarations: IrPackageFragment by lazy {
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
// IGNORE_BACKEND: JVM, JVM_IR
|
||||
// FILE: A.kt
|
||||
|
||||
fun test1F(o: Foo) = if (!o::bar.isInitialized) "1F" else "Fail1F"
|
||||
fun test1T(o: Foo) = if (o::bar.isInitialized) "1T" else "Fail1T"
|
||||
|
||||
// FILE: B.kt
|
||||
|
||||
fun test2F(o: Foo) = if (!o::bar.isInitialized) "2F" else "Fail2F"
|
||||
fun test2T(o: Foo) = if (o::bar.isInitialized) "2T" else "Fail2T"
|
||||
|
||||
class Foo {
|
||||
lateinit var bar: String
|
||||
|
||||
fun testF() = if (!this::bar.isInitialized) "0F" else "Fail0F"
|
||||
fun testT() = if (this::bar.isInitialized) "0T" else "Fail0T"
|
||||
}
|
||||
|
||||
|
||||
fun test3F(o: Foo) = if (!o::bar.isInitialized) "3F" else "Fail3F"
|
||||
fun test3T(o: Foo) = if (o::bar.isInitialized) "3T" else "Fail3T"
|
||||
|
||||
// FILE: C.kt
|
||||
|
||||
fun test4F(o: Foo) = if (!o::bar.isInitialized) "4F" else "Fail4F"
|
||||
fun test4T(o: Foo) = if (o::bar.isInitialized) "4T" else "Fail4T"
|
||||
|
||||
|
||||
fun box(): String {
|
||||
val o = Foo()
|
||||
if (o.testF() != "0F") return "Fail0F"
|
||||
if (test1F(o) != "1F") return "Fail1F"
|
||||
if (test2F(o) != "2F") return "Fail2F"
|
||||
if (test3F(o) != "3F") return "Fail3F"
|
||||
if (test4F(o) != "4F") return "Fail4F"
|
||||
|
||||
o.bar = "OK"
|
||||
|
||||
if (o.testT() != "0T") return "Fail0T"
|
||||
if (test1T(o) != "1T") return "Fail1T"
|
||||
if (test2T(o) != "2T") return "Fail2T"
|
||||
if (test3T(o) != "3T") return "Fail3T"
|
||||
if (test4T(o) != "4T") return "Fail4T"
|
||||
|
||||
return o.bar
|
||||
}
|
||||
+5
@@ -18912,6 +18912,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/innerSubclass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("isInitializedMultiFile.kt")
|
||||
public void testIsInitializedMultiFile() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/isInitializedMultiFile.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nonInlineLambda.kt")
|
||||
public void testNonInlineLambda() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/nonInlineLambda.kt");
|
||||
|
||||
+5
@@ -18912,6 +18912,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/innerSubclass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("isInitializedMultiFile.kt")
|
||||
public void testIsInitializedMultiFile() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/isInitializedMultiFile.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nonInlineLambda.kt")
|
||||
public void testNonInlineLambda() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/nonInlineLambda.kt");
|
||||
|
||||
+5
@@ -17731,6 +17731,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/innerSubclass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("isInitializedMultiFile.kt")
|
||||
public void testIsInitializedMultiFile() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/isInitializedMultiFile.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nonInlineLambda.kt")
|
||||
public void testNonInlineLambda() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/nonInlineLambda.kt");
|
||||
|
||||
Generated
+5
@@ -14687,6 +14687,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/innerSubclass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("isInitializedMultiFile.kt")
|
||||
public void testIsInitializedMultiFile() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/isInitializedMultiFile.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nonInlineLambda.kt")
|
||||
public void testNonInlineLambda() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/nonInlineLambda.kt");
|
||||
|
||||
+5
@@ -15842,6 +15842,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/innerSubclass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("isInitializedMultiFile.kt")
|
||||
public void testIsInitializedMultiFile() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/isInitializedMultiFile.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nonInlineLambda.kt")
|
||||
public void testNonInlineLambda() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/nonInlineLambda.kt");
|
||||
|
||||
Reference in New Issue
Block a user