JVM IR: replace unoverridden Number.toChar with toInt().toChar()
This fixes failing tests for JVM_IR in `box/primitiveTypes/numberToChar`. #KT-23447 Fixed #KT-46465
This commit is contained in:
committed by
Space Team
parent
a962ec4553
commit
e56e058b7b
+5
-9
@@ -162,8 +162,11 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
|
||||
private fun binaryOp(methodName: String, opcode: Int) = binaryFunForPrimitivesAcrossPrimitives(methodName, BinaryOp(opcode))
|
||||
|
||||
private fun numberConversionMethods(): List<Pair<Key, IntrinsicMethod>> =
|
||||
PrimitiveType.NUMBER_TYPES.flatMap { type -> numberConversionMethods(type.symbol) } +
|
||||
numberConversionMethods(irBuiltIns.numberClass)
|
||||
PrimitiveType.NUMBER_TYPES.flatMap { type ->
|
||||
OperatorConventions.NUMBER_CONVERSIONS.map { method ->
|
||||
createKeyMapping(NumberCast, type.symbol, method.asString())
|
||||
}
|
||||
}
|
||||
|
||||
private fun arrayMethods(): List<Pair<Key, IntrinsicMethod>> =
|
||||
symbols.primitiveArraysToPrimitiveTypes.flatMap { (array, primitiveType) -> arrayMethods(primitiveType.symbol, array) } +
|
||||
@@ -234,12 +237,5 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
|
||||
): Pair<Key, IntrinsicMethod> =
|
||||
Key(klass.owner.fqNameWhenAvailable!!, null, name, args.map { getParameterFqName(it) }) to
|
||||
intrinsic
|
||||
|
||||
private fun numberConversionMethods(numberClass: IrClassSymbol) =
|
||||
OperatorConventions.NUMBER_CONVERSIONS.map { method ->
|
||||
createKeyMapping(NumberCast, numberClass, method.asString())
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -444,6 +444,7 @@ private val jvmFilePhases = listOf(
|
||||
kotlinNothingValueExceptionPhase,
|
||||
makePropertyDelegateMethodsStaticPhase,
|
||||
addSuperQualifierToJavaFieldAccessPhase,
|
||||
replaceNumberToCharCallSitesPhase,
|
||||
|
||||
renameFieldsPhase,
|
||||
fakeInliningLocalVariablesLowering,
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.functionByName
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.types.isNumber
|
||||
import org.jetbrains.kotlin.ir.util.irCall
|
||||
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
|
||||
internal val replaceNumberToCharCallSitesPhase = makeIrFilePhase(
|
||||
::ReplaceNumberToCharCallSitesLowering,
|
||||
name = "ReplaceNumberToCharCallSites",
|
||||
description = "Replace `Number.toChar` call sites with `toInt().toChar()`",
|
||||
)
|
||||
|
||||
// This lowering replaces call sites of the form `x.toChar()` to `x.toInt().toChar()`, but only if the declaration of `toChar`
|
||||
// in the scope of `x` comes from the library class `kotlin.Number`. For example, if `x` is some `MyNumber` which overrides
|
||||
// `toChar`, we won't replace it because there might be some custom logic, different from `toInt().toChar()`.
|
||||
//
|
||||
// This allows us to migrate usages of deprecated `Number.toChar` less painfully in order to remove it in the future (KT-56822).
|
||||
// Also, this allows to invoke `toChar` on `Number` subclasses declared in Java, which do not have it declared, even though the
|
||||
// compiler sees it there because `java.lang.Number` is mapped to `kotlin.Number`.
|
||||
class ReplaceNumberToCharCallSitesLowering(val context: JvmBackendContext) : FileLoweringPass, IrElementTransformerVoid() {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
expression.transformChildrenVoid(this)
|
||||
|
||||
val callee = expression.symbol.owner
|
||||
if (callee.name != OperatorConventions.CHAR) return expression
|
||||
|
||||
val declaration = callee.resolveFakeOverride() ?: callee
|
||||
val declaringClassType = declaration.dispatchReceiverParameter?.type ?: return expression
|
||||
if (!declaringClassType.isNumber()) return expression
|
||||
|
||||
val dispatchReceiver = expression.dispatchReceiver ?: return expression
|
||||
expression.dispatchReceiver = IrCallImpl(
|
||||
dispatchReceiver.startOffset, dispatchReceiver.endOffset,
|
||||
context.irBuiltIns.intType, context.irBuiltIns.numberClass.functionByName("toInt"), 0, 0,
|
||||
).also { toInt ->
|
||||
toInt.dispatchReceiver = dispatchReceiver
|
||||
}
|
||||
|
||||
return irCall(expression, context.irBuiltIns.intClass.functionByName("toChar"))
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,9 @@
|
||||
// ISSUE: KT-23447
|
||||
// WITH_STDLIB
|
||||
|
||||
// IGNORE_BACKEND_K2: JVM_IR
|
||||
// Ignore reason: KT-57217
|
||||
|
||||
// FILE: MyNumber.java
|
||||
|
||||
public class MyNumber extends Number {
|
||||
|
||||
Reference in New Issue
Block a user