Fix lateinit isInitialized check in multi-file case

This commit is contained in:
Roman Artemev
2019-10-28 16:38:50 +03:00
committed by romanart
parent d75b938089
commit 78b29349c9
11 changed files with 100 additions and 12 deletions
@@ -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>
}
@@ -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 {
@@ -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
}
@@ -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");
@@ -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");
@@ -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");
@@ -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");
@@ -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");