Initial version of RangeContainsLowering, which optimizes calls to

contains() on ClosedRanges.
This commit is contained in:
Mark Punzalan
2020-08-04 23:44:04 -07:00
committed by Alexander Udalov
parent ca541337d1
commit 1c1b1b4b0f
36 changed files with 1194 additions and 57 deletions
@@ -20679,11 +20679,36 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForDownTo.kt");
}
@TestMetadata("evaluationOrderForDownToReversed.kt")
public void testEvaluationOrderForDownToReversed() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForDownToReversed.kt");
}
@TestMetadata("evaluationOrderForNullableArgument.kt")
public void testEvaluationOrderForNullableArgument() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForNullableArgument.kt");
}
@TestMetadata("evaluationOrderForRangeLiteral.kt")
public void testEvaluationOrderForRangeLiteral() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForRangeLiteral.kt");
}
@TestMetadata("evaluationOrderForRangeLiteralReversed.kt")
public void testEvaluationOrderForRangeLiteralReversed() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForRangeLiteralReversed.kt");
}
@TestMetadata("evaluationOrderForUntil.kt")
public void testEvaluationOrderForUntil() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntil.kt");
}
@TestMetadata("evaluationOrderForUntilReversed.kt")
public void testEvaluationOrderForUntilReversed() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntilReversed.kt");
}
@TestMetadata("genericCharInRangeLiteral.kt")
public void testGenericCharInRangeLiteral() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/genericCharInRangeLiteral.kt");
@@ -20799,6 +20824,21 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/ranges/contains/inUntil.kt");
}
@TestMetadata("inUntilMaxValue.kt")
public void testInUntilMaxValue() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/inUntilMaxValue.kt");
}
@TestMetadata("inUntilMinValue.kt")
public void testInUntilMinValue() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/inUntilMinValue.kt");
}
@TestMetadata("inUntilMinValueNonConst.kt")
public void testInUntilMinValueNonConst() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/inUntilMinValueNonConst.kt");
}
@TestMetadata("kt20106.kt")
public void testKt20106() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/kt20106.kt");
@@ -118,6 +118,8 @@ open class BuiltinSymbolsBase(protected val irBuiltIns: IrBuiltIns, protected va
val longRange = progression("LongRange")
val rangeClasses = listOfNotNull(charRange, intRange, longRange, uIntRange, uLongRange)
val closedRange = progression("ClosedRange")
val getProgressionLastElementByReturnType = builtInsPackage("kotlin", "internal")
.getContributedFunctions(Name.identifier("getProgressionLastElement"), NoLookupLocation.FROM_BACKEND)
.filter { it.containingDeclaration !is BuiltInsPackageFragment }
@@ -156,6 +158,8 @@ open class BuiltinSymbolsBase(protected val irBuiltIns: IrBuiltIns, protected va
val short = symbolTable.referenceClass(builtIns.short)
val int = symbolTable.referenceClass(builtIns.int)
val long = symbolTable.referenceClass(builtIns.long)
val float = symbolTable.referenceClass(builtIns.float)
val double = symbolTable.referenceClass(builtIns.double)
val integerClasses = listOf(byte, short, int, long)
@@ -0,0 +1,401 @@
/*
* Copyright 2010-2020 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.common.lower
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.ir.Symbols
import org.jetbrains.kotlin.backend.common.lower.loops.*
import org.jetbrains.kotlin.backend.common.lower.loops.handlers.*
import org.jetbrains.kotlin.backend.common.lower.matchers.SimpleCalleeMatcher
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.andand
import org.jetbrains.kotlin.ir.builders.irBlock
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.irInt
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner
import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.ir.util.functions
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addIfNotNull
// TODO:
// 1. Handle (kotlin.ranges.)ClosedRange.contains on (kotlin.ranges.)Comparable.rangeTo(Comparable).
// Make sure right extension function was called!
// 2. Handle contains on ClosedFloatingPointRange non-literal expression (similar to DefaultProgressionHandler)
// 3. Note for unsigned until, the decremented last is signed (see UntilHandler.kt:81). Rather than converting back to unsigned,
// should we remove the conversion call instead?
// 4. Unsigned step has similar concerns as well. getProgressionLastElement return value is signed.
val rangeContainsLoweringPhase = makeIrFilePhase(
::RangeContainsLowering,
name = "RangeContainsLowering",
description = "Optimizes calls to contains() for ClosedRanges"
)
/**
* This lowering pass optimizes calls to contains() (`in` operator) for ClosedRanges.
*
* For example, the expression `X in A..B` is transformed into `A <= X && X <= B`.
*/
class RangeContainsLowering(val context: CommonBackendContext) : BodyLoweringPass {
override fun lower(irBody: IrBody, container: IrDeclaration) {
val transformer = Transformer(context, container as IrSymbolOwner)
irBody.transformChildrenVoid(transformer)
}
}
private class Transformer(
val context: CommonBackendContext,
val container: IrSymbolOwner
) : IrElementTransformerVoidWithContext() {
private val headerInfoBuilder = RangeHeaderInfoBuilder(context, this::getScopeOwnerSymbol)
fun getScopeOwnerSymbol() = currentScope?.scope?.scopeOwnerSymbol ?: container.symbol
val stdlibExtensionContainsCallMatcher = SimpleCalleeMatcher {
extensionReceiver { it != null && it.type.isSubtypeOfClass(context.ir.symbols.closedRange) }
fqName { it == FqName("kotlin.ranges.${OperatorNameConventions.CONTAINS}") }
parameterCount { it == 1 }
}
override fun visitCall(expression: IrCall): IrExpression {
// The call to contains() in `5 in 0..10` has origin=IN:
//
// CALL 'public open fun contains (value: kotlin.Int): kotlin.Boolean [operator] declared in kotlin.ranges.IntRange' type=kotlin.Boolean origin=IN
//
// And when `!in` is used in `5 !in 0..10`, _both_ the not() and contains() calls have origin=NOT_IN:
//
// CALL 'public final fun not (): kotlin.Boolean [operator] declared in kotlin.Boolean' type=kotlin.Boolean origin=NOT_IN
// $this: CALL 'public open fun contains (value: kotlin.Int): kotlin.Boolean [operator] declared in kotlin.ranges.IntRange' type=kotlin.Boolean origin=NOT_IN
//
// We only want to lower the call to contains(); in the `!in` case, the call to not() should be preserved.
val origin = expression.origin
if (origin != IrStatementOrigin.IN && origin != IrStatementOrigin.NOT_IN) {
return super.visitCall(expression) // The call is not an `in` expression.
}
if (origin == IrStatementOrigin.NOT_IN && expression.symbol == context.irBuiltIns.booleanNotSymbol) {
return super.visitCall(expression) // Preserve the call to not().
}
if (expression.extensionReceiver != null && !stdlibExtensionContainsCallMatcher(expression)) {
// We can only optimize calls to the stdlib extension functions and not a user-defined extension.
// TODO: This breaks the optimization for *Range.reversed().contains(). The function called there is the extension function
// Iterable.contains(). Figure out if we can safely match on that as well.
return super.visitCall(expression)
}
// The HeaderInfoBuilder extracts information (e.g., lower/upper bounds, direction) from the range expression, which is the
// receiver for the contains() call.
val receiver = expression.dispatchReceiver ?: expression.extensionReceiver!!
val headerInfo = receiver.accept(headerInfoBuilder, expression)
?: return super.visitCall(expression) // The receiver is not a supported range (or not a range at all).
val argument = expression.getValueArgument(0)!!
if (argument.type.isNullable()) {
// There are stdlib extension functions that return false for null arguments, e.g., IntRange.contains(Int?). We currently
// do not optimize such calls.
return super.visitCall(expression)
}
val builder = context.createIrBuilder(getScopeOwnerSymbol(), expression.startOffset, expression.endOffset)
return builder.buildContainsComparison(headerInfo, argument, origin) ?: super.visitCall(expression) // The call cannot be lowered.
}
private fun DeclarationIrBuilder.buildContainsComparison(
headerInfo: HeaderInfo,
argument: IrExpression,
origin: IrStatementOrigin
): IrExpression? {
// If the lower bound of the range is A, the upper bound is B, and the argument is X, the contains() call is generally transformed
// into `A <= X && X <= B`. However, when any of these expressions (A/B/X) can have side-effects, they must resolve in the order
// in the expression. E.g., for `X in A..B` the order is A -> B -> X (the equivalent call is `(A..B).contains(X)`), and for
// `X in B downTo A` the order is B -> A -> X (the equivalent call is `(B.downTo(A)).contains(X)`).
// Therefore, we need to know in which order the expressions appear in the contains() expression. `shouldUpperComeFirst` is true
// when the expression or variable for `B` (upper) should appear in the lowered IR before `A` (lower).
val lower: IrExpression
val upper: IrExpression
val shouldUpperComeFirst: Boolean
val useCompareTo: Boolean
val additionalNotEmptyCondition: IrExpression?
val additionalStatements = mutableListOf<IrStatement>()
when (headerInfo) {
is NumericHeaderInfo -> {
when (headerInfo) {
is ProgressionHeaderInfo -> {
additionalStatements.addAll(headerInfo.additionalStatements)
}
// None of the handlers in RangeHeaderInfoBuilder should return a IndexedGetHeaderInfo (those are only for loops).
is IndexedGetHeaderInfo -> error("Unexpected IndexedGetHeaderInfo returned by RangeHeaderInfoBuilder")
}
// TODO: Optimize contains() for progressions with |step| > 1 or unknown step and/or direction. These are also not optimized
// in the old JVM backend. contains(x) for a stepped progression returns true if it is one of the elements/steps in the
// progression. e.g., `4 in 0..10 step 2` is true, and `3 in 0..10 step 2` is false. This requires an additional condition
// with a modulo.
when (headerInfo.direction) {
ProgressionDirection.INCREASING -> {
if (headerInfo.step.constLongValue != 1L) return null
// There are 2 cases for an optimizable range with INCREASING direction:
// 1. `X in A..B`:
// Produces HeaderInfo with first = A, last = B, isReversed = false (`first/A` is lower).
// Expression for `lower/A` should come first.
// 2. `X in (B downTo A).reversed()`:
// Produces HeaderInfo with first = A, last = B, isReversed = true (`first/A` is lower).
// Expression for `upper/B` should come first.
lower = headerInfo.first
upper = headerInfo.last
shouldUpperComeFirst = headerInfo.isReversed
}
ProgressionDirection.DECREASING -> {
if (headerInfo.step.constLongValue != -1L) return null
// There are 2 cases for an optimizable range with DECREASING direction:
// 1. `X in B downTo A`:
// Produces HeaderInfo with first = B, last = A, isReversed = false (`last/A` is lower).
// Expression for `upper/B` should come first.
// 2. `X in (A..B).reversed()`:
// Produces HeaderInfo with first = B, last = A, isReversed = true (`last/A` is lower).
// Expression for `lower/A` should come first.
lower = headerInfo.last
upper = headerInfo.first
shouldUpperComeFirst = !headerInfo.isReversed
}
ProgressionDirection.UNKNOWN -> return null
}
// `compareTo` must be used for UInt/ULong; they don't have intrinsic comparison operators.
useCompareTo = headerInfo.progressionType is UnsignedProgressionType
additionalNotEmptyCondition = headerInfo.additionalNotEmptyCondition
}
is FloatingPointRangeHeaderInfo -> {
lower = headerInfo.start
upper = headerInfo.endInclusive
shouldUpperComeFirst = false
useCompareTo = false
additionalNotEmptyCondition = null
}
else -> return null
}
// The transformed expression is `A <= X && X <= B`. If the argument expression X can have side effects, it must be stored in a
// temp variable before the expression so it does not get evaluated twice. If A and/or B can have side effects, they must also be
// stored in temp variables BEFORE X.
//
// On the other hand, if X can NOT have side effects, it does NOT need to be stored in a temp variable. However, because of
// short-circuit evaluation of &&, if A and/or B can have side effects, we need to make sure they get evaluated regardless.
// We accomplish this be storing it in a temp variable (the alternative is to duplicate A/B in a block in the "else" branch before
// returning false). We can also switch the order of the clauses to ensure evaluation. See below for the expected outcomes:
//
// =======|=======|=======|======================|================|=======================
// Can have side effects? | (Note B is "upper") | |
// X | A | B | shouldUpperComeFirst | Temp var order | Transformed expression
// =======|=======|=======|======================|================|=======================
// True | True | True | False | A -> B -> X | A <= X && X <= B *
// True | True | True | True | B -> A -> X | A <= X && X <= B *
// True | True | False | False/True | A -> X | A <= X && X <= B *
// True | False | True | False/True | B -> X | A <= X && X <= B *
// True | False | False | False/True | X | A <= X && X <= B *
// -------|-------|-------|----------------------|----------------|-----------------------
// False | True | True | False | A ** | X <= B && A <= X ***
// False | True | True | True | B ** | A <= X && X <= B ***
// False | True | False | False/True | [None] | A <= X && X <= B ***
// False | False | True | False/True | [None] | X <= B && A <= X ***
// False | False | False | False/True | [None] | A <= X && X <= B *
// =======|=======|=======|======================|================|=======================
//
// * - Order does not matter.
// ** - Bound with side effect is stored in a temp variable to ensure evaluation even if right side is short-circuited.
// *** - Bound with side effect is on left side of && to make sure it always gets evaluated.
val (argVar, argExpression) = createTemporaryVariableIfNecessary(argument, "containsArg")
val lowerExpression: IrExpression
val upperExpression: IrExpression
val useLowerClauseOnLeftSide: Boolean
if (argVar != null) {
val (lowerVar, tmpLowerExpression) = createTemporaryVariableIfNecessary(lower, "containsLower")
val (upperVar, tmpUpperExpression) = createTemporaryVariableIfNecessary(upper, "containsUpper")
if (shouldUpperComeFirst) {
additionalStatements.addIfNotNull(upperVar)
additionalStatements.addIfNotNull(lowerVar)
} else {
additionalStatements.addIfNotNull(lowerVar)
additionalStatements.addIfNotNull(upperVar)
}
lowerExpression = tmpLowerExpression
upperExpression = tmpUpperExpression
useLowerClauseOnLeftSide = true
} else if (lower.canHaveSideEffects && upper.canHaveSideEffects) {
if (shouldUpperComeFirst) {
val (upperVar, tmpUpperExpression) = createTemporaryVariableIfNecessary(upper, "containsUpper")
additionalStatements.add(upperVar!!)
lowerExpression = lower
upperExpression = tmpUpperExpression
useLowerClauseOnLeftSide = true
} else {
val (lowerVar, tmpLowerExpression) = createTemporaryVariableIfNecessary(lower, "containsLower")
additionalStatements.add(lowerVar!!)
lowerExpression = tmpLowerExpression
upperExpression = upper
useLowerClauseOnLeftSide = false
}
} else {
lowerExpression = lower
upperExpression = upper
useLowerClauseOnLeftSide = true
}
additionalStatements.addIfNotNull(argVar)
// TODO: Handle unsigned (comparisonClass is currently null).
val builtIns = context.irBuiltIns
val comparisonClass =
computeComparisonClass(this@Transformer.context.ir.symbols, lowerExpression.type, upperExpression.type, argExpression.type)
?: return null
val lessOrEqualFun = builtIns.lessOrEqualFunByOperandType.getValue(if (useCompareTo) builtIns.intClass else comparisonClass.symbol)
val compareToFun = comparisonClass.functions.singleOrNull {
it.name == OperatorNameConventions.COMPARE_TO &&
it.dispatchReceiverParameter != null && it.extensionReceiverParameter == null &&
it.valueParameters.size == 1 && it.valueParameters[0].type == argument.type.makeNotNull()
} ?: return null
// TODO: Handle null. This can happen with an extension fun, e.g., IntRange.compareTo(String) (See rangeContainsString.kt).
val lowerClause = if (useCompareTo) {
irCall(lessOrEqualFun).apply {
putValueArgument(0, irCall(compareToFun).apply {
dispatchReceiver = lowerExpression.castIfNecessary(comparisonClass)
putValueArgument(0, argExpression.castIfNecessary(comparisonClass))
})
putValueArgument(1, irInt(0))
}
} else {
irCall(lessOrEqualFun).apply {
putValueArgument(0, lowerExpression.castIfNecessary(comparisonClass))
putValueArgument(1, argExpression.castIfNecessary(comparisonClass))
}
}
val upperClause = if (useCompareTo) {
irCall(lessOrEqualFun).apply {
putValueArgument(0, irInt(0))
putValueArgument(1, irCall(compareToFun).apply {
dispatchReceiver = upperExpression.castIfNecessary(comparisonClass)
putValueArgument(0, argExpression.deepCopyWithSymbols().castIfNecessary(comparisonClass))
})
}
} else {
irCall(lessOrEqualFun).apply {
putValueArgument(0, argExpression.deepCopyWithSymbols().castIfNecessary(comparisonClass))
putValueArgument(1, upperExpression.castIfNecessary(comparisonClass))
}
}
val contains = context.andand(
if (useLowerClauseOnLeftSide) lowerClause else upperClause,
if (useLowerClauseOnLeftSide) upperClause else lowerClause,
origin
).let {
if (additionalNotEmptyCondition != null) {
// Add additional condition, currently used in `until` ranges (see UntilHandler.kt).
context.andand(additionalNotEmptyCondition, it)
} else {
it
}
}
return if (additionalStatements.isEmpty()) {
contains
} else {
irBlock {
for (stmt in additionalStatements) {
+stmt
}
+contains
}
}
}
// TODO: Handle unsigned.
private fun computeComparisonClass(
symbols: Symbols<CommonBackendContext>,
lowerType: IrType,
upperType: IrType,
argumentType: IrType
): IrClass? {
val commonBoundType = leastCommonPrimitiveNumericType(symbols, lowerType, upperType) ?: return null
return leastCommonPrimitiveNumericType(symbols, argumentType, commonBoundType)?.getClass()
}
private fun leastCommonPrimitiveNumericType(symbols: Symbols<CommonBackendContext>, t1: IrType, t2: IrType): IrType? {
val pt1 = t1.promoteIntegerTypeToIntIfRequired(symbols)
val pt2 = t2.promoteIntegerTypeToIntIfRequired(symbols)
return when {
pt1.isDouble() || pt2.isDouble() -> symbols.double
pt1.isFloat() || pt2.isFloat() -> symbols.float
// pt1.isULong() || pt2.isULong() -> symbols.uLong!!
// pt1.isUInt() || pt2.isUInt() -> symbols.uInt!!
pt1.isLong() || pt2.isLong() -> symbols.long
pt1.isInt() || pt2.isInt() -> symbols.int
pt1.isChar() || pt2.isChar() -> symbols.char
else -> return null
// error("Unexpected types: t1=${t1.classOrNull?.owner?.name}, t2=${t2.classOrNull?.owner?.name}")
}.defaultType
}
private fun IrType.promoteIntegerTypeToIntIfRequired(symbols: Symbols<CommonBackendContext>): IrType = when {
isByte() || isShort() -> symbols.int.defaultType
// isUByte() || isUShort() -> symbols.uInt!!.defaultType
else -> this
}
}
internal open class RangeHeaderInfoBuilder(context: CommonBackendContext, scopeOwnerSymbol: () -> IrSymbol) :
HeaderInfoBuilder(context, scopeOwnerSymbol) {
override val progressionHandlers = listOf(
CollectionIndicesHandler(context),
ArrayIndicesHandler(context),
CharSequenceIndicesHandler(context),
UntilHandler(context),
DownToHandler(context),
RangeToHandler(context)
)
override val callHandlers = listOf(ReversedHandler(context, this), FloatingPointRangeToHandler)
override val expressionHandlers = listOf(DefaultProgressionHandler(context))
}
/** Builds a [HeaderInfo] for closed floating-point ranges built using the `rangeTo` function. */
internal object FloatingPointRangeToHandler : HeaderInfoFromCallHandler<Nothing?> {
override val matcher = SimpleCalleeMatcher {
fqName { it == FqName("kotlin.ranges.rangeTo") }
extensionReceiver { it != null && it.type.run { isFloat() || isDouble() } }
parameterCount { it == 1 }
parameter(0) { it.type.run { isFloat() || isDouble() } }
}
override fun build(expression: IrCall, data: Nothing?, scopeOwner: IrSymbol) =
FloatingPointRangeHeaderInfo(
start = expression.extensionReceiver!!,
endInclusive = expression.getValueArgument(0)!!
)
}
@@ -117,7 +117,6 @@ private class RangeLoopTransformer(
val oldLoopToNewLoop: MutableMap<IrLoop, IrLoop>
) : IrElementTransformerVoidWithContext() {
private val symbols = context.ir.symbols
private val headerInfoBuilder = DefaultHeaderInfoBuilder(context, this::getScopeOwnerSymbol)
private val headerProcessor = HeaderProcessor(context, headerInfoBuilder, this::getScopeOwnerSymbol)
@@ -17,6 +17,7 @@ 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.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.defaultType
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
@@ -45,6 +46,15 @@ internal sealed class HeaderInfo {
abstract fun asReversed(): HeaderInfo?
}
// TODO: Update comments and member names in this file.
internal class FloatingPointRangeHeaderInfo(
val start: IrExpression,
val endInclusive: IrExpression
) : HeaderInfo() {
// No reverse() in ClosedFloatingPointRange.
override fun asReversed(): HeaderInfo? = null
}
internal sealed class NumericHeaderInfo(
val progressionType: ProgressionType,
val first: IrExpression,
@@ -243,25 +253,13 @@ internal abstract class HeaderInfoBuilder(context: CommonBackendContext, private
private val symbols = context.ir.symbols
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(
protected open val progressionHandlers = listOf(
CollectionIndicesHandler(context),
ArrayIndicesHandler(context),
CharSequenceIndicesHandler(context),
UntilHandler(context, progressionElementTypes),
DownToHandler(context, progressionElementTypes),
RangeToHandler(context, progressionElementTypes),
UntilHandler(context),
DownToHandler(context),
RangeToHandler(context),
StepHandler(context, this)
)
@@ -340,3 +338,6 @@ internal class NestedHeaderInfoBuilderForWithIndex(context: CommonBackendContext
DefaultSequenceHandler(context),
)
}
internal val Symbols<*>.progressionElementTypes: Collection<IrType>
get() = listOfNotNull(byte, short, int, long, char, uByte, uShort, uInt, uLong).map { it.defaultType }
@@ -440,6 +440,7 @@ internal class WithIndexLoopHeader(
is ProgressionHeaderInfo -> ProgressionLoopHeader(nestedInfo, this@with, context)
is IterableHeaderInfo -> IterableLoopHeader(nestedInfo)
is WithIndexHeaderInfo -> throw IllegalStateException("Nested WithIndexHeaderInfo not allowed for WithIndexLoopHeader")
is FloatingPointRangeHeaderInfo -> error("Unexpected FloatingPointRangeHeaderInfo for loops")
}
// Do not build own indexVariable if the nested loop header has an inductionVariable == 0 and step == 1.
@@ -668,6 +669,7 @@ internal class HeaderProcessor(
is ProgressionHeaderInfo -> ProgressionLoopHeader(headerInfo, builder, context)
is WithIndexHeaderInfo -> WithIndexLoopHeader(headerInfo, builder, context)
is IterableHeaderInfo -> IterableLoopHeader(headerInfo)
is FloatingPointRangeHeaderInfo -> error("Unexpected FloatingPointRangeHeaderInfo for loops")
}
}
}
@@ -38,24 +38,6 @@ internal sealed class ProgressionType(
fun IrExpression.asStepType() = castIfNecessary(stepClass)
private fun IrExpression.castIfNecessary(targetClass: IrClass) =
// This expression's type could be Nothing from an exception throw.
if (type == targetClass.defaultType || type.isNothing()) {
this
} else {
val numberCastFunctionName = Name.identifier("to${targetClass.name.asString()}")
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,
typeArgumentsCount = 0,
valueArgumentsCount = 0
).apply { dispatchReceiver = this@castIfNecessary }
}
companion object {
fun fromIrType(irType: IrType, symbols: Symbols<CommonBackendContext>): ProgressionType? = when {
irType.isSubtypeOfClass(symbols.charProgression) -> CharProgressionType(symbols)
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.common.lower.loops
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
import org.jetbrains.kotlin.ir.builders.createTmpVariable
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.expressions.IrConstKind
@@ -18,7 +19,9 @@ 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.defaultType
import org.jetbrains.kotlin.ir.util.functions
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.util.OperatorNameConventions
/** Return the negated value if the expression is const, otherwise call unaryMinus(). */
@@ -95,4 +98,22 @@ internal fun DeclarationIrBuilder.createTemporaryVariableIfNecessary(
scope.createTmpVariable(expression, nameHint = nameHint, irType = irType, isMutable = isMutable).let { Pair(it, irGet(it)) }
} else {
Pair(null, expression)
}
internal fun IrExpression.castIfNecessary(targetClass: IrClass) =
// This expression's type could be Nothing from an exception throw.
if (type == targetClass.defaultType || type.isNothing()) {
this
} else {
val numberCastFunctionName = Name.identifier("to${targetClass.name.asString()}")
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,
typeArgumentsCount = 0,
valueArgumentsCount = 0
).apply { dispatchReceiver = this@castIfNecessary }
}
@@ -17,9 +17,11 @@ import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.name.FqName
/** Builds a [HeaderInfo] for progressions built using the `downTo` extension function. */
internal class DownToHandler(private val context: CommonBackendContext, private val progressionElementTypes: Collection<IrType>) :
internal class DownToHandler(private val context: CommonBackendContext) :
ProgressionHandler {
private val progressionElementTypes = context.ir.symbols.progressionElementTypes
override val matcher = SimpleCalleeMatcher {
singleArgumentExtension(FqName("kotlin.ranges.downTo"), progressionElementTypes)
parameterCount { it == 1 }
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.common.lower.loops.handlers
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.loops.*
import org.jetbrains.kotlin.backend.common.lower.loops.ProgressionDirection
import org.jetbrains.kotlin.backend.common.lower.loops.ProgressionHandler
import org.jetbrains.kotlin.backend.common.lower.loops.ProgressionHeaderInfo
@@ -19,9 +20,11 @@ import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.util.OperatorNameConventions
/** Builds a [HeaderInfo] for progressions built using the `rangeTo` function. */
internal class RangeToHandler(private val context: CommonBackendContext, private val progressionElementTypes: Collection<IrType>) :
internal class RangeToHandler(private val context: CommonBackendContext) :
ProgressionHandler {
private val progressionElementTypes = context.ir.symbols.progressionElementTypes
override val matcher = SimpleCalleeMatcher {
dispatchReceiver { it != null && it.type in progressionElementTypes }
fqName { it.pathSegments().last() == OperatorNameConventions.RANGE_TO }
@@ -20,10 +20,11 @@ import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.name.FqName
/** Builds a [HeaderInfo] for progressions built using the `until` extension function. */
internal class UntilHandler(private val context: CommonBackendContext, private val progressionElementTypes: Collection<IrType>) :
internal class UntilHandler(private val context: CommonBackendContext) :
ProgressionHandler {
private val symbols = context.ir.symbols
private val progressionElementTypes = symbols.progressionElementTypes
private val uByteType = symbols.uByte?.defaultType
private val uShortType = symbols.uShort?.defaultType
private val uIntType = symbols.uInt?.defaultType
@@ -302,6 +302,7 @@ private val jvmFilePhases = listOf(
jvmStandardLibraryBuiltInsPhase,
rangeContainsLoweringPhase,
forLoopsPhase,
jvmInlineClassPhase,
@@ -1,5 +1,6 @@
// KJS_WITH_FULL_RUNTIME
// WITH_RUNTIME
import kotlin.test.*
var order = StringBuilder()
@@ -25,8 +26,32 @@ fun x(i: Int): Int {
}
fun box(): String {
expectOrder("0 in 1 .. 3", "HLX") { x(0) in high(3) downTo low(1) }
expectOrder("0 !in 1 .. 3", "HLX") { x(0) !in high(3) downTo low(1) }
expectOrder("x(0) in high(3) downTo low(1)", "HLX") { assertFalse(x(0) in high(3) downTo low(1)) }
expectOrder("0 in high(3) downTo low(1)", "HL") { assertFalse(0 in high(3) downTo low(1)) }
expectOrder("x(0) in high(3) downTo 1", "HX") { assertFalse(x(0) in high(3) downTo 1) }
expectOrder("x(0) in 3 downTo low(1)", "LX") { assertFalse(x(0) in 3 downTo low(1)) }
expectOrder("x(0) !in high(3) downTo low(1)", "HLX") { assertTrue(x(0) !in high(3) downTo low(1)) }
expectOrder("0 !in high(3) downTo low(1)", "HL") { assertTrue(0 !in high(3) downTo low(1)) }
expectOrder("x(0) !in high(3) downTo 1", "HX") { assertTrue(x(0) !in high(3) downTo 1) }
expectOrder("x(0) !in 3 downTo low(1)", "LX") { assertTrue(x(0) !in 3 downTo low(1)) }
expectOrder("x(4) in high(3) downTo low(1)", "HLX") { assertFalse(x(4) in high(3) downTo low(1)) }
expectOrder("4 in high(3) downTo low(1)", "HL") { assertFalse(4 in high(3) downTo low(1)) }
expectOrder("x(4) in high(3) downTo 1", "HX") { assertFalse(x(4) in high(3) downTo 1) }
expectOrder("x(4) in 3 downTo low(1)", "LX") { assertFalse(x(4) in 3 downTo low(1)) }
expectOrder("x(4) !in high(3) downTo low(1)", "HLX") { assertTrue(x(4) !in high(3) downTo low(1)) }
expectOrder("4 !in high(3) downTo low(1)", "HL") { assertTrue(4 !in high(3) downTo low(1)) }
expectOrder("x(4) !in high(3) downTo 1", "HX") { assertTrue(x(4) !in high(3) downTo 1) }
expectOrder("x(4) !in 3 downTo low(1)", "LX") { assertTrue(x(4) !in 3 downTo low(1)) }
expectOrder("x(2) in high(3) downTo low(1)", "HLX") { assertTrue(x(2) in high(3) downTo low(1)) }
expectOrder("2 in high(3) downTo low(1)", "HL") { assertTrue(2 in high(3) downTo low(1)) }
expectOrder("x(2) in high(3) downTo 1", "HX") { assertTrue(x(2) in high(3) downTo 1) }
expectOrder("x(2) in 3 downTo low(1)", "LX") { assertTrue(x(2) in 3 downTo low(1)) }
expectOrder("x(2) !in high(3) downTo low(1)", "HLX") { assertFalse(x(2) !in high(3) downTo low(1)) }
expectOrder("2 !in high(3) downTo low(1)", "HL") { assertFalse(2 !in high(3) downTo low(1)) }
expectOrder("x(2) !in high(3) downTo 1", "HX") { assertFalse(x(2) !in high(3) downTo 1) }
expectOrder("x(2) !in 3 downTo low(1)", "LX") { assertFalse(x(2) !in 3 downTo low(1)) }
return "OK"
}
@@ -0,0 +1,57 @@
// KJS_WITH_FULL_RUNTIME
// WITH_RUNTIME
import kotlin.test.*
var order = StringBuilder()
inline fun expectOrder(at: String, expected: String, body: () -> Unit) {
order = StringBuilder() // have to do that in order to run this test in JS
body()
if (order.toString() != expected) throw AssertionError("$at: expected: $expected, actual: $order")
}
fun low(i: Int): Int {
order.append("L")
return i
}
fun high(i: Int): Int {
order.append("H")
return i
}
fun x(i: Int): Int {
order.append("X")
return i
}
fun box(): String {
expectOrder("x(0) in (high(3) downTo low(1)).reversed()", "HLX") { assertFalse(x(0) in (high(3) downTo low(1)).reversed()) }
expectOrder("0 in (high(3) downTo low(1)).reversed()", "HL") { assertFalse(0 in (high(3) downTo low(1)).reversed()) }
expectOrder("x(0) in high(3) downTo 1", "HX") { assertFalse(x(0) in high(3) downTo 1) }
expectOrder("x(0) in 3 downTo low(1)", "LX") { assertFalse(x(0) in 3 downTo low(1)) }
expectOrder("x(0) !in (high(3) downTo low(1)).reversed()", "HLX") { assertTrue(x(0) !in (high(3) downTo low(1)).reversed()) }
expectOrder("0 !in (high(3) downTo low(1)).reversed()", "HL") { assertTrue(0 !in (high(3) downTo low(1)).reversed()) }
expectOrder("x(0) !in high(3) downTo 1", "HX") { assertTrue(x(0) !in high(3) downTo 1) }
expectOrder("x(0) !in 3 downTo low(1)", "LX") { assertTrue(x(0) !in 3 downTo low(1)) }
expectOrder("x(4) in (high(3) downTo low(1)).reversed()", "HLX") { assertFalse(x(4) in (high(3) downTo low(1)).reversed()) }
expectOrder("4 in (high(3) downTo low(1)).reversed()", "HL") { assertFalse(4 in (high(3) downTo low(1)).reversed()) }
expectOrder("x(4) in high(3) downTo 1", "HX") { assertFalse(x(4) in high(3) downTo 1) }
expectOrder("x(4) in 3 downTo low(1)", "LX") { assertFalse(x(4) in 3 downTo low(1)) }
expectOrder("x(4) !in (high(3) downTo low(1)).reversed()", "HLX") { assertTrue(x(4) !in (high(3) downTo low(1)).reversed()) }
expectOrder("4 !in (high(3) downTo low(1)).reversed()", "HL") { assertTrue(4 !in (high(3) downTo low(1)).reversed()) }
expectOrder("x(4) !in high(3) downTo 1", "HX") { assertTrue(x(4) !in high(3) downTo 1) }
expectOrder("x(4) !in 3 downTo low(1)", "LX") { assertTrue(x(4) !in 3 downTo low(1)) }
expectOrder("x(2) in (high(3) downTo low(1)).reversed()", "HLX") { assertTrue(x(2) in (high(3) downTo low(1)).reversed()) }
expectOrder("2 in (high(3) downTo low(1)).reversed()", "HL") { assertTrue(2 in (high(3) downTo low(1)).reversed()) }
expectOrder("x(2) in high(3) downTo 1", "HX") { assertTrue(x(2) in high(3) downTo 1) }
expectOrder("x(2) in 3 downTo low(1)", "LX") { assertTrue(x(2) in 3 downTo low(1)) }
expectOrder("x(2) !in (high(3) downTo low(1)).reversed()", "HLX") { assertFalse(x(2) !in (high(3) downTo low(1)).reversed()) }
expectOrder("2 !in (high(3) downTo low(1)).reversed()", "HL") { assertFalse(2 !in (high(3) downTo low(1)).reversed()) }
expectOrder("x(2) !in high(3) downTo 1", "HX") { assertFalse(x(2) !in high(3) downTo 1) }
expectOrder("x(2) !in 3 downTo low(1)", "LX") { assertFalse(x(2) !in 3 downTo low(1)) }
return "OK"
}
@@ -0,0 +1,66 @@
// KJS_WITH_FULL_RUNTIME
// WITH_RUNTIME
import kotlin.test.*
var order = StringBuilder()
inline fun expectOrder(at: String, expected: String, body: () -> Unit) {
order = StringBuilder() // have to do that in order to run this test in JS
body()
if (order.toString() != expected) throw AssertionError("$at: expected: $expected, actual: $order")
}
fun low(i: Int): Int {
order.append("L")
return i
}
fun high(i: Int): Int {
order.append("H")
return i
}
fun x(i: Int?): Int? {
order.append("X")
return i
}
fun box(): String {
expectOrder("x(null) in low(1) .. high(3)", "LHX") { assertFalse(x(null) in low(1) .. high(3)) }
expectOrder("null in low(1) .. high(3)", "LH") { assertFalse(null in low(1) .. high(3)) }
expectOrder("x(null) in 1 .. high(3)", "HX") { assertFalse(x(null) in 1 .. high(3)) }
expectOrder("x(null) in low(1) .. 3", "LX") { assertFalse(x(null) in low(1) .. 3) }
expectOrder("x(null) !in low(1) .. high(3)", "LHX") { assertTrue(x(null) !in low(1) .. high(3)) }
expectOrder("null !in low(1) .. high(3)", "LH") { assertTrue(null !in low(1) .. high(3)) }
expectOrder("x(null) !in 1 .. high(3)", "HX") { assertTrue(x(null) !in 1 .. high(3)) }
expectOrder("x(null) !in low(1) .. 3", "LX") { assertTrue(x(null) !in low(1) .. 3) }
expectOrder("x(0) in low(1) .. high(3)", "LHX") { assertFalse(x(0) in low(1) .. high(3)) }
expectOrder("0 in low(1) .. high(3)", "LH") { assertFalse(0 in low(1) .. high(3)) }
expectOrder("x(0) in 1 .. high(3)", "HX") { assertFalse(x(0) in 1 .. high(3)) }
expectOrder("x(0) in low(1) .. 3", "LX") { assertFalse(x(0) in low(1) .. 3) }
expectOrder("x(0) !in low(1) .. high(3)", "LHX") { assertTrue(x(0) !in low(1) .. high(3)) }
expectOrder("0 !in low(1) .. high(3)", "LH") { assertTrue(0 !in low(1) .. high(3)) }
expectOrder("x(0) !in 1 .. high(3)", "HX") { assertTrue(x(0) !in 1 .. high(3)) }
expectOrder("x(0) !in low(1) .. 3", "LX") { assertTrue(x(0) !in low(1) .. 3) }
expectOrder("x(4) in low(1) .. high(3)", "LHX") { assertFalse(x(4) in low(1) .. high(3)) }
expectOrder("4 in low(1) .. high(3)", "LH") { assertFalse(4 in low(1) .. high(3)) }
expectOrder("x(4) in 1 .. high(3)", "HX") { assertFalse(x(4) in 1 .. high(3)) }
expectOrder("x(4) in low(1) .. 3", "LX") { assertFalse(x(4) in low(1) .. 3) }
expectOrder("x(4) !in low(1) .. high(3)", "LHX") { assertTrue(x(4) !in low(1) .. high(3)) }
expectOrder("4 !in low(1) .. high(3)", "LH") { assertTrue(4 !in low(1) .. high(3)) }
expectOrder("x(4) !in 1 .. high(3)", "HX") { assertTrue(x(4) !in 1 .. high(3)) }
expectOrder("x(4) !in low(1) .. 3", "LX") { assertTrue(x(4) !in low(1) .. 3) }
expectOrder("x(2) in low(1) .. high(3)", "LHX") { assertTrue(x(2) in low(1) .. high(3)) }
expectOrder("2 in low(1) .. high(3)", "LH") { assertTrue(2 in low(1) .. high(3)) }
expectOrder("x(2) in 1 .. high(3)", "HX") { assertTrue(x(2) in 1 .. high(3)) }
expectOrder("x(2) in low(1) .. 3", "LX") { assertTrue(x(2) in low(1) .. 3) }
expectOrder("x(2) !in low(1) .. high(3)", "LHX") { assertFalse(x(2) !in low(1) .. high(3)) }
expectOrder("2 !in low(1) .. high(3)", "LH") { assertFalse(2 !in low(1) .. high(3)) }
expectOrder("x(2) !in 1 .. high(3)", "HX") { assertFalse(x(2) !in 1 .. high(3)) }
expectOrder("x(2) !in low(1) .. 3", "LX") { assertFalse(x(2) !in low(1) .. 3) }
return "OK"
}
@@ -1,5 +1,6 @@
// KJS_WITH_FULL_RUNTIME
// WITH_RUNTIME
import kotlin.test.*
var order = StringBuilder()
@@ -25,8 +26,32 @@ fun x(i: Int): Int {
}
fun box(): String {
expectOrder("0 in 1 .. 3", "LHX") { x(0) in low(1) .. high(3) }
expectOrder("0 !in 1 .. 3", "LHX") { x(0) !in low(1) .. high(3) }
expectOrder("x(0) in low(1) .. high(3)", "LHX") { assertFalse(x(0) in low(1) .. high(3)) }
expectOrder("0 in low(1) .. high(3)", "LH") { assertFalse(0 in low(1) .. high(3)) }
expectOrder("x(0) in 1 .. high(3)", "HX") { assertFalse(x(0) in 1 .. high(3)) }
expectOrder("x(0) in low(1) .. 3", "LX") { assertFalse(x(0) in low(1) .. 3) }
expectOrder("x(0) !in low(1) .. high(3)", "LHX") { assertTrue(x(0) !in low(1) .. high(3)) }
expectOrder("0 !in low(1) .. high(3)", "LH") { assertTrue(0 !in low(1) .. high(3)) }
expectOrder("x(0) !in 1 .. high(3)", "HX") { assertTrue(x(0) !in 1 .. high(3)) }
expectOrder("x(0) !in low(1) .. 3", "LX") { assertTrue(x(0) !in low(1) .. 3) }
expectOrder("x(4) in low(1) .. high(3)", "LHX") { assertFalse(x(4) in low(1) .. high(3)) }
expectOrder("4 in low(1) .. high(3)", "LH") { assertFalse(4 in low(1) .. high(3)) }
expectOrder("x(4) in 1 .. high(3)", "HX") { assertFalse(x(4) in 1 .. high(3)) }
expectOrder("x(4) in low(1) .. 3", "LX") { assertFalse(x(4) in low(1) .. 3) }
expectOrder("x(4) !in low(1) .. high(3)", "LHX") { assertTrue(x(4) !in low(1) .. high(3)) }
expectOrder("4 !in low(1) .. high(3)", "LH") { assertTrue(4 !in low(1) .. high(3)) }
expectOrder("x(4) !in 1 .. high(3)", "HX") { assertTrue(x(4) !in 1 .. high(3)) }
expectOrder("x(4) !in low(1) .. 3", "LX") { assertTrue(x(4) !in low(1) .. 3) }
expectOrder("x(2) in low(1) .. high(3)", "LHX") { assertTrue(x(2) in low(1) .. high(3)) }
expectOrder("2 in low(1) .. high(3)", "LH") { assertTrue(2 in low(1) .. high(3)) }
expectOrder("x(2) in 1 .. high(3)", "HX") { assertTrue(x(2) in 1 .. high(3)) }
expectOrder("x(2) in low(1) .. 3", "LX") { assertTrue(x(2) in low(1) .. 3) }
expectOrder("x(2) !in low(1) .. high(3)", "LHX") { assertFalse(x(2) !in low(1) .. high(3)) }
expectOrder("2 !in low(1) .. high(3)", "LH") { assertFalse(2 !in low(1) .. high(3)) }
expectOrder("x(2) !in 1 .. high(3)", "HX") { assertFalse(x(2) !in 1 .. high(3)) }
expectOrder("x(2) !in low(1) .. 3", "LX") { assertFalse(x(2) !in low(1) .. 3) }
return "OK"
}
@@ -0,0 +1,57 @@
// KJS_WITH_FULL_RUNTIME
// WITH_RUNTIME
import kotlin.test.*
var order = StringBuilder()
inline fun expectOrder(at: String, expected: String, body: () -> Unit) {
order = StringBuilder() // have to do that in order to run this test in JS
body()
if (order.toString() != expected) throw AssertionError("$at: expected: $expected, actual: $order")
}
fun low(i: Int): Int {
order.append("L")
return i
}
fun high(i: Int): Int {
order.append("H")
return i
}
fun x(i: Int): Int {
order.append("X")
return i
}
fun box(): String {
expectOrder("x(0) in (low(1) .. high(3)).reversed()", "LHX") { assertFalse(x(0) in (low(1) .. high(3)).reversed()) }
expectOrder("0 in (low(1) .. high(3)).reversed()", "LH") { assertFalse(0 in (low(1) .. high(3)).reversed()) }
expectOrder("x(0) in 1 .. high(3)", "HX") { assertFalse(x(0) in 1 .. high(3)) }
expectOrder("x(0) in low(1) .. 3", "LX") { assertFalse(x(0) in low(1) .. 3) }
expectOrder("x(0) !in (low(1) .. high(3)).reversed()", "LHX") { assertTrue(x(0) !in (low(1) .. high(3)).reversed()) }
expectOrder("0 !in (low(1) .. high(3)).reversed()", "LH") { assertTrue(0 !in (low(1) .. high(3)).reversed()) }
expectOrder("x(0) !in 1 .. high(3)", "HX") { assertTrue(x(0) !in 1 .. high(3)) }
expectOrder("x(0) !in low(1) .. 3", "LX") { assertTrue(x(0) !in low(1) .. 3) }
expectOrder("x(4) in (low(1) .. high(3)).reversed()", "LHX") { assertFalse(x(4) in (low(1) .. high(3)).reversed()) }
expectOrder("4 in (low(1) .. high(3)).reversed()", "LH") { assertFalse(4 in (low(1) .. high(3)).reversed()) }
expectOrder("x(4) in 1 .. high(3)", "HX") { assertFalse(x(4) in 1 .. high(3)) }
expectOrder("x(4) in low(1) .. 3", "LX") { assertFalse(x(4) in low(1) .. 3) }
expectOrder("x(4) !in (low(1) .. high(3)).reversed()", "LHX") { assertTrue(x(4) !in (low(1) .. high(3)).reversed()) }
expectOrder("4 !in (low(1) .. high(3)).reversed()", "LH") { assertTrue(4 !in (low(1) .. high(3)).reversed()) }
expectOrder("x(4) !in 1 .. high(3)", "HX") { assertTrue(x(4) !in 1 .. high(3)) }
expectOrder("x(4) !in low(1) .. 3", "LX") { assertTrue(x(4) !in low(1) .. 3) }
expectOrder("x(2) in (low(1) .. high(3)).reversed()", "LHX") { assertTrue(x(2) in (low(1) .. high(3)).reversed()) }
expectOrder("2 in (low(1) .. high(3)).reversed()", "LH") { assertTrue(2 in (low(1) .. high(3)).reversed()) }
expectOrder("x(2) in 1 .. high(3)", "HX") { assertTrue(x(2) in 1 .. high(3)) }
expectOrder("x(2) in low(1) .. 3", "LX") { assertTrue(x(2) in low(1) .. 3) }
expectOrder("x(2) !in (low(1) .. high(3)).reversed()", "LHX") { assertFalse(x(2) !in (low(1) .. high(3)).reversed()) }
expectOrder("2 !in (low(1) .. high(3)).reversed()", "LH") { assertFalse(2 !in (low(1) .. high(3)).reversed()) }
expectOrder("x(2) !in 1 .. high(3)", "HX") { assertFalse(x(2) !in 1 .. high(3)) }
expectOrder("x(2) !in low(1) .. 3", "LX") { assertFalse(x(2) !in low(1) .. 3) }
return "OK"
}
@@ -0,0 +1,57 @@
// KJS_WITH_FULL_RUNTIME
// WITH_RUNTIME
import kotlin.test.*
var order = StringBuilder()
inline fun expectOrder(at: String, expected: String, body: () -> Unit) {
order = StringBuilder() // have to do that in order to run this test in JS
body()
if (order.toString() != expected) throw AssertionError("$at: expected: $expected, actual: $order")
}
fun low(i: Int): Int {
order.append("L")
return i
}
fun high(i: Int): Int {
order.append("H")
return i
}
fun x(i: Int): Int {
order.append("X")
return i
}
fun box(): String {
expectOrder("x(0) in low(1) until high(3)", "LHX") { assertFalse(x(0) in low(1) until high(3)) }
expectOrder("0 in low(1) until high(3)", "LH") { assertFalse(0 in low(1) until high(3)) }
expectOrder("x(0) in 1 until high(3)", "HX") { assertFalse(x(0) in 1 until high(3)) }
expectOrder("x(0) in low(1) until 3", "LX") { assertFalse(x(0) in low(1) until 3) }
expectOrder("x(0) !in low(1) until high(3)", "LHX") { assertTrue(x(0) !in low(1) until high(3)) }
expectOrder("0 !in low(1) until high(3)", "LH") { assertTrue(0 !in low(1) until high(3)) }
expectOrder("x(0) !in 1 until high(3)", "HX") { assertTrue(x(0) !in 1 until high(3)) }
expectOrder("x(0) !in low(1) until 3", "LX") { assertTrue(x(0) !in low(1) until 3) }
expectOrder("x(4) in low(1) until high(3)", "LHX") { assertFalse(x(4) in low(1) until high(3)) }
expectOrder("4 in low(1) until high(3)", "LH") { assertFalse(4 in low(1) until high(3)) }
expectOrder("x(4) in 1 until high(3)", "HX") { assertFalse(x(4) in 1 until high(3)) }
expectOrder("x(4) in low(1) until 3", "LX") { assertFalse(x(4) in low(1) until 3) }
expectOrder("x(4) !in low(1) until high(3)", "LHX") { assertTrue(x(4) !in low(1) until high(3)) }
expectOrder("4 !in low(1) until high(3)", "LH") { assertTrue(4 !in low(1) until high(3)) }
expectOrder("x(4) !in 1 until high(3)", "HX") { assertTrue(x(4) !in 1 until high(3)) }
expectOrder("x(4) !in low(1) until 3", "LX") { assertTrue(x(4) !in low(1) until 3) }
expectOrder("x(2) in low(1) until high(3)", "LHX") { assertTrue(x(2) in low(1) until high(3)) }
expectOrder("2 in low(1) until high(3)", "LH") { assertTrue(2 in low(1) until high(3)) }
expectOrder("x(2) in 1 until high(3)", "HX") { assertTrue(x(2) in 1 until high(3)) }
expectOrder("x(2) in low(1) until 3", "LX") { assertTrue(x(2) in low(1) until 3) }
expectOrder("x(2) !in low(1) until high(3)", "LHX") { assertFalse(x(2) !in low(1) until high(3)) }
expectOrder("2 !in low(1) until high(3)", "LH") { assertFalse(2 !in low(1) until high(3)) }
expectOrder("x(2) !in 1 until high(3)", "HX") { assertFalse(x(2) !in 1 until high(3)) }
expectOrder("x(2) !in low(1) until 3", "LX") { assertFalse(x(2) !in low(1) until 3) }
return "OK"
}
@@ -0,0 +1,57 @@
// KJS_WITH_FULL_RUNTIME
// WITH_RUNTIME
import kotlin.test.*
var order = StringBuilder()
inline fun expectOrder(at: String, expected: String, body: () -> Unit) {
order = StringBuilder() // have to do that in order to run this test in JS
body()
if (order.toString() != expected) throw AssertionError("$at: expected: $expected, actual: $order")
}
fun low(i: Int): Int {
order.append("L")
return i
}
fun high(i: Int): Int {
order.append("H")
return i
}
fun x(i: Int): Int {
order.append("X")
return i
}
fun box(): String {
expectOrder("x(0) in (low(1) until high(3)).reversed()", "LHX") { assertFalse(x(0) in (low(1) until high(3)).reversed()) }
expectOrder("0 in (low(1) until high(3)).reversed()", "LH") { assertFalse(0 in (low(1) until high(3)).reversed()) }
expectOrder("x(0) in 1 until high(3)", "HX") { assertFalse(x(0) in 1 until high(3)) }
expectOrder("x(0) in low(1) until 3", "LX") { assertFalse(x(0) in low(1) until 3) }
expectOrder("x(0) !in (low(1) until high(3)).reversed()", "LHX") { assertTrue(x(0) !in (low(1) until high(3)).reversed()) }
expectOrder("0 !in (low(1) until high(3)).reversed()", "LH") { assertTrue(0 !in (low(1) until high(3)).reversed()) }
expectOrder("x(0) !in 1 until high(3)", "HX") { assertTrue(x(0) !in 1 until high(3)) }
expectOrder("x(0) !in low(1) until 3", "LX") { assertTrue(x(0) !in low(1) until 3) }
expectOrder("x(4) in (low(1) until high(3)).reversed()", "LHX") { assertFalse(x(4) in (low(1) until high(3)).reversed()) }
expectOrder("4 in (low(1) until high(3)).reversed()", "LH") { assertFalse(4 in (low(1) until high(3)).reversed()) }
expectOrder("x(4) in 1 until high(3)", "HX") { assertFalse(x(4) in 1 until high(3)) }
expectOrder("x(4) in low(1) until 3", "LX") { assertFalse(x(4) in low(1) until 3) }
expectOrder("x(4) !in (low(1) until high(3)).reversed()", "LHX") { assertTrue(x(4) !in (low(1) until high(3)).reversed()) }
expectOrder("4 !in (low(1) until high(3)).reversed()", "LH") { assertTrue(4 !in (low(1) until high(3)).reversed()) }
expectOrder("x(4) !in 1 until high(3)", "HX") { assertTrue(x(4) !in 1 until high(3)) }
expectOrder("x(4) !in low(1) until 3", "LX") { assertTrue(x(4) !in low(1) until 3) }
expectOrder("x(2) in (low(1) until high(3)).reversed()", "LHX") { assertTrue(x(2) in (low(1) until high(3)).reversed()) }
expectOrder("2 in (low(1) until high(3)).reversed()", "LH") { assertTrue(2 in (low(1) until high(3)).reversed()) }
expectOrder("x(2) in 1 until high(3)", "HX") { assertTrue(x(2) in 1 until high(3)) }
expectOrder("x(2) in low(1) until 3", "LX") { assertTrue(x(2) in low(1) until 3) }
expectOrder("x(2) !in (low(1) until high(3)).reversed()", "LHX") { assertFalse(x(2) !in (low(1) until high(3)).reversed()) }
expectOrder("2 !in (low(1) until high(3)).reversed()", "LH") { assertFalse(2 !in (low(1) until high(3)).reversed()) }
expectOrder("x(2) !in 1 until high(3)", "HX") { assertFalse(x(2) !in 1 until high(3)) }
expectOrder("x(2) !in low(1) until 3", "LX") { assertFalse(x(2) !in low(1) until 3) }
return "OK"
}
@@ -0,0 +1,20 @@
// WITH_RUNTIME
fun box(): String {
if (Char.MAX_VALUE in Char.MAX_VALUE until Char.MAX_VALUE) return "Fail in Char.MAX_VALUE"
if (!(Char.MAX_VALUE !in Char.MAX_VALUE until Char.MAX_VALUE)) return "Fail !in Char.MAX_VALUE"
if (Int.MAX_VALUE in Int.MAX_VALUE until Int.MAX_VALUE) return "Fail in Int.MAX_VALUE"
if (!(Int.MAX_VALUE !in Int.MAX_VALUE until Int.MAX_VALUE)) return "Fail !in Int.MAX_VALUE"
if (Long.MAX_VALUE in Long.MAX_VALUE until Long.MAX_VALUE) return "Fail in Long.MAX_VALUE"
if (!(Long.MAX_VALUE !in Long.MAX_VALUE until Long.MAX_VALUE)) return "Fail !in Long.MAX_VALUE"
if (UInt.MAX_VALUE in UInt.MAX_VALUE until UInt.MAX_VALUE) return "Fail in UInt.MAX_VALUE"
if (!(UInt.MAX_VALUE !in UInt.MAX_VALUE until UInt.MAX_VALUE)) return "Fail !in UInt.MAX_VALUE"
if (ULong.MAX_VALUE in ULong.MAX_VALUE until ULong.MAX_VALUE) return "Fail in ULong.MAX_VALUE"
if (!(ULong.MAX_VALUE !in ULong.MAX_VALUE until ULong.MAX_VALUE)) return "Fail !in ULong.MAX_VALUE"
return "OK"
}
@@ -0,0 +1,20 @@
// WITH_RUNTIME
fun box(): String {
if ('b' in 'a' until Char.MIN_VALUE) return "Fail in Char.MIN_VALUE"
if (!('b' !in 'a' until Char.MIN_VALUE)) return "Fail !in Char.MIN_VALUE"
if (1 in 0 until Int.MIN_VALUE) return "Fail in Int.MIN_VALUE"
if (!(1 !in 0 until Int.MIN_VALUE)) return "Fail !in Int.MIN_VALUE"
if (1L in 0L until Long.MIN_VALUE) return "Fail in Long.MIN_VALUE"
if (!(1L !in 0L until Long.MIN_VALUE)) return "Fail !in Long.MIN_VALUE"
if (1u in 0u until UInt.MIN_VALUE) return "Fail in UInt.MIN_VALUE"
if (!(1u !in 0u until UInt.MIN_VALUE)) return "Fail !in UInt.MIN_VALUE"
if (1uL in 0uL until ULong.MIN_VALUE) return "Fail in ULong.MIN_VALUE"
if (!(1uL !in 0uL until ULong.MIN_VALUE)) return "Fail !in ULong.MIN_VALUE"
return "OK"
}
@@ -0,0 +1,25 @@
// WITH_RUNTIME
fun box(): String {
val charBound = Char.MIN_VALUE
if ('b' in 'a' until charBound) return "Fail in Char.MIN_VALUE"
if (!('b' !in 'a' until charBound)) return "Fail !in Char.MIN_VALUE"
val intBound = Int.MIN_VALUE
if (1 in 0 until intBound) return "Fail in Int.MIN_VALUE"
if (!(1 !in 0 until intBound)) return "Fail !in Int.MIN_VALUE"
val longBound = Long.MIN_VALUE
if (1L in 0L until longBound) return "Fail in Long.MIN_VALUE"
if (!(1L !in 0L until longBound)) return "Fail !in Long.MIN_VALUE"
val uIntBound = UInt.MIN_VALUE
if (1u in 0u until uIntBound) return "Fail in UInt.MIN_VALUE"
if (!(1u !in 0u until uIntBound)) return "Fail !in UInt.MIN_VALUE"
val uLongBound = ULong.MIN_VALUE
if (1uL in 0uL until uLongBound) return "Fail in ULong.MIN_VALUE"
if (!(1uL !in 0uL until uLongBound)) return "Fail !in ULong.MIN_VALUE"
return "OK"
}
@@ -1,14 +1,38 @@
// WITH_RUNTIME
val x: Int? = 42
fun xFun(): Int? = 42
val n: Int? = null
val nProp: Int?
get() = null
fun box(): String {
if (x in 0..2) return "Fail in"
if (!(x !in 0..2)) return "Fail !in"
if (xFun() in 0..2) return "Fail in function"
if (!(xFun() !in 0..2)) return "Fail !in function"
if (n in 0..2) return "Fail in null"
if (!(n !in 0..2)) return "Fail !in null"
if (nProp in 0..2) return "Fail in null property"
if (!(nProp !in 0..2)) return "Fail !in null property"
val v: Int? = 10
if (v in 0..2) return "Fail in variable"
if (!(v !in 0..2)) return "Fail !in variable"
val nul: Int? = null
if (nul in 0..2) return "Fail in null variable"
if (!(nul !in 0..2)) return "Fail !in null variable"
if (null in 0..2) return "Fail in null const"
if (!(null !in 0..2)) return "Fail !in null const"
if ({ x }() in 0..2) return "Fail in complex"
if (!({ x }() !in 0..2)) return "Fail !in complex"
return "OK"
}
@@ -1,3 +1,6 @@
fun testChar(x: Char, a: Char, b: Char) =
if (x !in a .. b) "no" else "yes"
fun testInt(x: Int, a: Int, b: Int) =
if (x !in a .. b) "no" else "yes"
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TODO KT-36829 Optimize 'in' expressions in JVM_IR
fun testPrimitiveArray(i: Int, ints: IntArray) = i in ints.indices
fun testObjectArray(i: Int, xs: Array<Any>) = i in xs.indices
@@ -13,4 +11,9 @@ fun testLongWithObjectArray(i: Long, xs: Array<Any>) = i in xs.indices
// 2 I2L
// 4 ARRAYLENGTH
// 2 LCONST_0
// JVM_TEMPLATES
// 6 ICONST_0
// JVM_IR_TEMPLATES
// 10 ICONST_0
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TODO KT-36829 Optimize 'in' expressions in JVM_IR
fun testCharSequence(i: Int, cs: CharSequence) = i in cs.indices
fun testLongWithCharSequence(i: Long, cs: CharSequence) = i in cs.indices
@@ -7,5 +5,4 @@ fun testLongWithCharSequence(i: Long, cs: CharSequence) = i in cs.indices
// 0 getIndices
// 0 contains
// 2 length
// 1 I2L
// 1 I2L
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TODO KT-36829 Optimize 'in' expressions in JVM_IR
fun testCollection(i: Int, xs: List<Any>) = i in xs.indices
fun testLongWithCollection(i: Long, xs: List<Any>) = i in xs.indices
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TODO KT-36829 Optimize 'in' expressions in JVM_IR
fun inInt(x: Long): Boolean {
return x in 1..2
}
@@ -17,7 +15,6 @@ fun inDouble(x: Float): Boolean {
}
// 2 I2L
// 3 F2D
// 0 INVOKESPECIAL
// 0 NEW
// 0 rangeTo
@@ -25,3 +22,10 @@ fun inDouble(x: Float): Boolean {
// 0 intRangeContains
// 0 doubleRangeContains
// 0 floatRangeContains
// 0 contains
// JVM_TEMPLATES
// 3 F2D
// JVM_IR_TEMPLATES
// 2 F2D
@@ -1,11 +1,11 @@
// IGNORE_BACKEND: JVM_IR
// TODO KT-36829 Optimize 'in' expressions in JVM_IR
fun Byte.inByte(left: Byte, right: Byte) = this in left..right
fun Short.inInt(left: Int, right: Int) = this in left .. right
fun Short.inByte(left: Byte, right: Byte) = this in left..right
fun inChar(x: Char, left: Char, right: Char) = x in left..right
fun inInt(x: Int, left: Int, right: Int) = x in left..right
fun inDouble(x: Double, left: Double, right: Double) = x in left..right
@@ -23,3 +23,4 @@ fun inCharWithNullableParameter(x: Char?, left: Char, right: Char) = x!! in left
// 0 CHECKCAST
// 0 INVOKEINTERFACE
// 0 <init>
// 0 contains
+3 -2
View File
@@ -1,5 +1,5 @@
// IGNORE_BACKEND: JVM_IR
// TODO KT-36829 Optimize 'in' expressions in JVM_IR
fun testChar(a: Char, x: Char, y: Char) = a in x until y
fun testByte(a: Byte, x: Byte, y: Byte) = a in x until y
fun testShort(a: Short, x: Short, y: Short) = a in x until y
@@ -10,3 +10,4 @@ fun testLong(a: Long, x: Long, y: Long) = a in x until y
// 0 until
// 0 INVOKEVIRTUAL
// 0 contains
@@ -22275,11 +22275,36 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForDownTo.kt");
}
@TestMetadata("evaluationOrderForDownToReversed.kt")
public void testEvaluationOrderForDownToReversed() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForDownToReversed.kt");
}
@TestMetadata("evaluationOrderForNullableArgument.kt")
public void testEvaluationOrderForNullableArgument() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForNullableArgument.kt");
}
@TestMetadata("evaluationOrderForRangeLiteral.kt")
public void testEvaluationOrderForRangeLiteral() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForRangeLiteral.kt");
}
@TestMetadata("evaluationOrderForRangeLiteralReversed.kt")
public void testEvaluationOrderForRangeLiteralReversed() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForRangeLiteralReversed.kt");
}
@TestMetadata("evaluationOrderForUntil.kt")
public void testEvaluationOrderForUntil() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntil.kt");
}
@TestMetadata("evaluationOrderForUntilReversed.kt")
public void testEvaluationOrderForUntilReversed() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntilReversed.kt");
}
@TestMetadata("genericCharInRangeLiteral.kt")
public void testGenericCharInRangeLiteral() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/genericCharInRangeLiteral.kt");
@@ -22395,6 +22420,21 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/ranges/contains/inUntil.kt");
}
@TestMetadata("inUntilMaxValue.kt")
public void testInUntilMaxValue() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/inUntilMaxValue.kt");
}
@TestMetadata("inUntilMinValue.kt")
public void testInUntilMinValue() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/inUntilMinValue.kt");
}
@TestMetadata("inUntilMinValueNonConst.kt")
public void testInUntilMinValueNonConst() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/inUntilMinValueNonConst.kt");
}
@TestMetadata("kt20106.kt")
public void testKt20106() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/kt20106.kt");
@@ -22275,11 +22275,36 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForDownTo.kt");
}
@TestMetadata("evaluationOrderForDownToReversed.kt")
public void testEvaluationOrderForDownToReversed() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForDownToReversed.kt");
}
@TestMetadata("evaluationOrderForNullableArgument.kt")
public void testEvaluationOrderForNullableArgument() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForNullableArgument.kt");
}
@TestMetadata("evaluationOrderForRangeLiteral.kt")
public void testEvaluationOrderForRangeLiteral() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForRangeLiteral.kt");
}
@TestMetadata("evaluationOrderForRangeLiteralReversed.kt")
public void testEvaluationOrderForRangeLiteralReversed() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForRangeLiteralReversed.kt");
}
@TestMetadata("evaluationOrderForUntil.kt")
public void testEvaluationOrderForUntil() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntil.kt");
}
@TestMetadata("evaluationOrderForUntilReversed.kt")
public void testEvaluationOrderForUntilReversed() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntilReversed.kt");
}
@TestMetadata("genericCharInRangeLiteral.kt")
public void testGenericCharInRangeLiteral() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/genericCharInRangeLiteral.kt");
@@ -22395,6 +22420,21 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/ranges/contains/inUntil.kt");
}
@TestMetadata("inUntilMaxValue.kt")
public void testInUntilMaxValue() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/inUntilMaxValue.kt");
}
@TestMetadata("inUntilMinValue.kt")
public void testInUntilMinValue() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/inUntilMinValue.kt");
}
@TestMetadata("inUntilMinValueNonConst.kt")
public void testInUntilMinValueNonConst() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/inUntilMinValueNonConst.kt");
}
@TestMetadata("kt20106.kt")
public void testKt20106() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/kt20106.kt");
@@ -20679,11 +20679,36 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForDownTo.kt");
}
@TestMetadata("evaluationOrderForDownToReversed.kt")
public void testEvaluationOrderForDownToReversed() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForDownToReversed.kt");
}
@TestMetadata("evaluationOrderForNullableArgument.kt")
public void testEvaluationOrderForNullableArgument() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForNullableArgument.kt");
}
@TestMetadata("evaluationOrderForRangeLiteral.kt")
public void testEvaluationOrderForRangeLiteral() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForRangeLiteral.kt");
}
@TestMetadata("evaluationOrderForRangeLiteralReversed.kt")
public void testEvaluationOrderForRangeLiteralReversed() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForRangeLiteralReversed.kt");
}
@TestMetadata("evaluationOrderForUntil.kt")
public void testEvaluationOrderForUntil() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntil.kt");
}
@TestMetadata("evaluationOrderForUntilReversed.kt")
public void testEvaluationOrderForUntilReversed() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntilReversed.kt");
}
@TestMetadata("genericCharInRangeLiteral.kt")
public void testGenericCharInRangeLiteral() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/genericCharInRangeLiteral.kt");
@@ -20799,6 +20824,21 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/ranges/contains/inUntil.kt");
}
@TestMetadata("inUntilMaxValue.kt")
public void testInUntilMaxValue() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/inUntilMaxValue.kt");
}
@TestMetadata("inUntilMinValue.kt")
public void testInUntilMinValue() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/inUntilMinValue.kt");
}
@TestMetadata("inUntilMinValueNonConst.kt")
public void testInUntilMinValueNonConst() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/inUntilMinValueNonConst.kt");
}
@TestMetadata("kt20106.kt")
public void testKt20106() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/kt20106.kt");
@@ -17090,11 +17090,36 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForDownTo.kt");
}
@TestMetadata("evaluationOrderForDownToReversed.kt")
public void testEvaluationOrderForDownToReversed() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForDownToReversed.kt");
}
@TestMetadata("evaluationOrderForNullableArgument.kt")
public void testEvaluationOrderForNullableArgument() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForNullableArgument.kt");
}
@TestMetadata("evaluationOrderForRangeLiteral.kt")
public void testEvaluationOrderForRangeLiteral() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForRangeLiteral.kt");
}
@TestMetadata("evaluationOrderForRangeLiteralReversed.kt")
public void testEvaluationOrderForRangeLiteralReversed() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForRangeLiteralReversed.kt");
}
@TestMetadata("evaluationOrderForUntil.kt")
public void testEvaluationOrderForUntil() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntil.kt");
}
@TestMetadata("evaluationOrderForUntilReversed.kt")
public void testEvaluationOrderForUntilReversed() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntilReversed.kt");
}
@TestMetadata("genericCharInRangeLiteral.kt")
public void testGenericCharInRangeLiteral() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/genericCharInRangeLiteral.kt");
@@ -17210,6 +17235,21 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
runTest("compiler/testData/codegen/box/ranges/contains/inUntil.kt");
}
@TestMetadata("inUntilMaxValue.kt")
public void testInUntilMaxValue() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/inUntilMaxValue.kt");
}
@TestMetadata("inUntilMinValue.kt")
public void testInUntilMinValue() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/inUntilMinValue.kt");
}
@TestMetadata("inUntilMinValueNonConst.kt")
public void testInUntilMinValueNonConst() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/inUntilMinValueNonConst.kt");
}
@TestMetadata("kt20106.kt")
public void testKt20106() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/kt20106.kt");
@@ -17090,11 +17090,36 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForDownTo.kt");
}
@TestMetadata("evaluationOrderForDownToReversed.kt")
public void testEvaluationOrderForDownToReversed() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForDownToReversed.kt");
}
@TestMetadata("evaluationOrderForNullableArgument.kt")
public void testEvaluationOrderForNullableArgument() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForNullableArgument.kt");
}
@TestMetadata("evaluationOrderForRangeLiteral.kt")
public void testEvaluationOrderForRangeLiteral() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForRangeLiteral.kt");
}
@TestMetadata("evaluationOrderForRangeLiteralReversed.kt")
public void testEvaluationOrderForRangeLiteralReversed() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForRangeLiteralReversed.kt");
}
@TestMetadata("evaluationOrderForUntil.kt")
public void testEvaluationOrderForUntil() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntil.kt");
}
@TestMetadata("evaluationOrderForUntilReversed.kt")
public void testEvaluationOrderForUntilReversed() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntilReversed.kt");
}
@TestMetadata("genericCharInRangeLiteral.kt")
public void testGenericCharInRangeLiteral() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/genericCharInRangeLiteral.kt");
@@ -17210,6 +17235,21 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/ranges/contains/inUntil.kt");
}
@TestMetadata("inUntilMaxValue.kt")
public void testInUntilMaxValue() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/inUntilMaxValue.kt");
}
@TestMetadata("inUntilMinValue.kt")
public void testInUntilMinValue() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/inUntilMinValue.kt");
}
@TestMetadata("inUntilMinValueNonConst.kt")
public void testInUntilMinValueNonConst() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/inUntilMinValueNonConst.kt");
}
@TestMetadata("kt20106.kt")
public void testKt20106() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/kt20106.kt");
@@ -17195,11 +17195,36 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForDownTo.kt");
}
@TestMetadata("evaluationOrderForDownToReversed.kt")
public void testEvaluationOrderForDownToReversed() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForDownToReversed.kt");
}
@TestMetadata("evaluationOrderForNullableArgument.kt")
public void testEvaluationOrderForNullableArgument() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForNullableArgument.kt");
}
@TestMetadata("evaluationOrderForRangeLiteral.kt")
public void testEvaluationOrderForRangeLiteral() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForRangeLiteral.kt");
}
@TestMetadata("evaluationOrderForRangeLiteralReversed.kt")
public void testEvaluationOrderForRangeLiteralReversed() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForRangeLiteralReversed.kt");
}
@TestMetadata("evaluationOrderForUntil.kt")
public void testEvaluationOrderForUntil() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntil.kt");
}
@TestMetadata("evaluationOrderForUntilReversed.kt")
public void testEvaluationOrderForUntilReversed() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntilReversed.kt");
}
@TestMetadata("genericCharInRangeLiteral.kt")
public void testGenericCharInRangeLiteral() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/genericCharInRangeLiteral.kt");
@@ -17315,6 +17340,21 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/ranges/contains/inUntil.kt");
}
@TestMetadata("inUntilMaxValue.kt")
public void testInUntilMaxValue() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/inUntilMaxValue.kt");
}
@TestMetadata("inUntilMinValue.kt")
public void testInUntilMinValue() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/inUntilMinValue.kt");
}
@TestMetadata("inUntilMinValueNonConst.kt")
public void testInUntilMinValueNonConst() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/inUntilMinValueNonConst.kt");
}
@TestMetadata("kt20106.kt")
public void testKt20106() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/kt20106.kt");