Support nullable inline classes
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+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.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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user