Support nullable inline classes

This commit is contained in:
Svyatoslav Kuzmich
2018-11-06 19:07:14 +03:00
parent 5ea7673950
commit 0bf3199c19
4 changed files with 56 additions and 12 deletions
@@ -124,7 +124,6 @@ private fun JsIrBackendContext.lower(moduleFragment: IrModuleFragment, dependenc
MultipleCatchesLowering(this).lower(moduleFragment)
BridgesConstruction(this).runOnFilesPostfix(moduleFragment)
TypeOperatorLowering(this).lower(moduleFragment)
BlockDecomposerLowering(this).runOnFilesPostfix(moduleFragment)
SecondaryCtorLowering(this).apply {
constructorProcessorLowering.runOnFilesPostfix(moduleFragment.files + dependencies.flatMap { it.files })
@@ -136,6 +135,7 @@ private fun JsIrBackendContext.lower(moduleFragment: IrModuleFragment, dependenc
inlineClassUsageLowering.lower(moduleFragment)
}
AutoboxingTransformer(this).lower(moduleFragment)
BlockDecomposerLowering(this).runOnFilesPostfix(moduleFragment)
ClassReferenceLowering(this).lower(moduleFragment)
PrimitiveCompanionLowering(this).lower(moduleFragment)
@@ -177,7 +177,7 @@ object JsIrBuilder {
fun buildVar(
type: IrType,
parent: IrDeclarationParent,
parent: IrDeclarationParent?,
name: String = "tmp",
isVar: Boolean = false,
isConst: Boolean = false,
@@ -198,7 +198,7 @@ object JsIrBuilder {
).also {
descriptor.bind(it)
it.initializer = initializer
it.parent = parent
if (parent != null) it.parent = parent
}
}
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.ir.types.isNothing
import org.jetbrains.kotlin.ir.types.makeNotNull
import org.jetbrains.kotlin.ir.util.getInlinedClass
import org.jetbrains.kotlin.ir.util.isInlined
import org.jetbrains.kotlin.ir.util.isNullable
// Copied and adapted from Kotlin/Native
@@ -64,7 +65,7 @@ class AutoboxingTransformer(val context: JsIrBackendContext) : AbstractValueUsag
else -> this.type
}
// TODO: Default parameters are passed as nulls and they need not to be unboxed. Fix this
// // TODO: Default parameters are passed as nulls and they need not to be unboxed. Fix this
if (actualType.makeNotNull().isNothing())
return this
@@ -80,12 +81,43 @@ class AutoboxingTransformer(val context: JsIrBackendContext) : AbstractValueUsag
else -> return this
}
return JsIrBuilder.buildCall(
function,
expectedType,
typeArguments = listOf(actualType, expectedType)
).also {
it.putValueArgument(0, this)
return buildSafeCall(this, actualType, expectedType) { arg ->
JsIrBuilder.buildCall(
function,
expectedType,
typeArguments = listOf(actualType, expectedType)
).also {
it.putValueArgument(0, arg)
}
}
}
private fun buildSafeCall(
arg: IrExpression,
actualType: IrType,
resultType: IrType,
call: (IrExpression) -> IrExpression
): IrExpression {
if (!actualType.isNullable())
return call(arg)
return JsIrBuilder.run {
val tmp = buildVar(actualType, parent = null, initializer = arg)
val nullCheck = buildIfElse(
type = resultType,
cond = buildCall(irBuiltIns.eqeqSymbol).apply {
putValueArgument(0, buildGetValue(tmp.symbol))
putValueArgument(1, buildNull(irBuiltIns.nothingNType))
},
thenBranch = buildNull(irBuiltIns.nothingNType),
elseBranch = call(buildGetValue(tmp.symbol))
)
buildBlock(
type = resultType,
statements = listOf(
tmp,
nullCheck
)
)
}
}
@@ -23,8 +23,20 @@ import org.jetbrains.kotlin.ir.types.isMarkedNullable
fun IrType.getInlinedClass(): IrClass? {
if (this is IrSimpleType) {
val erased = erase(this) ?: return null
if (!this.isMarkedNullable() && erased.isInline) {
// TODO: Don't box nullable type inline classes with non-nullable underlying type (JS IR BE)
if (erased.isInline) {
if (this.isMarkedNullable()) {
var fieldType: IrType
var fieldInlinedClass = erased
while (true) {
fieldType = getInlineClassBackingField(fieldInlinedClass).type
if (fieldType.isMarkedNullable()) {
return null
}
fieldInlinedClass = fieldType.getInlinedClass() ?: break
}
}
return erased
}
}