JVM IR: prevent behavior change with operator dot calls on literals
#KT-42321 Fixed
This commit is contained in:
+6
-7
@@ -5,7 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.utils
|
||||
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
object OperatorNames {
|
||||
@@ -21,12 +20,12 @@ object OperatorNames {
|
||||
|
||||
val AND = OperatorNameConventions.AND
|
||||
val OR = OperatorNameConventions.OR
|
||||
val XOR = Name.identifier("xor")
|
||||
val INV = Name.identifier("inv")
|
||||
val XOR = OperatorNameConventions.XOR
|
||||
val INV = OperatorNameConventions.INV
|
||||
|
||||
val SHL = Name.identifier("shl")
|
||||
val SHR = Name.identifier("shr")
|
||||
val SHRU = Name.identifier("ushr")
|
||||
val SHL = OperatorNameConventions.SHL
|
||||
val SHR = OperatorNameConventions.SHR
|
||||
val SHRU = OperatorNameConventions.USHR
|
||||
|
||||
val NOT = OperatorNameConventions.NOT
|
||||
|
||||
@@ -37,4 +36,4 @@ object OperatorNames {
|
||||
val BINARY = setOf(ADD, SUB, MUL, DIV, MOD, REM, AND, OR, XOR, SHL, SHR, SHRU)
|
||||
val UNARY = setOf(UNARY_PLUS, UNARY_MINUS, INV, NOT, INC, DEC)
|
||||
val ALL = BINARY + UNARY
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -160,6 +160,9 @@ class JvmGeneratorExtensionsImpl(private val generateFacades: Boolean = true) :
|
||||
)
|
||||
}
|
||||
|
||||
override val shouldPreventDeprecatedIntegerValueTypeLiteralConversion: Boolean
|
||||
get() = true
|
||||
|
||||
private val flexibleNullabilityAnnotationClass =
|
||||
createSpecialAnnotationClass(JvmSymbols.FLEXIBLE_NULLABILITY_ANNOTATION_FQ_NAME, kotlinIrInternalPackage)
|
||||
|
||||
|
||||
+3
-1
@@ -20,7 +20,6 @@ open class GeneratorExtensions : StubGeneratorExtensions() {
|
||||
get() = SamConversion
|
||||
|
||||
open class SamConversion {
|
||||
|
||||
open fun isPlatformSamType(type: KotlinType): Boolean = false
|
||||
|
||||
open fun getSamTypeForValueParameter(valueParameter: ValueParameterDescriptor): KotlinType? = null
|
||||
@@ -37,4 +36,7 @@ open class GeneratorExtensions : StubGeneratorExtensions() {
|
||||
descriptor: ClassDescriptor,
|
||||
context: GeneratorContext,
|
||||
): IrDelegatingConstructorCall? = null
|
||||
|
||||
open val shouldPreventDeprecatedIntegerValueTypeLiteralConversion: Boolean
|
||||
get() = false
|
||||
}
|
||||
|
||||
+44
-10
@@ -24,10 +24,8 @@ import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.PsiIrFileEntry
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBasedDeclarationDescriptor
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
@@ -35,33 +33,40 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.types.toKotlinType
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.ir.util.TypeTranslator
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
||||
import org.jetbrains.kotlin.psi2ir.containsNull
|
||||
import org.jetbrains.kotlin.psi2ir.findSingleFunction
|
||||
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
|
||||
import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions
|
||||
import org.jetbrains.kotlin.psi2ir.generators.OPERATORS_DESUGARED_TO_CALLS
|
||||
import org.jetbrains.kotlin.psi2ir.generators.getSubstitutedFunctionTypeForSamType
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.typeUtil.*
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
fun insertImplicitCasts(element: IrElement, context: GeneratorContext) {
|
||||
fun insertImplicitCasts(file: IrFile, context: GeneratorContext) {
|
||||
InsertImplicitCasts(
|
||||
context.builtIns,
|
||||
context.irBuiltIns,
|
||||
context.typeTranslator,
|
||||
context.callToSubstitutedDescriptorMap,
|
||||
context.extensions,
|
||||
context.symbolTable
|
||||
).run(element)
|
||||
context.symbolTable,
|
||||
file,
|
||||
).run(file)
|
||||
}
|
||||
|
||||
internal class InsertImplicitCasts(
|
||||
@@ -70,7 +75,8 @@ internal class InsertImplicitCasts(
|
||||
private val typeTranslator: TypeTranslator,
|
||||
private val callToSubstitutedDescriptorMap: Map<IrDeclarationReference, CallableDescriptor>,
|
||||
private val generatorExtensions: GeneratorExtensions,
|
||||
private val symbolTable: SymbolTable
|
||||
private val symbolTable: SymbolTable,
|
||||
private val file: IrFile,
|
||||
) : IrElementTransformerVoid() {
|
||||
|
||||
private val expectedFunctionExpressionReturnType = hashMapOf<FunctionDescriptor, IrType>()
|
||||
@@ -402,6 +408,11 @@ internal class InsertImplicitCasts(
|
||||
private fun IrExpression.coerceIntToAnotherIntegerType(targetType: KotlinType): IrExpression {
|
||||
if (!type.originalKotlinType!!.isInt()) throw AssertionError("Expression of type 'kotlin.Int' expected: $this")
|
||||
if (targetType.isInt()) return this
|
||||
|
||||
if (generatorExtensions.shouldPreventDeprecatedIntegerValueTypeLiteralConversion &&
|
||||
this is IrCall && preventDeprecatedIntegerValueTypeLiteralConversion()
|
||||
) return this
|
||||
|
||||
return if (this is IrConst<*>) {
|
||||
val value = this.value as Int
|
||||
val irType = targetType.toIrType()
|
||||
@@ -429,6 +440,29 @@ internal class InsertImplicitCasts(
|
||||
}
|
||||
}
|
||||
|
||||
// In JVM, we don't convert values resulted from calling built-in operators on integer literals to another integer type.
|
||||
// The reason is that doing so would change behavior, which we want to avoid, see KT-42321.
|
||||
// At the same time, such structure seems possible to achieve only via the magical integer value type, but inferring the result of
|
||||
// the operator call based on an expected type is deprecated behavior which is going to be removed in the future, see KT-38895.
|
||||
private fun IrCall.preventDeprecatedIntegerValueTypeLiteralConversion(): Boolean {
|
||||
val descriptor = symbol.descriptor
|
||||
if (descriptor.name !in operatorsWithDeprecatedIntegerValueTypeLiteralConversion) return false
|
||||
|
||||
// This bug is only reproducible for non-operator calls, for example "1.plus(2)", NOT "1 + 2".
|
||||
if (origin in OPERATORS_DESUGARED_TO_CALLS) return false
|
||||
|
||||
// For infix methods, this bug is only reproducible for non-infix calls, for example "1.shl(2)", NOT "1 shl 2".
|
||||
if (descriptor.isInfix) {
|
||||
if ((file.fileEntry as? PsiIrFileEntry)?.findPsiElement(this) is KtBinaryExpression) return false
|
||||
}
|
||||
|
||||
return descriptor.dispatchReceiverParameter?.type?.let { KotlinBuiltIns.isPrimitiveType(it) } == true
|
||||
}
|
||||
|
||||
private val operatorsWithDeprecatedIntegerValueTypeLiteralConversion = with(OperatorNameConventions) {
|
||||
setOf(PLUS, MINUS, TIMES, DIV, REM, UNARY_PLUS, UNARY_MINUS, SHL, SHR, USHR, AND, OR, XOR, INV)
|
||||
}
|
||||
|
||||
private fun IrExpression.invokeIntegerCoercionFunction(targetType: KotlinType, coercionFunName: String): IrExpression {
|
||||
val coercionFunction = builtIns.int.unsubstitutedMemberScope.findSingleFunction(Name.identifier(coercionFunName))
|
||||
return IrCallImpl(
|
||||
|
||||
Reference in New Issue
Block a user