ForLoopsLowering: Add support for unsigned progressions.
This commit is contained in:
committed by
Alexander Udalov
parent
9fdb1ff4f8
commit
03ef3724f4
@@ -64,9 +64,13 @@ open class BuiltinSymbolsBase(protected val irBuiltIns: IrBuiltIns, protected va
|
||||
)
|
||||
|
||||
private fun getClass(name: Name, vararg packageNameSegments: String = arrayOf("kotlin")): IrClassSymbol =
|
||||
symbolTable.referenceClass(
|
||||
builtInsPackage(*packageNameSegments).getContributedClassifier(name, NoLookupLocation.FROM_BACKEND) as ClassDescriptor
|
||||
)
|
||||
getClassOrNull(name, *packageNameSegments) ?: error("Class '$name' not found in package '${packageNameSegments.joinToString(".")}'")
|
||||
|
||||
private fun getClassOrNull(name: Name, vararg packageNameSegments: String = arrayOf("kotlin")): IrClassSymbol? =
|
||||
(builtInsPackage(*packageNameSegments).getContributedClassifier(
|
||||
name,
|
||||
NoLookupLocation.FROM_BACKEND
|
||||
) as? ClassDescriptor)?.let { symbolTable.referenceClass(it) }
|
||||
|
||||
/**
|
||||
* Use this table to reference external dependencies.
|
||||
@@ -89,11 +93,22 @@ open class BuiltinSymbolsBase(protected val irBuiltIns: IrBuiltIns, protected va
|
||||
.map { symbolTable.referenceFunction(it) }
|
||||
|
||||
private fun progression(name: String) = getClass(Name.identifier(name), "kotlin", "ranges")
|
||||
private fun progressionOrNull(name: String) = getClassOrNull(Name.identifier(name), "kotlin", "ranges")
|
||||
|
||||
// The "...OrNull" variants are used for unsigned (and progressions) because the minimal stdlib used in tests do not include those
|
||||
// those classes. It was not feasible to add them to the JS reduced runtime because all its transitive dependencies also need to be
|
||||
// added, which would include a lot of the full stdlib.
|
||||
open val uByte = getClassOrNull(Name.identifier("UByte"), "kotlin")
|
||||
open val uShort = getClassOrNull(Name.identifier("UShort"), "kotlin")
|
||||
open val uInt = getClassOrNull(Name.identifier("UInt"), "kotlin")
|
||||
open val uLong = getClassOrNull(Name.identifier("ULong"), "kotlin")
|
||||
val uIntProgression = progressionOrNull("UIntProgression")
|
||||
val uLongProgression = progressionOrNull("ULongProgression")
|
||||
|
||||
val charProgression = progression("CharProgression")
|
||||
val intProgression = progression("IntProgression")
|
||||
val longProgression = progression("LongProgression")
|
||||
val progressionClasses = listOf(charProgression, intProgression, longProgression)
|
||||
val progressionClasses = listOfNotNull(charProgression, intProgression, longProgression, uIntProgression, uLongProgression)
|
||||
val progressionClassesTypes = progressionClasses.map { it.descriptor.defaultType }.toSet()
|
||||
|
||||
val getProgressionLastElementByReturnType = builtInsPackage("kotlin", "internal")
|
||||
@@ -105,6 +120,18 @@ open class BuiltinSymbolsBase(protected val irBuiltIns: IrBuiltIns, protected va
|
||||
c to f
|
||||
}.toMap()
|
||||
|
||||
val toUIntByExtensionReceiver = builtInsPackage("kotlin").getContributedFunctions(
|
||||
Name.identifier("toUInt"),
|
||||
NoLookupLocation.FROM_BACKEND
|
||||
).filter { it.containingDeclaration !is BuiltInsPackageFragment && it.extensionReceiverParameter != null }
|
||||
.map { Pair(it.extensionReceiverParameter!!.type, symbolTable.referenceSimpleFunction(it)) }.toMap()
|
||||
|
||||
val toULongByExtensionReceiver = builtInsPackage("kotlin").getContributedFunctions(
|
||||
Name.identifier("toULong"),
|
||||
NoLookupLocation.FROM_BACKEND
|
||||
).filter { it.containingDeclaration !is BuiltInsPackageFragment && it.extensionReceiverParameter != null }
|
||||
.map { Pair(it.extensionReceiverParameter!!.type, symbolTable.referenceSimpleFunction(it)) }.toMap()
|
||||
|
||||
val any = symbolTable.referenceClass(builtIns.any)
|
||||
val unit = symbolTable.referenceClass(builtIns.unit)
|
||||
|
||||
|
||||
+1
-2
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.backend.common.lower.loops
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
@@ -238,7 +237,7 @@ private class RangeLoopTransformer(
|
||||
mainLoopVariable.endOffset,
|
||||
context.irBuiltIns.unitType,
|
||||
IrStatementOrigin.FOR_LOOP_NEXT,
|
||||
loopHeader.initializeIteration(mainLoopVariable, loopVariableComponents, symbols, this)
|
||||
loopHeader.initializeIteration(mainLoopVariable, loopVariableComponents, this)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+106
-41
@@ -14,46 +14,77 @@ import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.isSubtypeOfClass
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.functions
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
|
||||
// TODO: Handle withIndex()
|
||||
// TODO: Handle UIntProgression, ULongProgression
|
||||
|
||||
/** Represents a progression type in the Kotlin stdlib. */
|
||||
internal enum class ProgressionType(val elementCastFunctionName: Name, val stepCastFunctionName: Name) {
|
||||
internal enum class ProgressionType(
|
||||
private val elementCastFunctionName: Name,
|
||||
private val stepCastFunctionName: Name,
|
||||
val isLong: Boolean = false,
|
||||
val isUnsigned: Boolean = false
|
||||
) {
|
||||
INT_PROGRESSION(Name.identifier("toInt"), Name.identifier("toInt")),
|
||||
LONG_PROGRESSION(Name.identifier("toLong"), Name.identifier("toLong")),
|
||||
CHAR_PROGRESSION(Name.identifier("toChar"), Name.identifier("toInt"));
|
||||
LONG_PROGRESSION(Name.identifier("toLong"), Name.identifier("toLong"), isLong = true),
|
||||
CHAR_PROGRESSION(Name.identifier("toChar"), Name.identifier("toInt")),
|
||||
UINT_PROGRESSION(Name.identifier("toUInt"), Name.identifier("toInt"), isUnsigned = true),
|
||||
ULONG_PROGRESSION(Name.identifier("toULong"), Name.identifier("toLong"), isLong = true, isUnsigned = true);
|
||||
|
||||
/** Returns the [IrType] of the `first`/`last` properties and elements in the progression. */
|
||||
fun elementType(builtIns: IrBuiltIns): IrType = when (this) {
|
||||
INT_PROGRESSION -> builtIns.intType
|
||||
LONG_PROGRESSION -> builtIns.longType
|
||||
CHAR_PROGRESSION -> builtIns.charType
|
||||
fun elementType(symbols: Symbols<CommonBackendContext>): IrType = elementClassifier(symbols).defaultType
|
||||
|
||||
/** Returns the [IrClassSymbol] of the `first`/`last` properties and elements in the progression. */
|
||||
fun elementClassifier(symbols: Symbols<CommonBackendContext>): IrClassSymbol = when (this) {
|
||||
INT_PROGRESSION -> symbols.int
|
||||
LONG_PROGRESSION -> symbols.long
|
||||
CHAR_PROGRESSION -> symbols.char
|
||||
UINT_PROGRESSION -> symbols.uInt!!
|
||||
ULONG_PROGRESSION -> symbols.uLong!!
|
||||
}
|
||||
|
||||
/** Returns the [IrType] of the `step` property in the progression. */
|
||||
fun stepType(builtIns: IrBuiltIns): IrType = when (this) {
|
||||
INT_PROGRESSION, CHAR_PROGRESSION -> builtIns.intType
|
||||
LONG_PROGRESSION -> builtIns.longType
|
||||
INT_PROGRESSION, CHAR_PROGRESSION, UINT_PROGRESSION -> builtIns.intType
|
||||
LONG_PROGRESSION, ULONG_PROGRESSION -> builtIns.longType
|
||||
}
|
||||
|
||||
/** Returns the [IrClassSymbol] of the `step` property type constructor in the progression. */
|
||||
fun stepClassifier(builtIns: IrBuiltIns): IrClassSymbol = when(this) {
|
||||
INT_PROGRESSION, CHAR_PROGRESSION -> builtIns.intClass
|
||||
LONG_PROGRESSION -> builtIns.longClass
|
||||
INT_PROGRESSION, CHAR_PROGRESSION , UINT_PROGRESSION-> builtIns.intClass
|
||||
LONG_PROGRESSION, ULONG_PROGRESSION -> builtIns.longClass
|
||||
}
|
||||
|
||||
fun castElementIfNecessary(element: IrExpression, context: CommonBackendContext) =
|
||||
element.castIfNecessary(elementType(context.ir.symbols), elementCastFunctionName)
|
||||
|
||||
fun castStepIfNecessary(step: IrExpression, context: CommonBackendContext) =
|
||||
step.castIfNecessary(stepType(context.irBuiltIns), stepCastFunctionName)
|
||||
|
||||
private fun IrExpression.castIfNecessary(targetType: IrType, numberCastFunctionName: Name) =
|
||||
// This expression's type could be Nothing from an exception throw.
|
||||
if (type == targetType || type.isNothing()) {
|
||||
this
|
||||
} else {
|
||||
val castFun = type.getClass()!!.functions.single {
|
||||
it.name == numberCastFunctionName &&
|
||||
it.dispatchReceiverParameter != null && it.extensionReceiverParameter == null && it.valueParameters.isEmpty()
|
||||
}
|
||||
IrCallImpl(startOffset, endOffset, castFun.returnType, castFun.symbol)
|
||||
.apply { dispatchReceiver = this@castIfNecessary }
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun fromIrType(irType: IrType, symbols: Symbols<CommonBackendContext>): ProgressionType? = when {
|
||||
irType.isSubtypeOfClass(symbols.charProgression) -> CHAR_PROGRESSION
|
||||
irType.isSubtypeOfClass(symbols.intProgression) -> INT_PROGRESSION
|
||||
irType.isSubtypeOfClass(symbols.longProgression) -> LONG_PROGRESSION
|
||||
symbols.uIntProgression != null && irType.isSubtypeOfClass(symbols.uIntProgression) -> UINT_PROGRESSION
|
||||
symbols.uLongProgression != null && irType.isSubtypeOfClass(symbols.uLongProgression) -> ULONG_PROGRESSION
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
@@ -113,12 +144,18 @@ internal class ProgressionHeaderInfo(
|
||||
additionalNotEmptyCondition = additionalNotEmptyCondition
|
||||
) {
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
val canOverflow: Boolean by lazy {
|
||||
if (canOverflow != null) return@lazy canOverflow
|
||||
|
||||
// We can't determine the safe limit at compile-time if "step" is not const.
|
||||
val stepValueAsLong = step.constLongValue ?: return@lazy true
|
||||
|
||||
if (direction == ProgressionDirection.UNKNOWN) {
|
||||
// If we don't know the direction, we can't be sure which limit to use.
|
||||
return@lazy true
|
||||
}
|
||||
|
||||
// Induction variable can NOT overflow if "last" is const and is <= (MAX/MIN_VALUE - step) (depending on direction).
|
||||
//
|
||||
// Examples that can NOT overflow:
|
||||
@@ -137,26 +174,51 @@ internal class ProgressionHeaderInfo(
|
||||
// - `0..10 step someStep()` CAN overflow (we don't know the step and hence can't determine the safe limit)
|
||||
// - `0..someLast()` CAN overflow (we don't know the direction)
|
||||
// - `someProgression()` CAN overflow (we don't know the direction)
|
||||
val lastValueAsLong = last.constLongValue ?: return@lazy true // If "last" is not a const Number or Char.
|
||||
when (direction) {
|
||||
ProgressionDirection.UNKNOWN ->
|
||||
// If we don't know the direction, we can't be sure which limit to use.
|
||||
true
|
||||
ProgressionDirection.DECREASING -> {
|
||||
val constLimitAsLong = when (progressionType) {
|
||||
ProgressionType.INT_PROGRESSION -> Int.MIN_VALUE.toLong()
|
||||
ProgressionType.CHAR_PROGRESSION -> Char.MIN_VALUE.toLong()
|
||||
ProgressionType.LONG_PROGRESSION -> Long.MIN_VALUE
|
||||
|
||||
if (progressionType.isUnsigned) {
|
||||
// "step" is still signed for unsigned progressions.
|
||||
val lastValueAsULong = last.constLongValue?.toULong() ?: return@lazy true // If "last" is not a const Number or Char.
|
||||
when (direction) {
|
||||
ProgressionDirection.DECREASING -> {
|
||||
val constLimitAsULong = when (progressionType) {
|
||||
ProgressionType.UINT_PROGRESSION -> UInt.MIN_VALUE.toULong()
|
||||
ProgressionType.ULONG_PROGRESSION -> ULong.MIN_VALUE
|
||||
else -> error("Unexpected progression type")
|
||||
}
|
||||
lastValueAsULong < (constLimitAsULong - stepValueAsLong.toULong())
|
||||
}
|
||||
lastValueAsLong < (constLimitAsLong - stepValueAsLong)
|
||||
ProgressionDirection.INCREASING -> {
|
||||
val constLimitAsULong = when (progressionType) {
|
||||
ProgressionType.UINT_PROGRESSION -> UInt.MAX_VALUE.toULong()
|
||||
ProgressionType.ULONG_PROGRESSION -> ULong.MAX_VALUE
|
||||
else -> error("Unexpected progression type")
|
||||
}
|
||||
lastValueAsULong > (constLimitAsULong - stepValueAsLong.toULong())
|
||||
}
|
||||
else -> error("Unexpected progression direction")
|
||||
}
|
||||
ProgressionDirection.INCREASING -> {
|
||||
val constLimitAsLong = when (progressionType) {
|
||||
ProgressionType.INT_PROGRESSION -> Int.MAX_VALUE.toLong()
|
||||
ProgressionType.CHAR_PROGRESSION -> Char.MAX_VALUE.toLong()
|
||||
ProgressionType.LONG_PROGRESSION -> Long.MAX_VALUE
|
||||
} else {
|
||||
val lastValueAsLong = last.constLongValue ?: return@lazy true // If "last" is not a const Number or Char.
|
||||
when (direction) {
|
||||
ProgressionDirection.DECREASING -> {
|
||||
val constLimitAsLong = when (progressionType) {
|
||||
ProgressionType.INT_PROGRESSION -> Int.MIN_VALUE.toLong()
|
||||
ProgressionType.CHAR_PROGRESSION -> Char.MIN_VALUE.toLong()
|
||||
ProgressionType.LONG_PROGRESSION -> Long.MIN_VALUE
|
||||
else -> error("Unexpected progression type")
|
||||
}
|
||||
lastValueAsLong < (constLimitAsLong - stepValueAsLong)
|
||||
}
|
||||
lastValueAsLong > (constLimitAsLong - stepValueAsLong)
|
||||
ProgressionDirection.INCREASING -> {
|
||||
val constLimitAsLong = when (progressionType) {
|
||||
ProgressionType.INT_PROGRESSION -> Int.MAX_VALUE.toLong()
|
||||
ProgressionType.CHAR_PROGRESSION -> Char.MAX_VALUE.toLong()
|
||||
ProgressionType.LONG_PROGRESSION -> Long.MAX_VALUE
|
||||
else -> error("Unexpected progression type")
|
||||
}
|
||||
lastValueAsLong > (constLimitAsLong - stepValueAsLong)
|
||||
}
|
||||
else -> error("Unexpected progression direction")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -268,14 +330,17 @@ internal abstract class HeaderInfoBuilder(context: CommonBackendContext, private
|
||||
|
||||
private val symbols = context.ir.symbols
|
||||
|
||||
// TODO: Include unsigned types
|
||||
private val progressionElementTypes = listOf(
|
||||
context.irBuiltIns.byteType,
|
||||
context.irBuiltIns.shortType,
|
||||
context.irBuiltIns.intType,
|
||||
context.irBuiltIns.longType,
|
||||
context.irBuiltIns.charType
|
||||
)
|
||||
private val progressionElementTypes = listOfNotNull(
|
||||
symbols.byte,
|
||||
symbols.short,
|
||||
symbols.int,
|
||||
symbols.long,
|
||||
symbols.char,
|
||||
symbols.uByte,
|
||||
symbols.uShort,
|
||||
symbols.uInt,
|
||||
symbols.uLong
|
||||
).map { it.defaultType }
|
||||
|
||||
private val progressionHandlers = listOf(
|
||||
CollectionIndicesHandler(context),
|
||||
|
||||
+109
-65
@@ -6,7 +6,6 @@
|
||||
package org.jetbrains.kotlin.backend.common.lower.loops
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.ir.Symbols
|
||||
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irIfThen
|
||||
@@ -50,7 +49,6 @@ internal interface ForLoopHeader {
|
||||
fun initializeIteration(
|
||||
loopVariable: IrVariable?,
|
||||
loopVariableComponents: Map<Int, IrVariable>,
|
||||
symbols: Symbols<CommonBackendContext>,
|
||||
builder: DeclarationIrBuilder
|
||||
): List<IrStatement>
|
||||
|
||||
@@ -61,6 +59,7 @@ internal interface ForLoopHeader {
|
||||
internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
||||
protected val headerInfo: T,
|
||||
builder: DeclarationIrBuilder,
|
||||
context: CommonBackendContext,
|
||||
protected val isLastInclusive: Boolean
|
||||
) : ForLoopHeader {
|
||||
|
||||
@@ -68,16 +67,18 @@ internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
||||
|
||||
val inductionVariable: IrVariable
|
||||
val stepVariable: IrVariable
|
||||
val stepVariableForIncrement: IrVariable?
|
||||
protected val lastVariableIfCanCacheLast: IrVariable?
|
||||
protected val lastExpression: IrExpression
|
||||
// Always copy `lastExpression` is it may be used in multiple conditions.
|
||||
get() = field.deepCopyWithSymbols()
|
||||
|
||||
private val symbols = context.ir.symbols
|
||||
private val elementType: IrType
|
||||
|
||||
init {
|
||||
with(builder) {
|
||||
elementType = headerInfo.progressionType.elementType(context.irBuiltIns)
|
||||
elementType = headerInfo.progressionType.elementType(symbols)
|
||||
|
||||
// For this loop:
|
||||
//
|
||||
@@ -89,10 +90,7 @@ internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
||||
// In the above example, if first() is a Long and last() is an Int, this creates a
|
||||
// LongProgression so last() should be cast to a Long.
|
||||
inductionVariable = scope.createTemporaryVariable(
|
||||
headerInfo.first.castIfNecessary(
|
||||
elementType,
|
||||
headerInfo.progressionType.elementCastFunctionName
|
||||
),
|
||||
headerInfo.progressionType.castElementIfNecessary(headerInfo.first, context),
|
||||
nameHint = "inductionVariable",
|
||||
isMutable = true
|
||||
)
|
||||
@@ -101,12 +99,7 @@ internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
||||
// they are non-nullable (the frontend takes care about this). So we need to cast
|
||||
// them to non-nullable.
|
||||
// TODO: Confirm if casting to non-nullable is still necessary
|
||||
val last = ensureNotNullable(
|
||||
headerInfo.last.castIfNecessary(
|
||||
elementType,
|
||||
headerInfo.progressionType.elementCastFunctionName
|
||||
)
|
||||
)
|
||||
val last = ensureNotNullable(headerInfo.progressionType.castElementIfNecessary(headerInfo.last, context))
|
||||
|
||||
lastVariableIfCanCacheLast = if (headerInfo.canCacheLast) {
|
||||
scope.createTemporaryVariable(
|
||||
@@ -117,17 +110,29 @@ internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
||||
|
||||
lastExpression = if (headerInfo.canCacheLast) irGet(lastVariableIfCanCacheLast!!) else last
|
||||
|
||||
stepVariable = headerInfo.progressionType.stepType(context.irBuiltIns).let {
|
||||
stepVariable =
|
||||
scope.createTemporaryVariable(
|
||||
ensureNotNullable(
|
||||
headerInfo.step.castIfNecessary(
|
||||
it,
|
||||
headerInfo.progressionType.stepCastFunctionName
|
||||
)
|
||||
),
|
||||
ensureNotNullable(headerInfo.progressionType.castStepIfNecessary(headerInfo.step, context)),
|
||||
nameHint = "step",
|
||||
irType = it
|
||||
irType = headerInfo.progressionType.stepType(context.irBuiltIns)
|
||||
)
|
||||
|
||||
stepVariableForIncrement = when (headerInfo.progressionType) {
|
||||
ProgressionType.UINT_PROGRESSION -> {
|
||||
val castFun = context.ir.symbols.toUIntByExtensionReceiver.getValue(stepVariable.type.toKotlinType())
|
||||
scope.createTemporaryVariable(
|
||||
irCall(castFun).apply { extensionReceiver = irGet(stepVariable) },
|
||||
nameHint = "stepForIncrement"
|
||||
)
|
||||
}
|
||||
ProgressionType.ULONG_PROGRESSION -> {
|
||||
val castFun = context.ir.symbols.toULongByExtensionReceiver.getValue(stepVariable.type.toKotlinType())
|
||||
scope.createTemporaryVariable(
|
||||
irCall(castFun).apply { extensionReceiver = irGet(stepVariable) },
|
||||
nameHint = "stepForIncrement"
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,16 +147,17 @@ internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
||||
/** Statement used to increment the induction variable. */
|
||||
protected fun incrementInductionVariable(builder: DeclarationIrBuilder): IrStatement = with(builder) {
|
||||
// inductionVariable = inductionVariable + step
|
||||
val stepVariableToUse = stepVariableForIncrement ?: stepVariable
|
||||
val plusFun = elementType.getClass()!!.functions.single {
|
||||
it.name == OperatorNameConventions.PLUS &&
|
||||
it.valueParameters.size == 1 &&
|
||||
it.valueParameters[0].type == stepVariable.type
|
||||
it.valueParameters[0].type == stepVariableToUse.type
|
||||
}
|
||||
irSetVar(
|
||||
inductionVariable.symbol, irCallOp(
|
||||
plusFun.symbol, plusFun.returnType,
|
||||
irGet(inductionVariable),
|
||||
irGet(stepVariable)
|
||||
irGet(stepVariableToUse)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -160,25 +166,65 @@ internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
||||
with(builder) {
|
||||
val builtIns = context.irBuiltIns
|
||||
val progressionType = headerInfo.progressionType
|
||||
val progressionElementType = progressionType.elementType(builtIns)
|
||||
val compFun =
|
||||
if (isLastInclusive) builtIns.lessOrEqualFunByOperandType[progressionElementType.classifierOrFail]!!
|
||||
else builtIns.lessFunByOperandType[progressionElementType.classifierOrFail]!!
|
||||
val progressionElementType = progressionType.elementType(symbols)
|
||||
|
||||
// The default condition depends on the direction.
|
||||
when (headerInfo.direction) {
|
||||
ProgressionDirection.DECREASING ->
|
||||
// last <= inductionVar (use `<` if last is exclusive)
|
||||
irCall(compFun).apply {
|
||||
// `compareTo` must be used for UInt/ULong; they don't have intrinsic comparison operators.
|
||||
val intCompFun = if (isLastInclusive) {
|
||||
builtIns.lessOrEqualFunByOperandType.getValue(builtIns.intClass)
|
||||
} else {
|
||||
builtIns.lessFunByOperandType.getValue(builtIns.intClass)
|
||||
}
|
||||
val elementCompareToFun = progressionElementType.getClass()!!.functions.single {
|
||||
it.name == OperatorNameConventions.COMPARE_TO &&
|
||||
it.dispatchReceiverParameter != null && it.extensionReceiverParameter == null &&
|
||||
it.valueParameters.size == 1 && it.valueParameters[0].type == progressionElementType
|
||||
}
|
||||
|
||||
val elementCompFun =
|
||||
if (isLastInclusive) {
|
||||
builtIns.lessOrEqualFunByOperandType[progressionElementType.classifierOrFail]
|
||||
} else {
|
||||
builtIns.lessFunByOperandType[progressionElementType.classifierOrFail]
|
||||
}
|
||||
|
||||
fun conditionForDecreasing(): IrExpression =
|
||||
// last <= inductionVar (use `<` if last is exclusive)
|
||||
if (progressionType.isUnsigned) {
|
||||
irCall(intCompFun).apply {
|
||||
putValueArgument(0, irCall(elementCompareToFun).apply {
|
||||
dispatchReceiver = lastExpression
|
||||
putValueArgument(0, irGet(inductionVariable))
|
||||
})
|
||||
putValueArgument(1, irInt(0))
|
||||
}
|
||||
} else {
|
||||
irCall(elementCompFun!!).apply {
|
||||
putValueArgument(0, lastExpression)
|
||||
putValueArgument(1, irGet(inductionVariable))
|
||||
}
|
||||
ProgressionDirection.INCREASING ->
|
||||
// inductionVar <= last (use `<` if last is exclusive)
|
||||
irCall(compFun).apply {
|
||||
}
|
||||
|
||||
fun conditionForIncreasing(): IrExpression =
|
||||
// inductionVar <= last (use `<` if last is exclusive)
|
||||
if (progressionType.isUnsigned) {
|
||||
irCall(intCompFun).apply {
|
||||
putValueArgument(0, irCall(elementCompareToFun).apply {
|
||||
dispatchReceiver = irGet(inductionVariable)
|
||||
putValueArgument(0, lastExpression)
|
||||
})
|
||||
putValueArgument(1, irInt(0))
|
||||
}
|
||||
} else {
|
||||
irCall(elementCompFun!!).apply {
|
||||
putValueArgument(0, irGet(inductionVariable))
|
||||
putValueArgument(1, lastExpression)
|
||||
}
|
||||
}
|
||||
|
||||
// The default condition depends on the direction.
|
||||
when (headerInfo.direction) {
|
||||
ProgressionDirection.DECREASING -> conditionForDecreasing()
|
||||
ProgressionDirection.INCREASING -> conditionForIncreasing()
|
||||
ProgressionDirection.UNKNOWN -> {
|
||||
// If the direction is unknown, we check depending on the "step" value:
|
||||
// // (use `<` if last is exclusive)
|
||||
@@ -187,33 +233,31 @@ internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
||||
val isLong = progressionType == ProgressionType.LONG_PROGRESSION
|
||||
context.oror(
|
||||
context.andand(
|
||||
irCall(builtIns.greaterFunByOperandType[stepTypeClassifier]!!).apply {
|
||||
irCall(builtIns.greaterFunByOperandType.getValue(stepTypeClassifier)).apply {
|
||||
putValueArgument(0, irGet(stepVariable))
|
||||
putValueArgument(1, if (isLong) irLong(0) else irInt(0))
|
||||
putValueArgument(1, if (progressionType.isLong) irLong(0) else irInt(0))
|
||||
},
|
||||
irCall(compFun).apply {
|
||||
putValueArgument(0, irGet(inductionVariable))
|
||||
putValueArgument(1, lastExpression)
|
||||
}),
|
||||
conditionForIncreasing()
|
||||
),
|
||||
context.andand(
|
||||
irCall(builtIns.lessFunByOperandType[stepTypeClassifier]!!).apply {
|
||||
irCall(builtIns.lessFunByOperandType.getValue(stepTypeClassifier)).apply {
|
||||
putValueArgument(0, irGet(stepVariable))
|
||||
putValueArgument(1, if (isLong) irLong(0) else irInt(0))
|
||||
putValueArgument(1, if (progressionType.isLong) irLong(0) else irInt(0))
|
||||
},
|
||||
irCall(compFun).apply {
|
||||
putValueArgument(0, lastExpression)
|
||||
putValueArgument(1, irGet(inductionVariable))
|
||||
})
|
||||
conditionForDecreasing()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
internal class ProgressionLoopHeader(
|
||||
headerInfo: ProgressionHeaderInfo,
|
||||
builder: DeclarationIrBuilder
|
||||
) : NumericForLoopHeader<ProgressionHeaderInfo>(headerInfo, builder, isLastInclusive = true) {
|
||||
builder: DeclarationIrBuilder,
|
||||
context: CommonBackendContext
|
||||
) : NumericForLoopHeader<ProgressionHeaderInfo>(headerInfo, builder, context, isLastInclusive = true) {
|
||||
|
||||
// For this loop:
|
||||
//
|
||||
@@ -230,14 +274,14 @@ internal class ProgressionLoopHeader(
|
||||
else
|
||||
listOfNotNull(inductionVariable, lastVariableIfCanCacheLast)
|
||||
) +
|
||||
stepVariable
|
||||
listOfNotNull(stepVariable, stepVariableForIncrement)
|
||||
|
||||
private var loopVariable: IrVariable? = null
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
override fun initializeIteration(
|
||||
loopVariable: IrVariable?,
|
||||
loopVariableComponents: Map<Int, IrVariable>,
|
||||
symbols: Symbols<CommonBackendContext>,
|
||||
builder: DeclarationIrBuilder
|
||||
) =
|
||||
with(builder) {
|
||||
@@ -258,6 +302,7 @@ internal class ProgressionLoopHeader(
|
||||
listOfNotNull(loopVariable, incrementInductionVariable(this))
|
||||
}
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
override fun buildLoop(builder: DeclarationIrBuilder, oldLoop: IrLoop, newBody: IrExpression?) =
|
||||
with(builder) {
|
||||
val newLoop = if (headerInfo.canOverflow) {
|
||||
@@ -322,15 +367,16 @@ private class InitializerCallReplacer(symbolRemapper: SymbolRemapper, typeRemapp
|
||||
|
||||
internal class IndexedGetLoopHeader(
|
||||
headerInfo: IndexedGetHeaderInfo,
|
||||
builder: DeclarationIrBuilder
|
||||
) : NumericForLoopHeader<IndexedGetHeaderInfo>(headerInfo, builder, isLastInclusive = false) {
|
||||
builder: DeclarationIrBuilder,
|
||||
context: CommonBackendContext
|
||||
) : NumericForLoopHeader<IndexedGetHeaderInfo>(headerInfo, builder, context, isLastInclusive = false) {
|
||||
|
||||
override val loopInitStatements = listOfNotNull(headerInfo.objectVariable, inductionVariable, lastVariableIfCanCacheLast, stepVariable)
|
||||
override val loopInitStatements =
|
||||
listOfNotNull(headerInfo.objectVariable, inductionVariable, lastVariableIfCanCacheLast, stepVariable, stepVariableForIncrement)
|
||||
|
||||
override fun initializeIteration(
|
||||
loopVariable: IrVariable?,
|
||||
loopVariableComponents: Map<Int, IrVariable>,
|
||||
symbols: Symbols<CommonBackendContext>,
|
||||
builder: DeclarationIrBuilder
|
||||
) =
|
||||
with(builder) {
|
||||
@@ -371,7 +417,8 @@ internal class IndexedGetLoopHeader(
|
||||
|
||||
internal class WithIndexLoopHeader(
|
||||
headerInfo: WithIndexHeaderInfo,
|
||||
builder: DeclarationIrBuilder
|
||||
builder: DeclarationIrBuilder,
|
||||
context: CommonBackendContext
|
||||
) : ForLoopHeader {
|
||||
|
||||
private val nestedLoopHeader: ForLoopHeader
|
||||
@@ -384,8 +431,8 @@ internal class WithIndexLoopHeader(
|
||||
// To build the optimized/lowered `for` loop over a `withIndex()` call, we first need the header for the underlying iterable so
|
||||
// so that we know how to build the loop for that iterable. More info in comments in initializeIteration().
|
||||
nestedLoopHeader = when (val nestedInfo = headerInfo.nestedInfo) {
|
||||
is IndexedGetHeaderInfo -> IndexedGetLoopHeader(nestedInfo, this@with)
|
||||
is ProgressionHeaderInfo -> ProgressionLoopHeader(nestedInfo, this@with)
|
||||
is IndexedGetHeaderInfo -> IndexedGetLoopHeader(nestedInfo, this@with, context)
|
||||
is ProgressionHeaderInfo -> ProgressionLoopHeader(nestedInfo, this@with, context)
|
||||
is IterableHeaderInfo -> IterableLoopHeader(nestedInfo)
|
||||
is WithIndexHeaderInfo -> throw IllegalStateException("Nested WithIndexHeaderInfo not allowed for WithIndexLoopHeader")
|
||||
}
|
||||
@@ -409,7 +456,7 @@ internal class WithIndexLoopHeader(
|
||||
)
|
||||
ownsIndexVariable = true
|
||||
// `index++` during iteration initialization
|
||||
// TODO: MUSTDO: Check for overflow for Iterable and Sequence (call to checkIndexOverflow()).
|
||||
// TODO: KT-34665: Check for overflow for Iterable and Sequence (call to checkIndexOverflow()).
|
||||
val plusFun = indexVariable.type.getClass()!!.functions.first {
|
||||
it.name == OperatorNameConventions.PLUS &&
|
||||
it.valueParameters.size == 1 &&
|
||||
@@ -435,7 +482,6 @@ internal class WithIndexLoopHeader(
|
||||
override fun initializeIteration(
|
||||
loopVariable: IrVariable?,
|
||||
loopVariableComponents: Map<Int, IrVariable>,
|
||||
symbols: Symbols<CommonBackendContext>,
|
||||
builder: DeclarationIrBuilder
|
||||
) =
|
||||
with(builder) {
|
||||
@@ -508,7 +554,6 @@ internal class WithIndexLoopHeader(
|
||||
listOfNotNull(loopVariableComponents[1], incrementIndexStatement) + nestedLoopHeader.initializeIteration(
|
||||
loopVariableComponents[2],
|
||||
linkedMapOf(),
|
||||
symbols,
|
||||
builder
|
||||
)
|
||||
}
|
||||
@@ -528,7 +573,6 @@ internal class IterableLoopHeader(
|
||||
override fun initializeIteration(
|
||||
loopVariable: IrVariable?,
|
||||
loopVariableComponents: Map<Int, IrVariable>,
|
||||
symbols: Symbols<CommonBackendContext>,
|
||||
builder: DeclarationIrBuilder
|
||||
) =
|
||||
with(builder) {
|
||||
@@ -615,9 +659,9 @@ internal class HeaderProcessor(
|
||||
|
||||
val builder = context.createIrBuilder(scopeOwnerSymbol(), variable.startOffset, variable.endOffset)
|
||||
return when (headerInfo) {
|
||||
is IndexedGetHeaderInfo -> IndexedGetLoopHeader(headerInfo, builder)
|
||||
is ProgressionHeaderInfo -> ProgressionLoopHeader(headerInfo, builder)
|
||||
is WithIndexHeaderInfo -> WithIndexLoopHeader(headerInfo, builder)
|
||||
is IndexedGetHeaderInfo -> IndexedGetLoopHeader(headerInfo, builder, context)
|
||||
is ProgressionHeaderInfo -> ProgressionLoopHeader(headerInfo, builder, context)
|
||||
is WithIndexHeaderInfo -> WithIndexLoopHeader(headerInfo, builder, context)
|
||||
is IterableHeaderInfo -> IterableLoopHeader(headerInfo)
|
||||
}
|
||||
}
|
||||
|
||||
+60
-29
@@ -17,10 +17,12 @@ import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.types.asSimpleType
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
@@ -73,12 +75,19 @@ internal class DownToHandler(private val context: CommonBackendContext, private
|
||||
internal class UntilHandler(private val context: CommonBackendContext, private val progressionElementTypes: Collection<IrType>) :
|
||||
ProgressionHandler {
|
||||
|
||||
private val symbols = context.ir.symbols
|
||||
private val uByteType = symbols.uByte?.defaultType
|
||||
private val uShortType = symbols.uShort?.defaultType
|
||||
private val uIntType = symbols.uInt?.defaultType
|
||||
private val uLongType = symbols.uLong?.defaultType
|
||||
|
||||
override val matcher = SimpleCalleeMatcher {
|
||||
singleArgumentExtension(FqName("kotlin.ranges.until"), progressionElementTypes)
|
||||
parameterCount { it == 1 }
|
||||
parameter(0) { it.type in progressionElementTypes }
|
||||
}
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
override fun build(expression: IrCall, data: ProgressionType, scopeOwner: IrSymbol): HeaderInfo? =
|
||||
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
|
||||
// `A until B` is essentially the same as `A .. (B-1)`. However, B could be MIN_VALUE and hence `(B-1)` could underflow.
|
||||
@@ -121,10 +130,7 @@ internal class UntilHandler(private val context: CommonBackendContext, private v
|
||||
val untilArg = expression.getValueArgument(0)!!
|
||||
|
||||
// Ensure that the argument conforms to the progression type before we decrement.
|
||||
val untilArgCasted = untilArg.castIfNecessary(
|
||||
data.elementType(context.irBuiltIns),
|
||||
data.elementCastFunctionName
|
||||
)
|
||||
val untilArgCasted = data.castElementIfNecessary(untilArg, this@UntilHandler.context)
|
||||
|
||||
// To reduce local variable usage, we create and use temporary variables only if necessary.
|
||||
var receiverValueVar: IrVariable? = null
|
||||
@@ -147,6 +153,24 @@ internal class UntilHandler(private val context: CommonBackendContext, private v
|
||||
ProgressionType.INT_PROGRESSION -> Pair(Int.MIN_VALUE.toLong(), irInt(Int.MIN_VALUE))
|
||||
ProgressionType.CHAR_PROGRESSION -> Pair(Char.MIN_VALUE.toLong(), irChar(Char.MIN_VALUE))
|
||||
ProgressionType.LONG_PROGRESSION -> Pair(Long.MIN_VALUE, irLong(Long.MIN_VALUE))
|
||||
ProgressionType.UINT_PROGRESSION -> Pair(
|
||||
UInt.MIN_VALUE.toLong(),
|
||||
IrConstImpl.int(
|
||||
startOffset,
|
||||
endOffset,
|
||||
symbols.uInt!!.defaultType,
|
||||
UInt.MIN_VALUE.toInt()
|
||||
)
|
||||
)
|
||||
ProgressionType.ULONG_PROGRESSION -> Pair(
|
||||
ULong.MIN_VALUE.toLong(),
|
||||
IrConstImpl.long(
|
||||
startOffset,
|
||||
endOffset,
|
||||
symbols.uLong!!.defaultType,
|
||||
ULong.MIN_VALUE.toLong()
|
||||
)
|
||||
)
|
||||
}
|
||||
val additionalNotEmptyCondition = untilArg.constLongValue.let {
|
||||
when {
|
||||
@@ -197,11 +221,14 @@ internal class UntilHandler(private val context: CommonBackendContext, private v
|
||||
// infix fun Long.until(to: Short): LongRange
|
||||
// infix fun Long.until(to: Int): LongRange
|
||||
// infix fun Long.until(to: Long): LongRange
|
||||
// infix fun UByte.until(to: UByte): UIntRange
|
||||
// infix fun UShort.until(to: UShort): UIntRange
|
||||
// infix fun UInt.until(to: UInt): UIntRange
|
||||
// infix fun ULong.until(to: ULong): ULongRange
|
||||
//
|
||||
// The combinations where the range element type is strictly larger than the argument type do NOT need the additional condition.
|
||||
// In such combinations, there is no possibility of underflow when the argument (casted to the range element type) is decremented.
|
||||
// For unexpected combinations that currently don't exist (e.g., Int until Char), we assume the check is needed to be safe.
|
||||
// TODO: Include unsigned types
|
||||
return with(context.irBuiltIns) {
|
||||
when (receiverType) {
|
||||
charType -> true
|
||||
@@ -213,7 +240,11 @@ internal class UntilHandler(private val context: CommonBackendContext, private v
|
||||
byteType, shortType, intType -> false
|
||||
else -> true
|
||||
}
|
||||
else -> true
|
||||
uByteType -> false
|
||||
uShortType -> false
|
||||
uIntType -> true
|
||||
uLongType -> true
|
||||
else -> true // Default in case a new `until` overload is added to stdlib and this function was not updated.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -258,7 +289,7 @@ internal class StepHandler(
|
||||
// We insert this check in the lowered form only if necessary.
|
||||
val stepType = data.stepType(context.irBuiltIns)
|
||||
val stepGreaterFun = context.irBuiltIns.greaterFunByOperandType[data.stepClassifier(context.irBuiltIns)]!!
|
||||
val zeroStep = if (data == ProgressionType.LONG_PROGRESSION) irLong(0) else irInt(0)
|
||||
val zeroStep = if (data.isLong) irLong(0) else irInt(0)
|
||||
val throwIllegalStepExceptionCall = {
|
||||
irCall(context.irBuiltIns.illegalArgumentExceptionSymbol).apply {
|
||||
val exceptionMessage = irConcat()
|
||||
@@ -458,29 +489,29 @@ internal class StepHandler(
|
||||
return last
|
||||
}
|
||||
|
||||
// Call `getProgressionLastElement(first, last, step)`
|
||||
val stepTypeClassifier = progressionType.stepClassifier(context.irBuiltIns)
|
||||
val getProgressionLastElementFun = symbols.getProgressionLastElementByReturnType[stepTypeClassifier]
|
||||
?: throw IllegalArgumentException("No `getProgressionLastElement` for step type $stepTypeClassifier")
|
||||
// Call `getProgressionLastElement(first, last, step)`. The following overloads are present in the stdlib:
|
||||
// - getProgressionLastElement(Int, Int, Int): Int // Used by IntProgression and CharProgression (uses Int step)
|
||||
// - getProgressionLastElement(Long, Long, Long): Long // Used by LongProgression
|
||||
// - getProgressionLastElement(UInt, UInt, Int): UInt // Used by UIntProgression (uses Int step)
|
||||
// - getProgressionLastElement(ULong, ULong, Long): ULong // Used by ULongProgression (uses Long step)
|
||||
//
|
||||
// We make sure to retrieve the correct symbol and use the correct argument types.
|
||||
val returnTypeClassifier = if (progressionType.isUnsigned) {
|
||||
progressionType.elementClassifier(symbols)
|
||||
} else {
|
||||
progressionType.stepClassifier(context.irBuiltIns)
|
||||
}
|
||||
val getProgressionLastElementFun = symbols.getProgressionLastElementByReturnType[returnTypeClassifier]
|
||||
?: throw IllegalArgumentException("No `getProgressionLastElement` for return type ${returnTypeClassifier.defaultType}")
|
||||
return irCall(getProgressionLastElementFun).apply {
|
||||
putValueArgument(
|
||||
0, first.deepCopyWithSymbols().castIfNecessary(
|
||||
progressionType.stepType(context.irBuiltIns),
|
||||
progressionType.stepCastFunctionName
|
||||
)
|
||||
)
|
||||
putValueArgument(
|
||||
1, last.deepCopyWithSymbols().castIfNecessary(
|
||||
progressionType.stepType(context.irBuiltIns),
|
||||
progressionType.stepCastFunctionName
|
||||
)
|
||||
)
|
||||
putValueArgument(
|
||||
2, step.deepCopyWithSymbols().castIfNecessary(
|
||||
progressionType.stepType(context.irBuiltIns),
|
||||
progressionType.stepCastFunctionName
|
||||
)
|
||||
)
|
||||
if (progressionType.isUnsigned) {
|
||||
putValueArgument(0, progressionType.castElementIfNecessary(first.deepCopyWithSymbols(), this@StepHandler.context))
|
||||
putValueArgument(1, progressionType.castElementIfNecessary(last.deepCopyWithSymbols(), this@StepHandler.context))
|
||||
} else {
|
||||
putValueArgument(0, progressionType.castStepIfNecessary(first.deepCopyWithSymbols(), this@StepHandler.context))
|
||||
putValueArgument(1, progressionType.castStepIfNecessary(last.deepCopyWithSymbols(), this@StepHandler.context))
|
||||
}
|
||||
putValueArgument(2, progressionType.castStepIfNecessary(step.deepCopyWithSymbols(), this@StepHandler.context))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-13
@@ -14,24 +14,11 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrGetValue
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.getClass
|
||||
import org.jetbrains.kotlin.ir.types.isNothing
|
||||
import org.jetbrains.kotlin.ir.util.functions
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
internal fun IrExpression.castIfNecessary(targetType: IrType, numberCastFunctionName: Name): IrExpression {
|
||||
// This expression's type could be Nothing from an exception throw.
|
||||
return if (type == targetType || type.isNothing()) {
|
||||
this
|
||||
} else {
|
||||
val castFun = type.getClass()!!.functions.single { it.name == numberCastFunctionName && it.valueParameters.isEmpty() }
|
||||
IrCallImpl(startOffset, endOffset, castFun.returnType, castFun.symbol)
|
||||
.apply { dispatchReceiver = this@castIfNecessary }
|
||||
}
|
||||
}
|
||||
|
||||
/** Return the negated value if the expression is const, otherwise call unaryMinus(). */
|
||||
internal fun IrExpression.negate(): IrExpression {
|
||||
return when (val value = (this as? IrConst<*>)?.value as? Number) {
|
||||
|
||||
@@ -299,6 +299,7 @@ private val jvmFilePhases =
|
||||
anonymousObjectSuperConstructorPhase then
|
||||
tailrecPhase then
|
||||
|
||||
forLoopsPhase then
|
||||
jvmInlineClassPhase then
|
||||
|
||||
sharedVariablesPhase then
|
||||
@@ -318,7 +319,6 @@ private val jvmFilePhases =
|
||||
|
||||
jvmDefaultConstructorPhase then
|
||||
|
||||
forLoopsPhase then
|
||||
flattenStringConcatenationPhase then
|
||||
foldConstantLoweringPhase then
|
||||
computeStringTrimPhase then
|
||||
|
||||
+4
-1
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.common.ir.copyParameterDeclarationsFrom
|
||||
import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
|
||||
import org.jetbrains.kotlin.backend.common.lower.loops.forLoopsPhase
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
@@ -42,7 +43,9 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
val jvmInlineClassPhase = makeIrFilePhase(
|
||||
::JvmInlineClassLowering,
|
||||
name = "Inline Classes",
|
||||
description = "Lower inline classes"
|
||||
description = "Lower inline classes",
|
||||
// forLoopsPhase may produce UInt and ULong which are inline classes.
|
||||
prerequisite = setOf(forLoopsPhase)
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
+1
-2
@@ -1,5 +1,4 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TODO KT-36773 Use counter loop when generating 'for' loop over an unsigned range in JVM_IR
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun testUIntRangeLiteral(a: UInt, b: UInt): Int {
|
||||
var s = 0
|
||||
|
||||
Reference in New Issue
Block a user