diff --git a/libraries/stdlib/common/src/generated/_Ranges.kt b/libraries/stdlib/common/src/generated/_Ranges.kt index 792cb5ad3c3..7af596ba3d5 100644 --- a/libraries/stdlib/common/src/generated/_Ranges.kt +++ b/libraries/stdlib/common/src/generated/_Ranges.kt @@ -93,6 +93,39 @@ public fun CharRange.random(random: Random): Char { } } +/** + * Returns `true` if this range contains the specified [element]. + * + * Always returns `false` if the [element] is `null`. + */ +@SinceKotlin("1.3") +@kotlin.internal.InlineOnly +public inline operator fun IntRange.contains(element: Int?): Boolean { + return element != null && contains(element) +} + +/** + * Returns `true` if this range contains the specified [element]. + * + * Always returns `false` if the [element] is `null`. + */ +@SinceKotlin("1.3") +@kotlin.internal.InlineOnly +public inline operator fun LongRange.contains(element: Long?): Boolean { + return element != null && contains(element) +} + +/** + * Returns `true` if this range contains the specified [element]. + * + * Always returns `false` if the [element] is `null`. + */ +@SinceKotlin("1.3") +@kotlin.internal.InlineOnly +public inline operator fun CharRange.contains(element: Char?): Boolean { + return element != null && contains(element) +} + /** * Checks if the specified [value] belongs to this range. */ diff --git a/libraries/stdlib/common/src/generated/_URanges.kt b/libraries/stdlib/common/src/generated/_URanges.kt index f507ff246b8..1ea59ae0679 100644 --- a/libraries/stdlib/common/src/generated/_URanges.kt +++ b/libraries/stdlib/common/src/generated/_URanges.kt @@ -72,6 +72,30 @@ public fun ULongRange.random(random: Random): ULong { } } +/** + * Returns `true` if this range contains the specified [element]. + * + * Always returns `false` if the [element] is `null`. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline operator fun UIntRange.contains(element: UInt?): Boolean { + return element != null && contains(element) +} + +/** + * Returns `true` if this range contains the specified [element]. + * + * Always returns `false` if the [element] is `null`. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline operator fun ULongRange.contains(element: ULong?): Boolean { + return element != null && contains(element) +} + /** * Returns a progression from this value down to the specified [to] value with the step -1. * diff --git a/libraries/stdlib/src/kotlin/ranges/Ranges.kt b/libraries/stdlib/src/kotlin/ranges/Ranges.kt index 0abc26bb6f5..1bee0e844ce 100644 --- a/libraries/stdlib/src/kotlin/ranges/Ranges.kt +++ b/libraries/stdlib/src/kotlin/ranges/Ranges.kt @@ -98,6 +98,17 @@ public operator fun > T.rangeTo(that: T): ClosedRange = Com public operator fun Double.rangeTo(that: Double): ClosedFloatingPointRange = ClosedDoubleRange(this, that) +/** + * Returns `true` if this iterable range contains the specified [element]. + * + * Always returns `false` if the [element] is `null`. + */ +@SinceKotlin("1.3") +@kotlin.internal.InlineOnly +public inline operator fun R.contains(element: T?): Boolean where T : Any, R : Iterable, R : ClosedRange = + element != null && contains(element) + + internal fun checkStepIsPositive(isPositive: Boolean, step: Number) { if (!isPositive) throw IllegalArgumentException("Step must be positive, was: $step.") } diff --git a/libraries/stdlib/test/ranges/RangeTest.kt b/libraries/stdlib/test/ranges/RangeTest.kt index 2ca24d027ef..6f294f27907 100644 --- a/libraries/stdlib/test/ranges/RangeTest.kt +++ b/libraries/stdlib/test/ranges/RangeTest.kt @@ -38,6 +38,10 @@ public class RangeTest { assertFalse(Long.MAX_VALUE in range) + assertFalse(null in range) + assertTrue(1 as Int? in range) + assertFalse(10 as Int? in range) + val openRange = 1 until 10 assertTrue(9 in openRange) assertFalse(10 in openRange) @@ -73,6 +77,8 @@ public class RangeTest { assertFalse(Long.MAX_VALUE in range) + // assertTrue(1.toByte() as Byte? in range) // expected not to compile + val openRange = 1.toByte() until 10.toByte() assertTrue(9.toByte() in openRange) assertFalse(10.toByte() in openRange) @@ -109,6 +115,8 @@ public class RangeTest { assertFalse(Long.MAX_VALUE in range) + // assertTrue(1.toShort() as Short? in range) // expected not to compile + val openRange = 1.toShort() until 10.toShort() assertTrue(9.toShort() in openRange) assertFalse(10.toShort() in openRange) @@ -147,6 +155,9 @@ public class RangeTest { assertFalse(Double.MAX_VALUE in range) } + assertFalse(null in range) + assertTrue(1L as Long? in range) + assertFalse(10L as Long? in range) val openRange = 1L until 10L assertTrue(9L in openRange) @@ -177,6 +188,10 @@ public class RangeTest { assertTrue('v' in (range as ClosedRange)) assertFalse((range as ClosedRange).isEmpty()) + assertFalse(null in range) + assertTrue('p' as Char? in range) + assertFalse('z' as Char? in range) + val openRange = 'A' until 'Z' assertTrue('Y' in openRange) assertFalse('Z' in openRange) diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Ranges.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Ranges.kt index 3479b75741e..ad7a5bf1b13 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Ranges.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Ranges.kt @@ -174,6 +174,25 @@ object RangeOps : TemplateGroupBase() { } } + val f_contains_nullable = fn("contains(element: T?)") { + include(RangesOfPrimitives, rangePrimitives) + } builder { + since("1.3") + operator() + inlineOnly() + + doc { + """ + Returns `true` if this ${f.collection} contains the specified [element]. + + Always returns `false` if the [element] is `null`. + """ + } + + returns("Boolean") + body { "return element != null && contains(element)" } + } + val f_toPrimitiveExactOrNull = fn("to{}ExactOrNull()").byTwoPrimitives { include(Primitives, numericPermutations) filter { _, (fromType, toType) -> fromType.capacity > toType.capacity && toType.isIntegral() }