From 295fdc36cebe87198928680fa3e2dd12f8a1d8be Mon Sep 17 00:00:00 2001 From: Abduqodiri Qurbonzoda Date: Sun, 11 Jun 2023 03:14:37 +0300 Subject: [PATCH] Enum.valueOf throws inconsistent exception across multiple platforms #KT-35116 --- .../org/jetbrains/kotlin/backend/common/ir/Ir.kt | 3 +++ .../kotlin/ir/backend/js/JsIrBackendContext.kt | 6 +++--- .../ir/backend/js/lower/EnumClassLowering.kt | 6 ++++-- .../backend/js/lower/PropertyReferenceLowering.kt | 2 +- .../jetbrains/kotlin/backend/wasm/WasmSymbols.kt | 2 +- compiler/testData/codegen/box/enum/enumValueOf.kt | 15 ++++++++++++++- .../kotlin/js/translate/context/Namer.java | 2 +- .../js/translate/declaration/EnumTranslator.kt | 2 +- .../kotlin/kotlin/native/internal/RuntimeUtils.kt | 2 +- libraries/stdlib/js/src/kotlin/exceptionUtils.kt | 5 +++++ 10 files changed, 34 insertions(+), 11 deletions(-) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt index 7b6818bcc4d..a0f0e1ae29a 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt @@ -206,6 +206,9 @@ abstract class Symbols( open val throwISE: IrSimpleFunctionSymbol get() = error("throwISE is not implemented") + open val throwIAE: IrSimpleFunctionSymbol + get() = error("throwIAE is not implemented") + abstract val stringBuilder: IrClassSymbol abstract val defaultConstructorMarker: IrClassSymbol diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt index 35d8e2d3311..1b6a8dcbe7a 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt @@ -219,6 +219,9 @@ class JsIrBackendContext( override val throwISE: IrSimpleFunctionSymbol = symbolTable.referenceSimpleFunction(getFunctions(kotlinPackageFqn.child(Name.identifier("THROW_ISE"))).single()) + override val throwIAE: IrSimpleFunctionSymbol = + symbolTable.referenceSimpleFunction(getFunctions(kotlinPackageFqn.child(Name.identifier("THROW_IAE"))).single()) + override val stringBuilder get() = TODO("not implemented") override val coroutineImpl = @@ -325,9 +328,6 @@ class JsIrBackendContext( val setPropertiesToThrowableInstanceSymbol = symbolTable.referenceSimpleFunction(getJsInternalFunction("setPropertiesToThrowableInstance")) - val throwISEsymbol = symbolTable.referenceSimpleFunction(getFunctions(kotlinPackageFqn.child(Name.identifier("THROW_ISE"))).single()) - val throwIAEsymbol = symbolTable.referenceSimpleFunction(getFunctions(kotlinPackageFqn.child(Name.identifier("THROW_IAE"))).single()) - override val suiteFun = getFunctions(FqName("kotlin.test.suite")).singleOrNull()?.let { symbolTable.referenceSimpleFunction(it) } override val testFun = getFunctions(FqName("kotlin.test.test")).singleOrNull()?.let { symbolTable.referenceSimpleFunction(it) } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt index c20552377ba..942a861726f 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt @@ -501,7 +501,7 @@ class EnumSyntheticFunctionsAndPropertiesLowering( return null } - private val throwISESymbol = context.ir.symbols.throwISE + private val throwIAESymbol = context.ir.symbols.throwIAE private fun createEnumEntriesBody(entriesGetter: IrFunction, enumClass: IrClass): IrBlockBody { val entriesField = enumClass.buildEntriesField() @@ -548,7 +548,9 @@ class EnumSyntheticFunctionsAndPropertiesLowering( ) } memoryOptimizedPlus irElseBranch(irBlock { +irCall(irClass.initEntryInstancesFun!!) - +irCall(throwISESymbol) + +irCall(throwIAESymbol).apply { + putValueArgument(0, irString("No enum constant ${nameParameter.name.identifier}.")) + } }) ) } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PropertyReferenceLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PropertyReferenceLowering.kt index 83d86b92920..08b81cd4ecc 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PropertyReferenceLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PropertyReferenceLowering.kt @@ -32,7 +32,7 @@ class PropertyReferenceLowering(private val context: JsIrBackendContext) : BodyL private val localDelegateBuilderSymbol = context.klocalDelegateBuilder private val jsClassSymbol = context.intrinsics.jsClass - private val throwISE = context.throwISEsymbol + private val throwISE = context.ir.symbols.throwISE override fun lower(irBody: IrBody, container: IrDeclaration) { val currentParent = container as? IrDeclarationParent ?: container.parent diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt index bb9797d1849..6231a0e8aff 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt @@ -83,7 +83,7 @@ class WasmSymbols( override val throwNullPointerException = getInternalFunction("THROW_NPE") override val throwISE = getInternalFunction("THROW_ISE") override val throwTypeCastException = getInternalFunction("THROW_CCE") - val throwIAE = getInternalFunction("THROW_IAE") + override val throwIAE = getInternalFunction("THROW_IAE") val throwNoBranchMatchedException = getInternalFunction("throwNoBranchMatchedException") override val throwUninitializedPropertyAccessException = diff --git a/compiler/testData/codegen/box/enum/enumValueOf.kt b/compiler/testData/codegen/box/enum/enumValueOf.kt index 03f3923de88..8ff8d96a021 100644 --- a/compiler/testData/codegen/box/enum/enumValueOf.kt +++ b/compiler/testData/codegen/box/enum/enumValueOf.kt @@ -1,5 +1,18 @@ +// WITH_STDLIB + +import kotlin.test.assertSame +import kotlin.test.assertFailsWith + enum class E { OK } fun id(x: T) = x -fun box() = enumValueOf(id("OK")).name +fun box(): String { + assertSame(E.OK, E.valueOf("OK")) + assertSame(E.OK, enumValueOf("OK")) + + assertFailsWith { E.valueOf("NO") } + assertFailsWith { enumValueOf("NO") } + + return enumValueOf(id("OK")).name +} diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java index 18118f5c854..a1b105267c3 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java @@ -95,7 +95,7 @@ public final class Namer { public static final String ANOTHER_THIS_PARAMETER_NAME = "$this"; public static final String THROW_CLASS_CAST_EXCEPTION_FUN_NAME = "throwCCE"; - public static final String THROW_ILLEGAL_STATE_EXCEPTION_FUN_NAME = "throwISE"; + public static final String THROW_ILLEGAL_ARGUMENT_EXCEPTION_FUN_NAME = "throwIAE"; public static final String THROW_UNINITIALIZED_PROPERTY_ACCESS_EXCEPTION = "throwUPAE"; public static final String NULL_CHECK_INTRINSIC_NAME = "ensureNotNull"; private static final String PROTOTYPE_NAME = "prototype"; diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/EnumTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/EnumTranslator.kt index 4eddd449d92..a2525efe505 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/EnumTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/EnumTranslator.kt @@ -66,7 +66,7 @@ class EnumTranslator( val message = JsBinaryOperation(JsBinaryOperator.ADD, JsStringLiteral("No enum constant ${descriptor.fqNameSafe}."), nameParam.makeRef()) - val throwFunction = context().getReferenceToIntrinsic(Namer.THROW_ILLEGAL_STATE_EXCEPTION_FUN_NAME) + val throwFunction = context().getReferenceToIntrinsic(Namer.THROW_ILLEGAL_ARGUMENT_EXCEPTION_FUN_NAME) val throwStatement = JsExpressionStatement(JsInvocation(throwFunction, message).source(psi)) if (clauses.isNotEmpty()) { diff --git a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt index 80aa192fe11..08043289333 100644 --- a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt +++ b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt @@ -200,7 +200,7 @@ internal fun > valueOfForEnum(name: String, values: Array) : T { else -> return values[middle] } } - throw Exception("Invalid enum value name: $name") + throw IllegalArgumentException("Invalid enum value name: $name") } @PublishedApi diff --git a/libraries/stdlib/js/src/kotlin/exceptionUtils.kt b/libraries/stdlib/js/src/kotlin/exceptionUtils.kt index e0ef82cb556..19eee61fb56 100644 --- a/libraries/stdlib/js/src/kotlin/exceptionUtils.kt +++ b/libraries/stdlib/js/src/kotlin/exceptionUtils.kt @@ -20,6 +20,11 @@ internal fun throwISE(message: String) { throw IllegalStateException(message) } +@JsName("throwIAE") +internal fun throwIAE(message: String) { + throw IllegalArgumentException(message) +} + @JsName("throwUPAE") internal fun throwUPAE(propertyName: String) { throw UninitializedPropertyAccessException("lateinit property ${propertyName} has not been initialized")