Skip to content

[stdlib] Mark contains methods on Range/ClosedRange transparent #81458

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 6, 2025
2 changes: 2 additions & 0 deletions stdlib/public/core/ClosedRange.swift
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ extension ClosedRange: RangeExpression {
/// - Returns: `true` if `element` is contained in the range; otherwise,
/// `false`.
@inlinable
@inline(__always)
public func contains(_ element: Bound) -> Bool {
return element >= self.lowerBound && element <= self.upperBound
}
Expand Down Expand Up @@ -383,6 +384,7 @@ extension ClosedRange {
///
/// - Complexity: O(1)
@_alwaysEmitIntoClient
@_transparent
public func contains(_ other: ClosedRange<Bound>) -> Bool {
lowerBound <= other.lowerBound && upperBound >= other.upperBound
}
Expand Down
11 changes: 7 additions & 4 deletions stdlib/public/core/Range.swift
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,10 @@ extension RangeExpression {
/// - pattern: A range.
/// - bound: A value to match against `pattern`.
@inlinable
@inline(__always)
public static func ~= (pattern: Self, value: Bound) -> Bool {
return pattern.contains(value)
}
}
}

/// A half-open interval from a lower bound up to, but not including, an upper
Expand Down Expand Up @@ -194,7 +195,7 @@ public struct Range<Bound: Comparable> {
/// - Parameter element: The element to check for containment.
/// - Returns: `true` if `element` is contained in the range; otherwise,
/// `false`.
@inlinable
@_transparent
public func contains(_ element: Bound) -> Bool {
return lowerBound <= element && element < upperBound
}
Expand Down Expand Up @@ -682,7 +683,7 @@ extension PartialRangeFrom: RangeExpression {
) -> Range<Bound> where C.Index == Bound {
return self.lowerBound..<collection.endIndex
}
@inlinable // trivial-implementation
@_transparent
public func contains(_ element: Bound) -> Bool {
return lowerBound <= element
}
Expand Down Expand Up @@ -1074,11 +1075,12 @@ extension Range {
///
/// - Complexity: O(1)
@_alwaysEmitIntoClient
@_transparent
public func contains(_ other: Range<Bound>) -> Bool {
other.isEmpty ||
(lowerBound <= other.lowerBound && upperBound >= other.upperBound)
}

/// Returns a Boolean value indicating whether the given closed range is
/// contained within this range.
///
Expand All @@ -1101,6 +1103,7 @@ extension Range {
///
/// - Complexity: O(1)
@_alwaysEmitIntoClient
@_transparent
public func contains(_ other: ClosedRange<Bound>) -> Bool {
lowerBound <= other.lowerBound && upperBound > other.upperBound
}
Expand Down
43 changes: 43 additions & 0 deletions test/stdlib/RangeContainsInlining.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// RUN: %target-swift-emit-ir -primary-file %s 2>&1 | %FileCheck %s
// RUN: %target-swift-emit-ir -primary-file %s -O 2>&1 | %FileCheck --check-prefixes CHECK,CHECK-OPTIMIZED %s
// RUN: %target-swift-emit-ir -primary-file %s -Osize 2>&1 | %FileCheck --check-prefixes CHECK,CHECK-OPTIMIZED %s

// We expect calls to `Range.contains` to result in direct bound comparisons in
// all compilation modes, including unoptimized builds. (These are often used to
// implement bounds checking.)
//
// The sample functions below use bounds of different integer types to avoid
// them tail-calling each other.

// CHECK-LABEL: define {{.*}} i1 @"$s21RangeContainsInlining08halfOpenB0ySbSnys4Int8VG_ADtF"
// CHECK-NOT: call swiftcc
// CHECK: icmp
// CHECK-NOT: call swiftcc
// CHECK-LABEL: {{^}}}
public func halfOpenContains(_ r: Range<Int8>, _ i: Int8) -> Bool {
r.contains(i)
}

// `ClosedRange.contains is only marked `@inline(__always)`; unfortunately it
// doesn't get inlined in deug builds.

// CHECK-OPTIMIZED-LABEL: define {{.*}} i1 @"$s21RangeContainsInlining06closedB0ySbSNys5Int16VG_ADtF"
// CHECK-OPTIMIZED-NOT: call swiftcc
// CHECK-OPTIMIZED: icmp
// CHECK-OPTIMIZED-NOT: call swiftcc
// CHECK-OPTIMIZED-LABEL: {{^}}}
public func closedContains(_ r: ClosedRange<Int16>, _ i: Int16) -> Bool {
r.contains(i)
}

// `Range.~=` is only marked `@inline(__always)`; unfortunately it doesn't get
// inlined in deug builds.

// CHECK-OPTIMIZED-LABEL: define {{.*}} i1 @"$s21RangeContainsInlining20halfOpenPatternMatchySbSnys5Int32VG_ADtF"
// CHECK-OPTIMIZED-NOT: call swiftcc
// CHECK-OPTIMIZED: icmp
// CHECK-OPTIMIZED-NOT: call swiftcc
// CHECK-OPTIMIZED-LABEL: {{^}}}
public func halfOpenPatternMatch(_ r: Range<Int32>, _ i: Int32) -> Bool {
r ~= i
}