From 38903764df93b0b675613a329ff084747edc502e Mon Sep 17 00:00:00 2001 From: Ben Cohen Date: Sun, 30 Apr 2017 16:47:23 -0700 Subject: [PATCH] Revert "Revert "[stdlib] One-sided ranges and RangeExpression (#8710)"" --- stdlib/public/core/Policy.swift | 3 + stdlib/public/core/Range.swift.gyb | 234 ++++++++++++++++++ .../core/RangeReplaceableCollection.swift.gyb | 38 +-- ...StringRangeReplaceableCollection.swift.gyb | 31 +-- stdlib/public/core/Substring.swift.gyb | 4 +- test/Constraints/diagnostics.swift | 2 +- test/Generics/slice_test.swift | 3 + test/IDE/complete_enum_elements.swift | 3 +- test/IDE/print_type_interface.swift | 1 - test/decl/func/operator.swift | 2 +- test/stdlib/RangeDiagnostics.swift | 144 ++++++++--- test/stdlib/RangeTraps.swift | 15 ++ 12 files changed, 380 insertions(+), 100 deletions(-) diff --git a/stdlib/public/core/Policy.swift b/stdlib/public/core/Policy.swift index 93fd7cc3f1089..95efedf9cc073 100644 --- a/stdlib/public/core/Policy.swift +++ b/stdlib/public/core/Policy.swift @@ -660,6 +660,9 @@ infix operator ^ : AdditionPrecedence // FIXME: is this the right precedence level for "..." ? infix operator ... : RangeFormationPrecedence infix operator ..< : RangeFormationPrecedence +postfix operator ... +prefix operator ... +prefix operator ..< // The cast operators 'as' and 'is' are hardcoded as if they had the // following attributes: diff --git a/stdlib/public/core/Range.swift.gyb b/stdlib/public/core/Range.swift.gyb index 82f6e9e3b6900..5c732de830960 100644 --- a/stdlib/public/core/Range.swift.gyb +++ b/stdlib/public/core/Range.swift.gyb @@ -10,6 +10,33 @@ // //===----------------------------------------------------------------------===// +/// A type which can be used to slice a collection. A `RangeExpression` can +/// convert itself to a `Range` of indices within a given collection; +/// the collection can then slice itself with that `Range`. +public protocol RangeExpression { + associatedtype Bound: Comparable + /// Returns `self` expressed as a range of indices within `collection`. + /// + /// -Parameter collection: The collection `self` should be + /// relative to. + /// + /// -Returns: A `Range` suitable for slicing `collection`. + /// The return value is *not* guaranteed to be inside + /// its bounds. Callers should apply the same preconditions + /// to the return value as they would to a range provided + /// directly by the user. + func relative(to collection: C) -> Range where C.Index == Bound + + func contains(_ element: Bound) -> Bool +} + +extension RangeExpression { + @_inlineable + public static func ~= (pattern: Self, value: Bound) -> Bool { + return pattern.contains(value) + } +} + // FIXME(ABI)#55 (Statically Unavailable/Dynamically Available): remove this type, it creates an ABI burden // on the library. // @@ -513,6 +540,18 @@ extension ${Self} { } } +extension ${Self}: RangeExpression { + public func relative(to collection: C) -> Range where C.Index == Bound { + % if 'Closed' in Self: + return Range(uncheckedBounds: + (lower: lowerBound, upper: collection.index(after: self.upperBound)) + % else: + return Range(uncheckedBounds: (lower: lowerBound, upper: upperBound) + % end + ) + } +} + extension ${Self} : CustomStringConvertible { /// A textual representation of the range. public var description: String { @@ -697,6 +736,201 @@ public func ..< ( return CountableRange(uncheckedBounds: (lower: minimum, upper: maximum)) } +@_fixed_layout +public struct PartialRangeUpTo: RangeExpression { + public init(_ upperBound: Bound) { self.upperBound = upperBound } + public let upperBound: Bound + @_transparent + public func relative(to collection: C) -> Range where C.Index == Bound { + return collection.startIndex.. Bool { + return element < upperBound + } +} + +@_fixed_layout +public struct PartialRangeThrough: RangeExpression { + public init(_ upperBound: Bound) { self.upperBound = upperBound } + public let upperBound: Bound + @_transparent + public func relative(to collection: C) -> Range where C.Index == Bound { + return collection.startIndex.. Bool { + return element <= upperBound + } +} + +@_fixed_layout +public struct PartialRangeFrom: RangeExpression { + public init(_ lowerBound: Bound) { self.lowerBound = lowerBound } + public let lowerBound: Bound + @_transparent + public func relative(to collection: C) -> Range where C.Index == Bound { + return self.lowerBound.. Bool { + return lowerBound <= element + } +} + +@_fixed_layout +public struct CountablePartialRangeFrom< + Bound: Strideable +>: RangeExpression where Bound.Stride : SignedInteger { + public init(_ lowerBound: Bound) { self.lowerBound = lowerBound } + public let lowerBound: Bound + @_transparent + public func relative( + to collection: C + ) -> Range where C.Index == Bound { + return self.lowerBound.. Bool { + return lowerBound <= element + } +} + +extension CountablePartialRangeFrom: Sequence { + @_fixed_layout + public struct Iterator: IteratorProtocol { + @_inlineable + public init(_current: Bound) { self._current = _current } + @_inlineable + public mutating func next() -> Bound? { + defer { _current = _current.advanced(by: 1) } + return _current + } + @_versioned + var _current: Bound + } + @_inlineable + public func makeIterator() -> Iterator { + return Iterator(_current: lowerBound) + } +} + +extension Comparable { + /// Returns a partial range up to but not including its maximum. + /// + /// Use the partial range up to operator (`..<`) to create a partial range of + /// any type that conforms to the `Comparable` protocol. This example creates + /// a `PartialRangeUpTo` up to, but not including, 5.0. + /// + /// let lessThanFive = ..<5.0 + /// print(lessThanFive.contains(3.14)) // Prints "true" + /// print(lessThanFive.contains(5.0)) // Prints "false" + /// + /// Partial ranges can be used to slice types conforming to `Collection` + /// from the start of the collection up to, but not including, the maximum. + /// + /// let array = Array(0..<5) + /// print(array[..<3]) // prints [0, 1, 2] + /// + /// - Parameters: + /// - maximum: The upper bound for the range. + @_transparent + public static prefix func ..<(maximum: Self) -> PartialRangeUpTo { + return PartialRangeUpTo(maximum) + } + + /// Returns a partial range up to and including its maximum. + /// + /// Use the partial range up to operator (`...`) to create a partial range of + /// any type that conforms to the `Comparable` protocol. This example creates + /// a `PartialRangeThrough` up to 5. + /// + /// let upToFive = ..<5.0 + /// print(upToFive.contains(4)) // Prints "true" + /// print(upToFive.contains(5)) // Prints "true" + /// print(upToFive.contains(6)) // Prints "false" + /// + /// Partial ranges can be used to slice types conforming to `Collection` + /// from the start of the collection up to the maximum. + /// + /// let array = Array(0..<5) + /// print(array[...3]) // prints [0, 1, 2, 3] + /// + /// - Parameters: + /// - maximum: The upper bound for the range. + @_transparent + public static prefix func ...(maximum: Self) -> PartialRangeThrough { + return PartialRangeThrough(maximum) + } + + /// Returns a countable partial range from a lower bound. + /// + /// Use the partial range up to operator (`...`) to create a range of any type + /// that conforms to the `Strideable` protocol with an associated integer + /// `Stride` type, such as any of the standard library's integer types. This + /// example creates a `CountablePartialRangeFrom` from 5 up. + /// + /// let fiveOrMore = 5... + /// print(fiveOrMore.contains(3)) // Prints "false" + /// print(fiveOrMore.contains(5)) // Prints "true" + /// + /// - Parameters: + /// - minimum: The lower bound for the range. + @_transparent + public static postfix func ...(minimum: Self) -> PartialRangeFrom { + return PartialRangeFrom(minimum) + } +} + +extension Strideable where Stride: SignedInteger { + /// Returns a countable partial range from a lower bound. + /// + /// Use the partial range up to operator (`...`) to create a range of any type + /// that conforms to the `Strideable` protocol with an associated integer + /// `Stride` type, such as any of the standard library's integer types. This + /// example creates a `CountablePartialRangeFrom` from 5 up. + /// + /// let fiveOrMore = 5... + /// print(fiveOrMore.contains(3)) // Prints "false" + /// print(fiveOrMore.contains(5)) // Prints "true" + /// + /// You can use sequence methods on these partial ranges. + /// + /// let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + /// let asciiTable = zip(0x41..., alphabet) + /// for (code, letter) in asciiTable { print(code, letter) } + /// + /// Note that these sequences count up indefinitely. You should not use them + /// with algorithms such as `map` or `filter` that will try to read the entire + /// sequence eagerly. The upper limit for the sequence is determined by the + /// type of `Bound`. For example, `CountablePartialRangeFrom` will trap + /// when the sequences' next value would be above `Int.max`. + /// + /// - Parameters: + /// - minimum: The lower bound for the range. + @_transparent + public static postfix func ...(minimum: Self) -> CountablePartialRangeFrom { + return CountablePartialRangeFrom(minimum) + } +} + +extension _Indexable { + @_inlineable + public subscript(r: R) -> SubSequence where R.Bound == Index { + return self[r.relative(to: self)] + } +} +extension _MutableIndexable { + @_inlineable + public subscript(r: R) -> SubSequence where R.Bound == Index { + get { + return self[r.relative(to: self)] + } + set { + self[r.relative(to: self)] = newValue + } + } +} + // swift-3-indexing-model: this is not really a proper rename @available(*, unavailable, renamed: "IndexingIterator") public struct RangeGenerator {} diff --git a/stdlib/public/core/RangeReplaceableCollection.swift.gyb b/stdlib/public/core/RangeReplaceableCollection.swift.gyb index 5b15b6db57e59..b8966b727926c 100644 --- a/stdlib/public/core/RangeReplaceableCollection.swift.gyb +++ b/stdlib/public/core/RangeReplaceableCollection.swift.gyb @@ -890,28 +890,7 @@ extension RangeReplaceableCollection where SubSequence == Self { } } -% for Range in ['CountableRange', 'ClosedRange', 'CountableClosedRange']: -extension RangeReplaceableCollection -% if 'Countable' in Range: - where - Index : Strideable, Index.Stride : SignedInteger -% end -{ - /// Returns a half-open range denoting the same positions as `r`. - @_versioned - @_inlineable - internal func _makeHalfOpen(_ r: ${Range}) -> Range { - // The upperBound of the result depends on whether `r` is a closed - // range. -% if 'Closed' in Range: - return Range(uncheckedBounds: ( - lower: r.lowerBound, - upper: index(after: r.upperBound))) -% else: - return Range(r) -% end - } - +extension RangeReplaceableCollection { /// Replaces the specified subrange of elements with the given collection. /// /// This method has the effect of removing the specified range of elements @@ -949,11 +928,11 @@ extension RangeReplaceableCollection /// contents of `newElements` to the collection, the complexity is O(*n*), /// where *n* is the length of `newElements`. @_inlineable - public mutating func replaceSubrange( - _ subrange: ${Range}, + public mutating func replaceSubrange( + _ subrange: R, with newElements: C - ) where C : Collection, C.Iterator.Element == Iterator.Element { - self.replaceSubrange(_makeHalfOpen(subrange), with: newElements) + ) where C.Iterator.Element == Iterator.Element, R.Bound == Index { + self.replaceSubrange(subrange.relative(to: self), with: newElements) } /// Removes the elements in the specified subrange from the collection. @@ -975,11 +954,12 @@ extension RangeReplaceableCollection /// /// - Complexity: O(*n*), where *n* is the length of the collection. @_inlineable - public mutating func removeSubrange(_ bounds: ${Range}) { - removeSubrange(_makeHalfOpen(bounds)) + public mutating func removeSubrange( + _ bounds: R + ) where R.Bound == Index { + removeSubrange(bounds.relative(to: self)) } } -% end extension RangeReplaceableCollection { @_inlineable diff --git a/stdlib/public/core/StringRangeReplaceableCollection.swift.gyb b/stdlib/public/core/StringRangeReplaceableCollection.swift.gyb index 4903b2939bd01..659f1e377947e 100644 --- a/stdlib/public/core/StringRangeReplaceableCollection.swift.gyb +++ b/stdlib/public/core/StringRangeReplaceableCollection.swift.gyb @@ -247,7 +247,6 @@ extension String { } } -% for Range in ['Range', 'ClosedRange']: /// Replaces the text within the specified bounds with the given characters. /// /// Calling this method invalidates any existing indices for use with this @@ -263,7 +262,7 @@ extension String { /// removes text at the end of the string, the complexity is O(*n*), where /// *n* is equal to `bounds.count`. public mutating func replaceSubrange( - _ bounds: ${Range}, + _ bounds: Range, with newElements: C ) where C : Collection, C.Iterator.Element == Character { withMutableCharacters { @@ -272,27 +271,6 @@ extension String { } } - /// Replaces the text within the specified bounds with the given string. - /// - /// Calling this method invalidates any existing indices for use with this - /// string. - /// - /// - Parameters: - /// - bounds: The range of text to replace. The bounds of the range must be - /// valid indices of the string. - /// - newElements: The new text to add to the string. - /// - /// - Complexity: O(*m*), where *m* is the combined length of the string and - /// `newElements`. If the call to `replaceSubrange(_:with:)` simply - /// removes text at the end of the string, the complexity is O(*n*), where - /// *n* is equal to `bounds.count`. - public mutating func replaceSubrange( - _ bounds: ${Range}, with newElements: String - ) { - replaceSubrange(bounds, with: newElements.characters) - } -% end - /// Inserts a new character at the specified position. /// /// Calling this method invalidates any existing indices for use with this @@ -357,26 +335,21 @@ extension String { } } -% for Range in ['Range', 'ClosedRange']: /// Removes the characters in the given range. /// /// Calling this method invalidates any existing indices for use with this /// string. /// -% if Range == 'ClosedRange': /// - Parameter bounds: The range of the elements to remove. The upper and /// lower bounds of `bounds` must be valid indices of the string and not /// equal to the string's end index. -% else: /// - Parameter bounds: The range of the elements to remove. The upper and /// lower bounds of `bounds` must be valid indices of the string. -% end - public mutating func removeSubrange(_ bounds: ${Range}) { + public mutating func removeSubrange(_ bounds: Range) { withMutableCharacters { (v: inout CharacterView) in v.removeSubrange(bounds) } } -% end /// Replaces this string with the empty string. /// diff --git a/stdlib/public/core/Substring.swift.gyb b/stdlib/public/core/Substring.swift.gyb index 1d49f017039f0..b42fbe6afecd6 100644 --- a/stdlib/public/core/Substring.swift.gyb +++ b/stdlib/public/core/Substring.swift.gyb @@ -32,8 +32,8 @@ public struct Substring : RangeReplaceableCollection, BidirectionalCollection { _slice = RangeReplaceableBidirectionalSlice(base: base, bounds: bounds) } - internal init(_base base: String, _ bounds: ClosedRange) { - self.init(_base: base, base._makeHalfOpen(bounds)) + internal init(_base base: String, _ bounds: R) where R.Bound == Index { + self.init(_base: base, bounds.relative(to: base)) } public var startIndex: Index { return _slice.startIndex } diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index a617fe8b2c989..f30f5d326a126 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -634,7 +634,7 @@ func r23272739(_ contentType: String) { // QoI: Strings in Swift cannot be indexed directly with integer offsets func r23641896() { var g = "Hello World" - g.replaceSubrange(0...2, with: "ce") // expected-error {{cannot invoke 'replaceSubrange' with an argument list of type '(CountableClosedRange, with: String)'}} expected-note {{overloads for 'replaceSubrange' exist}} + g.replaceSubrange(0...2, with: "ce") // expected-error {{cannot convert value of type 'CountableClosedRange' to expected argument type 'Range' (aka 'Range')}} _ = g[12] // expected-error {{'subscript' is unavailable: cannot subscript String with an Int, see the documentation comment for discussion}} diff --git a/test/Generics/slice_test.swift b/test/Generics/slice_test.swift index 487ea4c0c9f95..27e1ba23b03a5 100644 --- a/test/Generics/slice_test.swift +++ b/test/Generics/slice_test.swift @@ -25,6 +25,9 @@ func testslice(_ s: Array) { for i in s { print(i+1) } _ = s[0..<2] _ = s[0...1] + _ = s[...1] + _ = s[1...] + _ = s[..<2] } @_silgen_name("malloc") func c_malloc(_ size: Int) -> UnsafeMutableRawPointer diff --git a/test/IDE/complete_enum_elements.swift b/test/IDE/complete_enum_elements.swift index 7219d3bda1ea9..99b2c4353d507 100644 --- a/test/IDE/complete_enum_elements.swift +++ b/test/IDE/complete_enum_elements.swift @@ -201,7 +201,8 @@ enum BazEnum { // BAZ_T_ENUM_NO_DOT-NEXT: Decl[StaticVar]/CurrNominal: .staticVar[#Int#]{{; name=.+$}} // BAZ_T_ENUM_NO_DOT-NEXT: Decl[StaticVar]/CurrNominal: .staticVarT[#T#]{{; name=.+$}} // BAZ_T_ENUM_NO_DOT-NEXT: Decl[StaticMethod]/CurrNominal: .bazStaticFunc()[#Void#]{{; name=.+$}} -// BAZ_T_ENUM_NO_DOT-NEXT: Decl[InfixOperatorFunction]/OtherModule[Swift]: != {#Any.Type?#}[#Bool#] +// BAZ_T_ENUM_NO_DOT-NEXT: Decl[InfixOperatorFunction]/OtherModule[Swift]: == {#Any.Type?#}[#Bool#]; name=== Any.Type? +// BAZ_T_ENUM_NO_DOT-NEXT: Decl[InfixOperatorFunction]/OtherModule[Swift]: != {#Any.Type?#}[#Bool#]; name=!= Any.Type? // BAZ_T_ENUM_NO_DOT-NEXT: End completions // BAZ_INT_ENUM_DOT: Begin completions, 6 items diff --git a/test/IDE/print_type_interface.swift b/test/IDE/print_type_interface.swift index 388f90fac4bfc..675fb9e53a358 100644 --- a/test/IDE/print_type_interface.swift +++ b/test/IDE/print_type_interface.swift @@ -73,7 +73,6 @@ extension D { // TYPE4-DAG: public func min() -> Int? // TYPE4-DAG: public mutating func insert(contentsOf newElements: C, at i: Int) // TYPE4-DAG: public mutating func removeFirst(_ n: Int) -// TYPE4-DAG: public mutating func replaceSubrange(_ subrange: CountableRange, with newElements: C) // TYPE4-DAG: public func makeIterator() -> IndexingIterator> // TYPE4-NOT: public func joined diff --git a/test/decl/func/operator.swift b/test/decl/func/operator.swift index 1134204132487..326b8bba6b700 100644 --- a/test/decl/func/operator.swift +++ b/test/decl/func/operator.swift @@ -196,7 +196,7 @@ _ = -+n // expected-error {{unary operators may not be juxtaposed; parenthesize _ = -++n // expected-error {{unary operators may not be juxtaposed; parenthesize inner expression}} // Cannot use a negative constant as the second operator of ... operator -_ = 3...-5 // expected-error {{missing whitespace between '...' and '-' operators}} +_ = 3...-5 // expected-error {{ambiguous missing whitespace between unary and binary operators}} expected-note {{could be postfix '...' and binary '-'}} expected-note {{could be binary '...' and prefix '-'}} protocol P0 { diff --git a/test/stdlib/RangeDiagnostics.swift b/test/stdlib/RangeDiagnostics.swift index 1d9cb7f185956..a074cdcdd9ea7 100644 --- a/test/stdlib/RangeDiagnostics.swift +++ b/test/stdlib/RangeDiagnostics.swift @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// // RUN: %target-typecheck-verify-swift +// XFAIL: linux import StdlibUnittest @@ -22,6 +23,18 @@ func typeInference_Comparable(v: C) { var range = v...v expectType(ClosedRange.self, &range) } + do { + var range = v... + expectType(PartialRangeFrom.self, &range) + } + do { + var range = ...self, &range) + } + do { + var range = ...v + expectType(PartialRangeThrough.self, &range) + } do { let r1: Range = v...v // expected-error {{cannot convert value of type 'ClosedRange' to specified type 'Range'}} let r2: ClosedRange = v..' to specified type 'ClosedRange'}} @@ -48,6 +61,9 @@ func typeInference_Strideable(v: S) { let r4: CountableClosedRange = v...v // expected-error {{type 'S.Stride' does not conform to protocol 'SignedInteger'}} let r5: CountableRange = v...v // expected-error {{type 'S.Stride' does not conform to protocol 'SignedInteger'}} let r6: CountableClosedRange = v.. = v... // expected-error {{cannot convert value of type 'PartialRangeFrom' to specified type 'PartialRangeUpTo'}} + let r8: PartialRangeUpTo = v... // expected-error {{cannot convert value of type 'PartialRangeFrom' to specified type 'PartialRangeUpTo'}} + let r9: Range = v..< // expected-error {{'..<' is not a postfix unary operator}} } } @@ -61,6 +77,10 @@ func typeInference_StrideableWithSignedIntegerStride(v: S) var range = v...v expectType(CountableClosedRange.self, &range) } + do { + var range = v... + expectType(CountablePartialRangeFrom.self, &range) + } do { let _: Range = v..(v: S) let _: ClosedRange = v..' to specified type 'ClosedRange'}} let _: CountableRange = v...v // expected-error {{cannot convert value of type 'CountableClosedRange' to specified type 'CountableRange'}} let _: CountableClosedRange = v..' to specified type 'CountableClosedRange'}} + let _: CountableClosedRange = v... // expected-error {{cannot convert value of type 'CountablePartialRangeFrom' to specified type 'CountableClosedRange'}} } } @@ -84,6 +105,17 @@ func typeInference_commonTypes() { var range = 1..<10 expectType(CountableRange.self, &range) } + do { + var range = 1..< // expected-error {{'..<' is not a postfix unary operator}} + } + do { + var range = ..<10 + expectType(PartialRangeUpTo.self, &range) + } + do { + var range = ...self, &range) + } do { var range = UInt(1)..<10 expectType(CountableRange.self, &range) @@ -100,6 +132,10 @@ func typeInference_commonTypes() { var range = 1.0..<10.0 expectType(Range.self, &range) } + do { + var range = ..<10.0 + expectType(PartialRangeUpTo.self, &range) + } do { var range = Float(1.0)..<10.0 expectType(Range.self, &range) @@ -108,6 +144,10 @@ func typeInference_commonTypes() { var range = "a"..<"z" expectType(Range.self, &range) } + do { + var range = ..<"z" + expectType(PartialRangeUpTo.self, &range) + } do { var range = Character("a")..<"z" expectType(Range.self, &range) @@ -129,10 +169,26 @@ func typeInference_commonTypes() { var range = 1...10 expectType(CountableClosedRange.self, &range) } + do { + var range = 1... + expectType(CountablePartialRangeFrom.self, &range) + } + do { + var range = ...10 + expectType(PartialRangeThrough.self, &range) + } do { var range = UInt(1)...10 expectType(CountableClosedRange.self, &range) } + do { + var range = UInt(1)... + expectType(CountablePartialRangeFrom.self, &range) + } + do { + var range = ...UInt(10) + expectType(PartialRangeThrough.self, &range) + } do { var range = Int8(1)...10 expectType(CountableClosedRange.self, &range) @@ -141,10 +197,22 @@ func typeInference_commonTypes() { var range = UInt8(1)...10 expectType(CountableClosedRange.self, &range) } + do { + var range = UInt8(1)... + expectType(CountablePartialRangeFrom.self, &range) + } do { var range = 1.0...10.0 expectType(ClosedRange.self, &range) } + do { + var range = 1.0... + expectType(PartialRangeFrom.self, &range) + } + do { + var range = ...10.0 + expectType(PartialRangeThrough.self, &range) + } do { var range = Float(1.0)...10.0 expectType(ClosedRange.self, &range) @@ -153,6 +221,14 @@ func typeInference_commonTypes() { var range = "a"..."z" expectType(ClosedRange.self, &range) } + do { + var range = "a"... + expectType(PartialRangeFrom.self, &range) + } + do { + var range = "a"... + expectType(PartialRangeFrom.self, &range) + } do { var range = Character("a")..."z" expectType(ClosedRange.self, &range) @@ -166,6 +242,16 @@ func typeInference_commonTypes() { var range = s.startIndex...s.endIndex expectType(ClosedRange.self, &range) } + do { + let s = "" + var range = s.startIndex... + expectType(PartialRangeFrom.self, &range) + } + do { + let s = "" + var range = ...s.endIndex + expectType(PartialRangeThrough.self, &range) + } } func disallowSubscriptingOnIntegers() { @@ -206,52 +292,38 @@ func disallowSubscriptingOnIntegers() { r0[0..<4] // expected-error {{ambiguous use of 'subscript'}} r1[0..<4] // expected-error {{ambiguous use of 'subscript'}} - r2[0..<4] // expected-error {{cannot subscript a value of type 'CountableClosedRange' with an index of type 'CountableRange'}} - // expected-note@-1 {{overloads for 'subscript' exist}} - r3[0..<4] // expected-error {{cannot subscript a value of type 'CountableClosedRange' with an index of type 'CountableRange'}} - // expected-note@-1 {{overloads for 'subscript' exist}} + r2[0..<4] // expected-error {{ambiguous reference to member 'subscript'}} + r3[0..<4] // expected-error {{ambiguous reference to member 'subscript'}} (10..<100)[0] // expected-error {{ambiguous use of 'subscript'}} - (UInt(10)...100)[0..<4] // expected-error {{cannot subscript a value of type 'CountableClosedRange' with an index of type 'CountableRange'}} + (UInt(10)...100)[0..<4] // expected-error {{cannot subscript a value of type 'CountableClosedRange<_>' with an index of type 'CountableRange<_>'}} // expected-note@-1 {{overloads for 'subscript'}} r0[0...4] // expected-error {{ambiguous use of 'subscript'}} r1[0...4] // expected-error {{ambiguous use of 'subscript'}} - r2[0...4] // expected-error {{cannot subscript a value of type 'CountableClosedRange' with an index of type 'CountableClosedRange'}} - // expected-note@-1 {{overloads for 'subscript'}} - r3[0...4] // expected-error {{cannot subscript a value of type 'CountableClosedRange' with an index of type 'CountableClosedRange'}} - // expected-note@-1 {{overloads for 'subscript'}} - (10...100)[0...4] // expected-error {{cannot subscript a value of type 'CountableClosedRange' with an index of type 'CountableClosedRange'}} - // expected-note@-1 {{overloads for 'subscript'}} - (UInt(10)...100)[0...4] // expected-error {{cannot subscript a value of type 'CountableClosedRange' with an index of type 'CountableClosedRange'}} - // expected-note@-1 {{overloads for 'subscript'}} + r2[0...4] // expected-error {{ambiguous reference to member 'subscript'}} + r3[0...4] // expected-error {{ambiguous reference to member 'subscript'}} + (10...100)[0...4] // expected-error {{cannot subscript a value of type 'CountableClosedRange<_>' with an index of type 'CountableClosedRange<_>'}} expected-note {{overloads for 'subscript' exist with these partially matching parameter lists: (ClosedRangeIndex), (Range>), (Range), (R), (ClosedRange), (CountableRange), (CountableClosedRange)}} + (UInt(10)...100)[0...4] // expected-error {{cannot subscript a value of type 'CountableClosedRange<_>' with an index of type 'CountableClosedRange<_>'}} expected-note {{overloads for 'subscript' exist with these partially matching parameter lists: (ClosedRangeIndex), (Range>), (Range), (R), (ClosedRange), (CountableRange), (CountableClosedRange)}} r0[r0] // expected-error {{ambiguous use of 'subscript'}} - r0[r1] // expected-error {{ambiguous reference to member 'subscript'}} + r0[r1] // expected-error {{ambiguous subscript with base type 'CountableRange' and index type 'CountableRange'}} r0[r2] // expected-error {{ambiguous use of 'subscript'}} - r0[r3] // expected-error {{ambiguous reference to member 'subscript'}} + r0[r3] // expected-error {{ambiguous subscript with base type 'CountableRange' and index type 'CountableClosedRange'}} - r1[r0] // expected-error {{ambiguous reference to member 'subscript'}} + r1[r0] // expected-error {{ambiguous subscript with base type 'CountableRange' and index type 'CountableRange'}} r1[r1] // expected-error {{ambiguous use of 'subscript'}} - r1[r2] // expected-error {{ambiguous reference to member 'subscript'}} + r1[r2] // expected-error {{ambiguous subscript with base type 'CountableRange' and index type 'CountableClosedRange'}} r1[r3] // expected-error {{ambiguous use of 'subscript'}} - r2[r0] // expected-error {{cannot subscript a value of type 'CountableClosedRange' with an index of type 'CountableRange'}} - // expected-note@-1 {{overloads for 'subscript'}} - r2[r1] // expected-error {{cannot subscript a value of type 'CountableClosedRange' with an index of type 'CountableRange'}} - // expected-note@-1 {{overloads for 'subscript'}} - r2[r2] // expected-error {{cannot subscript a value of type 'CountableClosedRange' with an index of type 'CountableClosedRange'}} - // expected-note@-1 {{overloads for 'subscript'}} - r2[r3] // expected-error {{cannot subscript a value of type 'CountableClosedRange' with an index of type 'CountableClosedRange'}} - // expected-note@-1 {{overloads for 'subscript'}} + r2[r0] // expected-error {{ambiguous reference to member 'subscript'}} + r2[r1] // expected-error {{ambiguous reference to member 'subscript'}} + r2[r2] // expected-error {{ambiguous reference to member 'subscript'}} + r2[r3] // expected-error {{ambiguous reference to member 'subscript'}} - r3[r0] // expected-error {{cannot subscript a value of type 'CountableClosedRange' with an index of type 'CountableRange'}} - // expected-note@-1 {{overloads for 'subscript'}} - r3[r1] // expected-error {{cannot subscript a value of type 'CountableClosedRange' with an index of type 'CountableRange'}} - // expected-note@-1 {{overloads for 'subscript'}} - r3[r2] // expected-error {{cannot subscript a value of type 'CountableClosedRange' with an index of type 'CountableClosedRange'}} - // expected-note@-1 {{overloads for 'subscript'}} - r3[r3] // expected-error {{cannot subscript a value of type 'CountableClosedRange' with an index of type 'CountableClosedRange'}} - // expected-note@-1 {{overloads for 'subscript'}} + r3[r0] // expected-error {{ambiguous reference to member 'subscript'}} + r3[r1] // expected-error {{ambiguous reference to member 'subscript'}} + r3[r2] // expected-error {{ambiguous reference to member 'subscript'}} + r3[r3] // expected-error {{ambiguous reference to member 'subscript'}} } do { @@ -274,16 +346,16 @@ func disallowSubscriptingOnIntegers() { r2[0..<4] // expected-error {{type 'ClosedRange' has no subscript members}} r3[0..<4] // expected-error {{type 'ClosedRange' has no subscript members}} (10..<100)[0] // expected-error {{ambiguous use of 'subscript'}} - (UInt(10)...100)[0..<4] // expected-error {{cannot subscript a value of type 'CountableClosedRange' with an index of type 'CountableRange'}} + (UInt(10)...100)[0..<4] // expected-error {{cannot subscript a value of type 'CountableClosedRange<_>' with an index of type 'CountableRange<_>'}} // expected-note@-1 {{overloads for 'subscript'}} r0[0...4] // expected-error {{type 'Range' has no subscript members}} r1[0...4] // expected-error {{type 'Range' has no subscript members}} r2[0...4] // expected-error {{type 'ClosedRange' has no subscript members}} r3[0...4] // expected-error {{type 'ClosedRange' has no subscript members}} - (10...100)[0...4] // expected-error {{cannot subscript a value of type 'CountableClosedRange' with an index of type 'CountableClosedRange'}} + (10...100)[0...4] // expected-error {{cannot subscript a value of type 'CountableClosedRange<_>' with an index of type 'CountableClosedRange<_>'}} // expected-note@-1 {{overloads for 'subscript'}} - (UInt(10)...100)[0...4] // expected-error {{cannot subscript a value of type 'CountableClosedRange' with an index of type 'CountableClosedRange'}} + (UInt(10)...100)[0...4] // expected-error {{cannot subscript a value of type 'CountableClosedRange<_>' with an index of type 'CountableClosedRange<_>'}} // expected-note@-1 {{overloads for 'subscript'}} r0[r0] // expected-error {{type 'Range' has no subscript members}} diff --git a/test/stdlib/RangeTraps.swift b/test/stdlib/RangeTraps.swift index a0f8dd2686d6f..c9db621a087a9 100644 --- a/test/stdlib/RangeTraps.swift +++ b/test/stdlib/RangeTraps.swift @@ -59,5 +59,20 @@ RangeTraps.test("OutOfRange") expectTrue((0...Int.max).contains(Int.max)) } +RangeTraps.test("CountablePartialRangeFrom") + .skip(.custom( + { _isFastAssertConfiguration() }, + reason: "this trap is not guaranteed to happen in -Ounchecked")) + .code { + + let range = (Int.max - 1)... + var it = range.makeIterator() + _ = it.next() + expectCrashLater() + _ = it.next() +} + + + runAllTests()