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.Ir
|
||||||
import org.jetbrains.kotlin.backend.common.ir.SharedVariablesManager
|
import org.jetbrains.kotlin.backend.common.ir.SharedVariablesManager
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
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.descriptors.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
@@ -33,4 +34,5 @@ interface BackendContext {
|
|||||||
val declarationFactory: DeclarationFactory
|
val declarationFactory: DeclarationFactory
|
||||||
val internalPackageFqn: FqName
|
val internalPackageFqn: FqName
|
||||||
val transformedFunction: MutableMap<IrFunctionSymbol, IrSimpleFunctionSymbol>
|
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.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
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.isPrimitiveType
|
||||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||||
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
|
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
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
|
||||||
class LateinitLowering(val context: CommonBackendContext) : FileLoweringPass {
|
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) {
|
override fun lower(irFile: IrFile) {
|
||||||
val nullableFields = mutableMapOf<IrField, IrField>()
|
|
||||||
val nullableVariables = mutableMapOf<IrVariable, IrVariable>()
|
val nullableVariables = mutableMapOf<IrVariable, IrVariable>()
|
||||||
|
|
||||||
// Transform declarations
|
// Transform declarations
|
||||||
@@ -46,17 +63,9 @@ class LateinitLowering(val context: CommonBackendContext) : FileLoweringPass {
|
|||||||
declaration.transformChildrenVoid(this)
|
declaration.transformChildrenVoid(this)
|
||||||
if (declaration.isLateinit && declaration.origin != IrDeclarationOrigin.FAKE_OVERRIDE) {
|
if (declaration.isLateinit && declaration.origin != IrDeclarationOrigin.FAKE_OVERRIDE) {
|
||||||
val oldField = declaration.backingField!!
|
val oldField = declaration.backingField!!
|
||||||
val newField = buildField {
|
val newField = buildOrGetNullableField(oldField)
|
||||||
updateFrom(oldField)
|
|
||||||
type = oldField.type.makeNullable()
|
|
||||||
name = oldField.name
|
|
||||||
}.also { newField ->
|
|
||||||
newField.parent = oldField.parent
|
|
||||||
newField.correspondingPropertySymbol = declaration.symbol
|
|
||||||
declaration.backingField = newField
|
|
||||||
}
|
|
||||||
|
|
||||||
nullableFields[oldField] = newField
|
declaration.backingField = newField
|
||||||
|
|
||||||
transformGetter(newField, declaration.getter!!)
|
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 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 {
|
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
|
override val scriptMode: Boolean = false
|
||||||
) : CommonBackendContext {
|
) : CommonBackendContext {
|
||||||
override val transformedFunction = mutableMapOf<IrFunctionSymbol, IrSimpleFunctionSymbol>()
|
override val transformedFunction = mutableMapOf<IrFunctionSymbol, IrSimpleFunctionSymbol>()
|
||||||
|
override val lateinitNullableFields = mutableMapOf<IrField, IrField>()
|
||||||
|
|
||||||
override val builtIns = module.builtIns
|
override val builtIns = module.builtIns
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ class JvmBackendContext(
|
|||||||
override val transformedFunction: MutableMap<IrFunctionSymbol, IrSimpleFunctionSymbol>
|
override val transformedFunction: MutableMap<IrFunctionSymbol, IrSimpleFunctionSymbol>
|
||||||
get() = TODO("not implemented")
|
get() = TODO("not implemented")
|
||||||
override val scriptMode: Boolean = false
|
override val scriptMode: Boolean = false
|
||||||
|
override val lateinitNullableFields = mutableMapOf<IrField, IrField>()
|
||||||
|
|
||||||
override val builtIns = state.module.builtIns
|
override val builtIns = state.module.builtIns
|
||||||
val typeMapper = IrTypeMapper(this)
|
val typeMapper = IrTypeMapper(this)
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ class WasmBackendContext(
|
|||||||
override var inVerbosePhase: Boolean = false
|
override var inVerbosePhase: Boolean = false
|
||||||
override val scriptMode = false
|
override val scriptMode = false
|
||||||
override val transformedFunction = mutableMapOf<IrFunctionSymbol, IrSimpleFunctionSymbol>()
|
override val transformedFunction = mutableMapOf<IrFunctionSymbol, IrSimpleFunctionSymbol>()
|
||||||
|
override val lateinitNullableFields = mutableMapOf<IrField, IrField>()
|
||||||
|
|
||||||
// Place to store declarations excluded from code generation
|
// Place to store declarations excluded from code generation
|
||||||
val excludedDeclarations: IrPackageFragment by lazy {
|
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");
|
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")
|
@TestMetadata("nonInlineLambda.kt")
|
||||||
public void testNonInlineLambda() throws Exception {
|
public void testNonInlineLambda() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/nonInlineLambda.kt");
|
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");
|
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")
|
@TestMetadata("nonInlineLambda.kt")
|
||||||
public void testNonInlineLambda() throws Exception {
|
public void testNonInlineLambda() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/nonInlineLambda.kt");
|
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");
|
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")
|
@TestMetadata("nonInlineLambda.kt")
|
||||||
public void testNonInlineLambda() throws Exception {
|
public void testNonInlineLambda() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/nonInlineLambda.kt");
|
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");
|
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")
|
@TestMetadata("nonInlineLambda.kt")
|
||||||
public void testNonInlineLambda() throws Exception {
|
public void testNonInlineLambda() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/nonInlineLambda.kt");
|
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");
|
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")
|
@TestMetadata("nonInlineLambda.kt")
|
||||||
public void testNonInlineLambda() throws Exception {
|
public void testNonInlineLambda() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/nonInlineLambda.kt");
|
runTest("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/nonInlineLambda.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user