Implemented 'lateinit' properties
If property is lateinit, then on each access we need to test its value and throw UninitializedPropertyAccessException if it is null.
This commit is contained in:
+3
@@ -48,6 +48,9 @@ internal class KonanLower(val context: Context) {
|
||||
DefaultArgumentStubGenerator(context).runOnFilePostfix(irFile)
|
||||
DefaultParameterInjector(context).runOnFilePostfix(irFile)
|
||||
}
|
||||
phaser.phase(KonanPhase.LOWER_LATEINIT) {
|
||||
LateinitLowering(context).lower(irFile)
|
||||
}
|
||||
phaser.phase(KonanPhase.LOWER_BUILTIN_OPERATORS) {
|
||||
BuiltinOperatorLowering(context).runOnFilePostfix(irFile)
|
||||
}
|
||||
|
||||
+17
-15
@@ -3,7 +3,7 @@ package org.jetbrains.kotlin.backend.konan
|
||||
import org.jetbrains.kotlin.backend.konan.util.*
|
||||
|
||||
enum class KonanPhase(val description: String,
|
||||
val prerequisite: Set<KonanPhase> = setOf<KonanPhase>(),
|
||||
vararg prerequisite: KonanPhase,
|
||||
var enabled: Boolean = true, var verbose: Boolean = false) {
|
||||
|
||||
/* */ FRONTEND("Frontend builds AST"),
|
||||
@@ -14,27 +14,29 @@ enum class KonanPhase(val description: String,
|
||||
/* ... ... */ LOWER_INTEROP("Interop lowering"),
|
||||
/* ... ... */ LOWER_ENUMS("Enum classes lowering"),
|
||||
/* ... ... */ LOWER_DELEGATION("Delegation lowering"),
|
||||
/* ... ... */ LOWER_INITIALIZERS("Initializers lowering", setOf(LOWER_ENUMS)),
|
||||
/* ... ... */ LOWER_SHARED_VARIABLES("Shared Variable Lowering", setOf(LOWER_INITIALIZERS)),
|
||||
/* ... ... */ LOWER_CALLABLES("Callable references Lowering", setOf(
|
||||
LOWER_INTEROP, LOWER_INITIALIZERS, LOWER_DELEGATION)),
|
||||
/* ... ... */ LOWER_VARARG("Vararg lowering", setOf(LOWER_CALLABLES)),
|
||||
/* ... ... */ LOWER_LOCAL_FUNCTIONS("Local Function Lowering", setOf(LOWER_SHARED_VARIABLES)),
|
||||
/* ... ... */ LOWER_TAILREC("tailrec lowering", setOf(LOWER_LOCAL_FUNCTIONS)),
|
||||
/* ... ... */ LOWER_DEFAULT_PARAMETER_EXTENT("Default Parameter Extent Lowering", setOf(
|
||||
LOWER_TAILREC, LOWER_ENUMS)),
|
||||
/* ... ... */ LOWER_INNER_CLASSES("Inner classes lowering", setOf(LOWER_DEFAULT_PARAMETER_EXTENT)),
|
||||
/* ... ... */ LOWER_BUILTIN_OPERATORS("BuiltIn Operators Lowering", setOf(
|
||||
LOWER_DEFAULT_PARAMETER_EXTENT)),
|
||||
/* ... ... */ LOWER_INITIALIZERS("Initializers lowering", LOWER_ENUMS),
|
||||
/* ... ... */ LOWER_SHARED_VARIABLES("Shared Variable Lowering", LOWER_INITIALIZERS),
|
||||
/* ... ... */ LOWER_CALLABLES("Callable references Lowering",
|
||||
LOWER_INTEROP, LOWER_INITIALIZERS, LOWER_DELEGATION),
|
||||
/* ... ... */ LOWER_VARARG("Vararg lowering", LOWER_CALLABLES),
|
||||
/* ... ... */ LOWER_LOCAL_FUNCTIONS("Local Function Lowering", LOWER_SHARED_VARIABLES),
|
||||
/* ... ... */ LOWER_TAILREC("tailrec lowering", LOWER_LOCAL_FUNCTIONS),
|
||||
/* ... ... */ LOWER_DEFAULT_PARAMETER_EXTENT("Default Parameter Extent Lowering",
|
||||
LOWER_TAILREC, LOWER_ENUMS),
|
||||
/* ... ... */ LOWER_INNER_CLASSES("Inner classes lowering", LOWER_DEFAULT_PARAMETER_EXTENT),
|
||||
/* ... ... */ LOWER_LATEINIT("Lateinit properties lowering"),
|
||||
/* ... ... */ LOWER_BUILTIN_OPERATORS("BuiltIn Operators Lowering", LOWER_DEFAULT_PARAMETER_EXTENT, LOWER_LATEINIT),
|
||||
/* ... ... */ LOWER_TYPE_OPERATORS("Type operators lowering"),
|
||||
/* ... ... */ BRIDGES_BUILDING("Bridges building"),
|
||||
/* ... ... */ LOWER_STRING_CONCAT("String concatenation lowering"),
|
||||
/* ... ... */ AUTOBOX("Autoboxing of primitive types", setOf(BRIDGES_BUILDING)),
|
||||
/* ... ... */ AUTOBOX("Autoboxing of primitive types", BRIDGES_BUILDING),
|
||||
/* ... */ BITCODE("LLVM BitCode Generation"),
|
||||
/* ... ... */ RTTI("RTTI Generation"),
|
||||
/* ... ... */ CODEGEN("Code Generation"),
|
||||
/* ... ... */ METADATOR("Metadata Generation"),
|
||||
/* */ LINKER("Link Stage")
|
||||
/* */ LINKER("Link Stage");
|
||||
|
||||
val prerequisite = prerequisite.toSet()
|
||||
}
|
||||
|
||||
object KonanPhases {
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalFunctions
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBlock
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
internal class LateinitLowering(val context: Context): FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(object: IrElementTransformerVoid() {
|
||||
override fun visitProperty(declaration: IrProperty): IrStatement {
|
||||
if (declaration.descriptor.isLateInit)
|
||||
transformGetter(declaration.descriptor, declaration.getter!!)
|
||||
return declaration
|
||||
}
|
||||
|
||||
private fun transformGetter(propertyDescriptor: PropertyDescriptor, getter: IrFunction) {
|
||||
val startOffset = getter.startOffset
|
||||
val endOffset = getter.endOffset
|
||||
val irBuilder = context.createIrBuilder(getter.descriptor, startOffset, endOffset)
|
||||
irBuilder.run {
|
||||
val block = irBlock(propertyDescriptor.type)
|
||||
val resultVar = scope.createTemporaryVariable(irGetField(irThis(), propertyDescriptor))
|
||||
block.statements.add(resultVar)
|
||||
val throwIfNull = irIfThenElse(context.builtIns.nothingType,
|
||||
irNotEquals(irGet(resultVar.descriptor), irNull()),
|
||||
irReturn(irGet(resultVar.descriptor)),
|
||||
irCall(throwErrorFunction))
|
||||
block.statements.add(throwIfNull)
|
||||
getter.body = IrExpressionBodyImpl(startOffset, endOffset, block)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private val throwErrorFunction = context.builtIns.getKonanInternalFunctions("ThrowUninitializedPropertyAccessException").single()
|
||||
|
||||
private fun IrBuilderWithScope.irBlock(type: KotlinType): IrBlock
|
||||
= IrBlockImpl(startOffset, endOffset, type)
|
||||
|
||||
private fun IrBuilderWithScope.irGetField(receiver: IrExpression?, property: PropertyDescriptor): IrExpression
|
||||
= IrGetFieldImpl(startOffset, endOffset, property, receiver)
|
||||
}
|
||||
@@ -24,6 +24,10 @@ fun ThrowNoWhenBranchMatchedException(): Nothing {
|
||||
throw NoWhenBranchMatchedException()
|
||||
}
|
||||
|
||||
fun ThrowUninitializedPropertyAccessException(): Nothing {
|
||||
throw UninitializedPropertyAccessException()
|
||||
}
|
||||
|
||||
@ExportForCppRuntime
|
||||
internal fun TheEmptyString() = ""
|
||||
|
||||
|
||||
@@ -176,6 +176,15 @@ public open class NoWhenBranchMatchedException : RuntimeException {
|
||||
}
|
||||
}
|
||||
|
||||
public open class UninitializedPropertyAccessException : RuntimeException {
|
||||
|
||||
constructor() : super() {
|
||||
}
|
||||
|
||||
constructor(s: String) : super(s) {
|
||||
}
|
||||
}
|
||||
|
||||
public open class OutOfMemoryError : Error {
|
||||
|
||||
constructor() : super() {
|
||||
|
||||
Reference in New Issue
Block a user