diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt index 3a3532b5cf2..a7c8f215763 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt @@ -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) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ir/IrBuilder.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ir/IrBuilder.kt index 093bea91ac2..92d2eeedf55 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ir/IrBuilder.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ir/IrBuilder.kt @@ -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 } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/AutoboxingTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/AutoboxingTransformer.kt index ca3e4634623..22030fb66c6 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/AutoboxingTransformer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/AutoboxingTransformer.kt @@ -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 + ) + ) } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/InlineClasses.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/InlineClasses.kt index 1d199a51fd3..92c92b04924 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/InlineClasses.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/InlineClasses.kt @@ -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 } }