Support nullable inline classes
This commit is contained in:
@@ -124,7 +124,6 @@ private fun JsIrBackendContext.lower(moduleFragment: IrModuleFragment, dependenc
|
|||||||
MultipleCatchesLowering(this).lower(moduleFragment)
|
MultipleCatchesLowering(this).lower(moduleFragment)
|
||||||
BridgesConstruction(this).runOnFilesPostfix(moduleFragment)
|
BridgesConstruction(this).runOnFilesPostfix(moduleFragment)
|
||||||
TypeOperatorLowering(this).lower(moduleFragment)
|
TypeOperatorLowering(this).lower(moduleFragment)
|
||||||
BlockDecomposerLowering(this).runOnFilesPostfix(moduleFragment)
|
|
||||||
|
|
||||||
SecondaryCtorLowering(this).apply {
|
SecondaryCtorLowering(this).apply {
|
||||||
constructorProcessorLowering.runOnFilesPostfix(moduleFragment.files + dependencies.flatMap { it.files })
|
constructorProcessorLowering.runOnFilesPostfix(moduleFragment.files + dependencies.flatMap { it.files })
|
||||||
@@ -136,6 +135,7 @@ private fun JsIrBackendContext.lower(moduleFragment: IrModuleFragment, dependenc
|
|||||||
inlineClassUsageLowering.lower(moduleFragment)
|
inlineClassUsageLowering.lower(moduleFragment)
|
||||||
}
|
}
|
||||||
AutoboxingTransformer(this).lower(moduleFragment)
|
AutoboxingTransformer(this).lower(moduleFragment)
|
||||||
|
BlockDecomposerLowering(this).runOnFilesPostfix(moduleFragment)
|
||||||
|
|
||||||
ClassReferenceLowering(this).lower(moduleFragment)
|
ClassReferenceLowering(this).lower(moduleFragment)
|
||||||
PrimitiveCompanionLowering(this).lower(moduleFragment)
|
PrimitiveCompanionLowering(this).lower(moduleFragment)
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ object JsIrBuilder {
|
|||||||
|
|
||||||
fun buildVar(
|
fun buildVar(
|
||||||
type: IrType,
|
type: IrType,
|
||||||
parent: IrDeclarationParent,
|
parent: IrDeclarationParent?,
|
||||||
name: String = "tmp",
|
name: String = "tmp",
|
||||||
isVar: Boolean = false,
|
isVar: Boolean = false,
|
||||||
isConst: Boolean = false,
|
isConst: Boolean = false,
|
||||||
@@ -198,7 +198,7 @@ object JsIrBuilder {
|
|||||||
).also {
|
).also {
|
||||||
descriptor.bind(it)
|
descriptor.bind(it)
|
||||||
it.initializer = initializer
|
it.initializer = initializer
|
||||||
it.parent = parent
|
if (parent != null) it.parent = parent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+39
-7
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.ir.types.isNothing
|
|||||||
import org.jetbrains.kotlin.ir.types.makeNotNull
|
import org.jetbrains.kotlin.ir.types.makeNotNull
|
||||||
import org.jetbrains.kotlin.ir.util.getInlinedClass
|
import org.jetbrains.kotlin.ir.util.getInlinedClass
|
||||||
import org.jetbrains.kotlin.ir.util.isInlined
|
import org.jetbrains.kotlin.ir.util.isInlined
|
||||||
|
import org.jetbrains.kotlin.ir.util.isNullable
|
||||||
|
|
||||||
|
|
||||||
// Copied and adapted from Kotlin/Native
|
// Copied and adapted from Kotlin/Native
|
||||||
@@ -64,7 +65,7 @@ class AutoboxingTransformer(val context: JsIrBackendContext) : AbstractValueUsag
|
|||||||
else -> this.type
|
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())
|
if (actualType.makeNotNull().isNothing())
|
||||||
return this
|
return this
|
||||||
|
|
||||||
@@ -80,12 +81,43 @@ class AutoboxingTransformer(val context: JsIrBackendContext) : AbstractValueUsag
|
|||||||
else -> return this
|
else -> return this
|
||||||
}
|
}
|
||||||
|
|
||||||
return JsIrBuilder.buildCall(
|
return buildSafeCall(this, actualType, expectedType) { arg ->
|
||||||
function,
|
JsIrBuilder.buildCall(
|
||||||
expectedType,
|
function,
|
||||||
typeArguments = listOf(actualType, expectedType)
|
expectedType,
|
||||||
).also {
|
typeArguments = listOf(actualType, expectedType)
|
||||||
it.putValueArgument(0, this)
|
).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? {
|
fun IrType.getInlinedClass(): IrClass? {
|
||||||
if (this is IrSimpleType) {
|
if (this is IrSimpleType) {
|
||||||
val erased = erase(this) ?: return null
|
val erased = erase(this) ?: return null
|
||||||
if (!this.isMarkedNullable() && erased.isInline) {
|
if (erased.isInline) {
|
||||||
// TODO: Don't box nullable type inline classes with non-nullable underlying type (JS IR BE)
|
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
|
return erased
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user