diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/EnumWhenLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/EnumWhenLowering.kt index f432b8fea59..efcc9809fad 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/EnumWhenLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/EnumWhenLowering.kt @@ -26,7 +26,7 @@ import org.jetbrains.kotlin.ir.util.* * Replace branches that are comparisons with compile-time known enum entries * with comparisons of ordinals. */ -open class EnumWhenLowering(protected val context: CommonBackendContext) : IrElementTransformerVoidWithContext(), FileLoweringPass { +open class EnumWhenLowering(protected open val context: CommonBackendContext) : IrElementTransformerVoidWithContext(), FileLoweringPass { protected open fun mapConstEnumEntry(entry: IrEnumEntry): Int = entry.parentAsClass.declarations.filterIsInstance().indexOf(entry).also { diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/MappedEnumWhenLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/MappedEnumWhenLowering.kt index 0290b7fa631..e56703c86d6 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/MappedEnumWhenLowering.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/MappedEnumWhenLowering.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.jvm.lower import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor import org.jetbrains.kotlin.backend.common.lower.EnumWhenLowering import org.jetbrains.kotlin.backend.common.lower.createIrBuilder +import org.jetbrains.kotlin.backend.common.lower.irCatch import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin @@ -60,7 +61,7 @@ internal val enumWhenPhase = makeIrFilePhase( // The latter would not need to be recompiled if new entries were added before `X` // at the negligible cost of an additional initializer per run + one array read per call. // -private class MappedEnumWhenLowering(context: JvmBackendContext) : EnumWhenLowering(context) { +private class MappedEnumWhenLowering(override val context: JvmBackendContext) : EnumWhenLowering(context) { private val intArray = context.irBuiltIns.primitiveArrayForType.getValue(context.irBuiltIns.intType) private val intArrayConstructor = intArray.constructors.single { it.owner.valueParameters.size == 1 } private val intArrayGet = intArray.functions.single { it.owner.name == OperatorNameConventions.GET } @@ -141,11 +142,23 @@ private class MappedEnumWhenLowering(context: JvmBackendContext) : EnumWhenLower val result = irTemporary(irCall(intArrayConstructor).apply { putValueArgument(0, enumSize) }) for ((entry, index) in mapping.ordinals) { val runtimeEntry = IrGetEnumValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, enum.defaultType, entry.symbol) - +irCall(intArraySet).apply { + val writeToMapping = irCall(intArraySet).apply { dispatchReceiver = irGet(result) putValueArgument(0, super.mapRuntimeEnumEntry(builder, runtimeEntry)) // .ordinal() putValueArgument(1, irInt(index)) } + val noSuchFieldVariable = scope.createTemporaryVariableDeclaration( + this@MappedEnumWhenLowering.context.ir.symbols.noSuchFieldErrorType, + startOffset = UNDEFINED_OFFSET, + endOffset = UNDEFINED_OFFSET + ) + +irTry( + // Ignore NoSuchFieldError in case this module is running with a version of the dependency + // that is missing some of the enum's fields; the corresponding branches are then effectively + // unreachable code (KT-38637) + context.irBuiltIns.unitType, writeToMapping, listOf(irCatch(noSuchFieldVariable, irUnit())), + finallyExpression = null + ) } +irGet(result) }) @@ -155,7 +168,7 @@ private class MappedEnumWhenLowering(context: JvmBackendContext) : EnumWhenLower declaration.declarations += mappingState.mappingsClass.apply { parent = declaration if (mappingState.isPublicAbi) { - (context as JvmBackendContext).publicAbiSymbols += symbol + context.publicAbiSymbols += symbol } } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt index 078784645a7..0ef70882d68 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt @@ -265,6 +265,11 @@ class JvmSymbols( val assertionErrorConstructor = javaLangAssertionError.constructors.single() + private val javaLangNoSuchFieldError: IrClassSymbol = + createClass(FqName("java.lang.NoSuchFieldError"), classModality = Modality.OPEN) {} + + val noSuchFieldErrorType = javaLangNoSuchFieldError.defaultType + val continuationClass: IrClassSymbol = createClass(StandardNames.CONTINUATION_INTERFACE_FQ_NAME, ClassKind.INTERFACE) { klass -> klass.addTypeParameter("T", irBuiltIns.anyNType, Variance.IN_VARIANCE)