Initial version of RangeContainsLowering, which optimizes calls to
contains() on ClosedRanges.
This commit is contained in:
committed by
Alexander Udalov
parent
ca541337d1
commit
1c1b1b4b0f
Generated
+40
@@ -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)
|
||||
|
||||
|
||||
+401
@@ -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)!!
|
||||
)
|
||||
}
|
||||
-1
@@ -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
-16
@@ -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 }
|
||||
|
||||
+2
@@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-18
@@ -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)
|
||||
|
||||
+21
@@ -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 }
|
||||
}
|
||||
+3
-1
@@ -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 }
|
||||
|
||||
+4
-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 }
|
||||
|
||||
+2
-1
@@ -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"
|
||||
}
|
||||
+57
@@ -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"
|
||||
}
|
||||
+66
@@ -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"
|
||||
}
|
||||
+27
-2
@@ -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"
|
||||
}
|
||||
+57
@@ -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"
|
||||
}
|
||||
+57
@@ -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
|
||||
|
||||
+7
-3
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+40
@@ -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");
|
||||
|
||||
+40
@@ -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");
|
||||
|
||||
+40
@@ -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");
|
||||
|
||||
Generated
+40
@@ -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");
|
||||
|
||||
Generated
+40
@@ -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");
|
||||
|
||||
+40
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user