diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index 781ee4fa8ca..cb69accca52 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -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"); diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt index 677015b946c..ec5c57ef446 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.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) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/RangeContainsLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/RangeContainsLowering.kt new file mode 100644 index 00000000000..1e3e4b47c36 --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/RangeContainsLowering.kt @@ -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() + + 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, + 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, 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): 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 { + + 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)!! + ) +} \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/ForLoopsLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/ForLoopsLowering.kt index c199ff9c812..8e2f2ad77dc 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/ForLoopsLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/ForLoopsLowering.kt @@ -117,7 +117,6 @@ private class RangeLoopTransformer( val oldLoopToNewLoop: MutableMap ) : IrElementTransformerVoidWithContext() { - private val symbols = context.ir.symbols private val headerInfoBuilder = DefaultHeaderInfoBuilder(context, this::getScopeOwnerSymbol) private val headerProcessor = HeaderProcessor(context, headerInfoBuilder, this::getScopeOwnerSymbol) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/HeaderInfo.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/HeaderInfo.kt index 547fc9a2315..68ecd726e3f 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/HeaderInfo.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/HeaderInfo.kt @@ -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 + get() = listOfNotNull(byte, short, int, long, char, uByte, uShort, uInt, uLong).map { it.defaultType } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/HeaderProcessor.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/HeaderProcessor.kt index 7dfeb4f72bd..fd44b92d99a 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/HeaderProcessor.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/HeaderProcessor.kt @@ -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") } } } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/ProgressionType.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/ProgressionType.kt index db511cf7f5b..87f116e08ab 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/ProgressionType.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/ProgressionType.kt @@ -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): ProgressionType? = when { irType.isSubtypeOfClass(symbols.charProgression) -> CharProgressionType(symbols) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/Utils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/Utils.kt index b436024816e..5492078fb6f 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/Utils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/Utils.kt @@ -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 } } \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/DownToHandler.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/DownToHandler.kt index 31826b43d94..b7ad80d0323 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/DownToHandler.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/DownToHandler.kt @@ -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) : +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 } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/RangeToHandler.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/RangeToHandler.kt index 65fa0e77457..67bba06b21f 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/RangeToHandler.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/RangeToHandler.kt @@ -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) : +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 } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/UntilHandler.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/UntilHandler.kt index 31363b33c52..744fe3d6cfa 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/UntilHandler.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/UntilHandler.kt @@ -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) : +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 diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index 136d43bedbe..c77013dd84c 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -302,6 +302,7 @@ private val jvmFilePhases = listOf( jvmStandardLibraryBuiltInsPhase, + rangeContainsLoweringPhase, forLoopsPhase, jvmInlineClassPhase, diff --git a/compiler/testData/codegen/box/ranges/contains/evaluationOrderForDownTo.kt b/compiler/testData/codegen/box/ranges/contains/evaluationOrderForDownTo.kt index 6fdc30dcdb7..6ea04b67d1c 100644 --- a/compiler/testData/codegen/box/ranges/contains/evaluationOrderForDownTo.kt +++ b/compiler/testData/codegen/box/ranges/contains/evaluationOrderForDownTo.kt @@ -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" } \ No newline at end of file diff --git a/compiler/testData/codegen/box/ranges/contains/evaluationOrderForDownToReversed.kt b/compiler/testData/codegen/box/ranges/contains/evaluationOrderForDownToReversed.kt new file mode 100644 index 00000000000..fe5c62edf7f --- /dev/null +++ b/compiler/testData/codegen/box/ranges/contains/evaluationOrderForDownToReversed.kt @@ -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" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/ranges/contains/evaluationOrderForNullableArgument.kt b/compiler/testData/codegen/box/ranges/contains/evaluationOrderForNullableArgument.kt new file mode 100644 index 00000000000..0e5899de254 --- /dev/null +++ b/compiler/testData/codegen/box/ranges/contains/evaluationOrderForNullableArgument.kt @@ -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" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/ranges/contains/evaluationOrderForRangeLiteral.kt b/compiler/testData/codegen/box/ranges/contains/evaluationOrderForRangeLiteral.kt index e3dc751bc49..5ab2d3d3794 100644 --- a/compiler/testData/codegen/box/ranges/contains/evaluationOrderForRangeLiteral.kt +++ b/compiler/testData/codegen/box/ranges/contains/evaluationOrderForRangeLiteral.kt @@ -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" } \ No newline at end of file diff --git a/compiler/testData/codegen/box/ranges/contains/evaluationOrderForRangeLiteralReversed.kt b/compiler/testData/codegen/box/ranges/contains/evaluationOrderForRangeLiteralReversed.kt new file mode 100644 index 00000000000..5f96894b6ae --- /dev/null +++ b/compiler/testData/codegen/box/ranges/contains/evaluationOrderForRangeLiteralReversed.kt @@ -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" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntil.kt b/compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntil.kt new file mode 100644 index 00000000000..218a9b24dc2 --- /dev/null +++ b/compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntil.kt @@ -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" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntilReversed.kt b/compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntilReversed.kt new file mode 100644 index 00000000000..c8a1257d939 --- /dev/null +++ b/compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntilReversed.kt @@ -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" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/ranges/contains/inUntilMaxValue.kt b/compiler/testData/codegen/box/ranges/contains/inUntilMaxValue.kt new file mode 100644 index 00000000000..c0b4afd5524 --- /dev/null +++ b/compiler/testData/codegen/box/ranges/contains/inUntilMaxValue.kt @@ -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" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/ranges/contains/inUntilMinValue.kt b/compiler/testData/codegen/box/ranges/contains/inUntilMinValue.kt new file mode 100644 index 00000000000..effd0d71a1c --- /dev/null +++ b/compiler/testData/codegen/box/ranges/contains/inUntilMinValue.kt @@ -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" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/ranges/contains/inUntilMinValueNonConst.kt b/compiler/testData/codegen/box/ranges/contains/inUntilMinValueNonConst.kt new file mode 100644 index 00000000000..0e385ec6f18 --- /dev/null +++ b/compiler/testData/codegen/box/ranges/contains/inUntilMinValueNonConst.kt @@ -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" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/ranges/contains/nullableInPrimitiveRange.kt b/compiler/testData/codegen/box/ranges/contains/nullableInPrimitiveRange.kt index fd05c2601f9..1f3ca5ba7ee 100644 --- a/compiler/testData/codegen/box/ranges/contains/nullableInPrimitiveRange.kt +++ b/compiler/testData/codegen/box/ranges/contains/nullableInPrimitiveRange.kt @@ -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" } \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/ranges/ifNotInRange.kt b/compiler/testData/codegen/bytecodeText/ranges/ifNotInRange.kt index 781ff728cae..0c0515d9c9b 100644 --- a/compiler/testData/codegen/bytecodeText/ranges/ifNotInRange.kt +++ b/compiler/testData/codegen/bytecodeText/ranges/ifNotInRange.kt @@ -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" diff --git a/compiler/testData/codegen/bytecodeText/ranges/inArrayIndices.kt b/compiler/testData/codegen/bytecodeText/ranges/inArrayIndices.kt index 41047e1ed6d..eb11afc1855 100644 --- a/compiler/testData/codegen/bytecodeText/ranges/inArrayIndices.kt +++ b/compiler/testData/codegen/bytecodeText/ranges/inArrayIndices.kt @@ -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) = i in xs.indices @@ -13,4 +11,9 @@ fun testLongWithObjectArray(i: Long, xs: Array) = i in xs.indices // 2 I2L // 4 ARRAYLENGTH // 2 LCONST_0 + +// JVM_TEMPLATES // 6 ICONST_0 + +// JVM_IR_TEMPLATES +// 10 ICONST_0 \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/ranges/inCharSequenceIndices.kt b/compiler/testData/codegen/bytecodeText/ranges/inCharSequenceIndices.kt index dc99f14af48..9c5003f200d 100644 --- a/compiler/testData/codegen/bytecodeText/ranges/inCharSequenceIndices.kt +++ b/compiler/testData/codegen/bytecodeText/ranges/inCharSequenceIndices.kt @@ -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 \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/ranges/inCollectionIndices.kt b/compiler/testData/codegen/bytecodeText/ranges/inCollectionIndices.kt index 68a38503f69..2426d4cf79e 100644 --- a/compiler/testData/codegen/bytecodeText/ranges/inCollectionIndices.kt +++ b/compiler/testData/codegen/bytecodeText/ranges/inCollectionIndices.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// TODO KT-36829 Optimize 'in' expressions in JVM_IR fun testCollection(i: Int, xs: List) = i in xs.indices fun testLongWithCollection(i: Long, xs: List) = i in xs.indices diff --git a/compiler/testData/codegen/bytecodeText/ranges/inNonMatchingRangeIntrinsified.kt b/compiler/testData/codegen/bytecodeText/ranges/inNonMatchingRangeIntrinsified.kt index de8bb4f291b..f55e366030f 100644 --- a/compiler/testData/codegen/bytecodeText/ranges/inNonMatchingRangeIntrinsified.kt +++ b/compiler/testData/codegen/bytecodeText/ranges/inNonMatchingRangeIntrinsified.kt @@ -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 \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/ranges/inOptimizableRange.kt b/compiler/testData/codegen/bytecodeText/ranges/inOptimizableRange.kt index 78f5b56614e..4473c174761 100644 --- a/compiler/testData/codegen/bytecodeText/ranges/inOptimizableRange.kt +++ b/compiler/testData/codegen/bytecodeText/ranges/inOptimizableRange.kt @@ -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 +// 0 contains diff --git a/compiler/testData/codegen/bytecodeText/ranges/inUntil.kt b/compiler/testData/codegen/bytecodeText/ranges/inUntil.kt index cbe4111642a..06a72214abe 100644 --- a/compiler/testData/codegen/bytecodeText/ranges/inUntil.kt +++ b/compiler/testData/codegen/bytecodeText/ranges/inUntil.kt @@ -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 diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 459597c1152..cf348a99c7a 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 3b265583452..b90283acb3e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 39438f9f2a8..05636c326d5 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -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"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java index 2ed565ce31b..cbd580f6750 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java @@ -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"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 057d13d6701..9f6b997105b 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -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"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 83374954f0f..8860b58d810 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -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");