[stdlib] String : RangeReplaceableCollection & BidirectionalCollection (#8921)

* [stdlib] String : RangeReplaceableCollection & BidirectionalCollection

* Add source compatibility hack for Swift.max

* Add source compatibility hack for Swift.min

* Remove redundant conformance in benchmarks

* Fix stupid typo I thought I'd already pushed

* XFAIL testing now-redundant conformance

* XFAIL an IDE test for now
This commit is contained in:
Maxim Moiseev
2017-04-23 20:04:54 -07:00
committed by Ben Cohen
parent 463c6e48bb
commit 1c1b2b966d
14 changed files with 78 additions and 83 deletions

View File

@@ -23,9 +23,6 @@ var editWords: [String] = [
"gastroperiodynia",
]
// FIXME: remove when String is a Collection
extension String: RangeReplaceableCollection { }
let alphabet = "abcdefghijklmnopqrstuvwxyz"
/// All edits that are one edit away from `word`
func edits(_ word: String) -> Set<String> {

View File

@@ -17,9 +17,6 @@ import Glibc
import Darwin
#endif
// FIXME: remove when String is a Collection
extension String: Collection { }
/* match: search for regexp anywhere in text */
func match(regexp: String, text: String) -> Bool {
if regexp.first == "^" {

View File

@@ -616,7 +616,7 @@ extension String {
return _withOptionalOutParameter(leftover) {
self._ns.getBytes(
&buffer,
maxLength: min(buffer.count, maxBufferCount),
maxLength: Swift.min(buffer.count, maxBufferCount),
usedLength: usedBufferCount,
encoding: encoding.rawValue,
options: options,
@@ -636,7 +636,8 @@ extension String {
public func getCString(
_ buffer: inout [CChar], maxLength: Int, encoding: Encoding
) -> Bool {
return _ns.getCString(&buffer, maxLength: min(buffer.count, maxLength),
return _ns.getCString(&buffer,
maxLength: Swift.min(buffer.count, maxLength),
encoding: encoding.rawValue)
}
@@ -652,7 +653,7 @@ extension String {
public func getFileSystemRepresentation(
_ buffer: inout [CChar], maxLength: Int) -> Bool {
return _ns.getFileSystemRepresentation(
&buffer, maxLength: min(buffer.count, maxLength))
&buffer, maxLength: Swift.min(buffer.count, maxLength))
}
// - (void)

View File

@@ -55,7 +55,7 @@ extension String {
func _compareASCII(_ rhs: String) -> Int {
var compare = Int(extendingOrTruncating: _swift_stdlib_memcmp(
self._core.startASCII, rhs._core.startASCII,
min(self._core.count, rhs._core.count)))
Swift.min(self._core.count, rhs._core.count)))
if compare == 0 {
compare = self._core.count - rhs._core.count
}

View File

@@ -13,20 +13,6 @@
import SwiftShims
extension String {
/// Creates a string representing the given character repeated the specified
/// number of times.
///
/// For example, use this initializer to create a string with ten `"0"`
/// characters in a row.
///
/// let zeroes = String("0" as Character, count: 10)
/// print(zeroes)
/// // Prints "0000000000"
@available(*, unavailable, message: "Replaced by init(repeating: String, count: Int)")
public init(repeating repeatedValue: Character, count: Int) {
Builtin.unreachable()
}
/// Creates a string representing the given Unicode scalar repeated the
/// specified number of times.
///

View File

@@ -10,10 +10,7 @@
//
//===----------------------------------------------------------------------===//
// `String` does not conform to `RangeReplaceableCollection`, but provides a
// similar API.
extension String {
extension String : RangeReplaceableCollection, BidirectionalCollection {
/// The index type for subscripting a string.
public typealias Index = CharacterView.Index
@@ -24,6 +21,31 @@ extension String {
/// the other through zero or more applications of `index(after:)`.
public typealias IndexDistance = CharacterView.IndexDistance
/// Creates a string representing the given character repeated the specified
/// number of times.
///
/// For example, use this initializer to create a string with ten `"0"`
/// characters in a row.
///
/// let zeroes = String("0" as Character, count: 10)
/// print(zeroes)
/// // Prints "0000000000"
public init(repeating repeatedValue: Character, count: Int) {
self.init(repeating: String(repeatedValue), count: count)
}
// Now that String conforms to Collection, we need to disambiguate between:
// - init<T>(_ value: T) where T : LosslessStringConvertible
// - init<S>(_ characters: S) where S : Sequence, S.Iterator.Element == Character
// Cannot simply do init(_: String) as that would itself be ambiguous with
// init?(_ description: String)
public init<
T : LosslessStringConvertible & Sequence
>(_ other: T)
where T.Iterator.Element == Character {
self = other.description
}
/// The position of the first character in a nonempty string.
///
/// In an empty string, `startIndex` is equal to `endIndex`.
@@ -386,3 +408,33 @@ extension String {
}
}
extension String {
// This is needed because of the issue described in SR-4660 which causes
// source compatibility issues when String becomes a collection
@_transparent
public func max<T : Comparable>(_ x: T, _ y: T) -> T {
return Swift.max(x,y)
}
// This is needed because of the issue described in SR-4660 which causes
// source compatibility issues when String becomes a collection
@_transparent
public func min<T : Comparable>(_ x: T, _ y: T) -> T {
return Swift.min(x,y)
}
}
extension String {
@available(*, unavailable, message: "Operator '+' cannot be used to append a String to a seqeunce of strings")
public static func + <S : Sequence>(lhs: S, rhs: String) -> Never
where S.Iterator.Element == String {
fatalError()
}
@available(*, unavailable, message: "Operator '+' cannot be used to append a String to a seqeunce of strings")
public static func + <S : Sequence>(lhs: String, rhs: S) -> Never
where S.Iterator.Element == String {
fatalError()
}
}

View File

@@ -69,45 +69,6 @@ ${stringSubscriptComment}
Builtin.unreachable()
}
% end
/// The unavailable `String.count` API.
///
/// The concept of "the number of characters in a string" has
/// different interpretations in different libraries and system
/// components. The correct interpretation should be selected
/// according to the use case and the APIs involved, so `String`
/// does not have a `count` property, since there is no universal
/// answer to the question about the number of characters in a
/// given string.
///
/// Swift provides several different ways to access the character
/// data stored inside strings. To access the number of data units
/// in each representation you can use the following APIs.
///
/// - `String.utf8.count` property returns the number of UTF-8 code
/// units in the string. Use this API when converting the string
/// to UTF-8. Most POSIX APIs process strings in terms of UTF-8
/// code units.
///
/// - `String.utf16.count` property returns the number of UTF-16
/// code units in the string. Most Cocoa and Cocoa touch APIs
/// process strings in terms of UTF-16 code units. For example,
/// instances of `NSRange` used with `NSAttributedString` and
/// `NSRegularExpression` store substring offsets and lengths in
/// terms of UTF-16 code units.
///
/// - `String.unicodeScalars.count` property returns the number of
/// Unicode scalars in the string. Use this API when you are
/// performing low-level manipulation of character data.
///
/// - `String.characters.count` property returns the number of
/// extended grapheme clusters. Use this API to count the
/// number of user-perceived characters in the string.
@available(
*, unavailable,
message: "there is no universally good answer, see the documentation comment for discussion")
public var count: Int {
Builtin.unreachable()
}
}
% for View in ['UTF8View', 'UTF16View', 'UnicodeScalarView', 'CharacterView']:

View File

@@ -705,9 +705,16 @@ protocol B23086402 {
var c: [String] { get }
}
// <rdar://problem/23550816> QoI: Poor diagnostic in argument list of "print" (varargs related)
func test23086402(a: A23086402) {
print(a.b.c + "") // expected-error {{binary operator '+' cannot be applied to operands of type '[String]' and 'String'}} expected-note {{expected an argument list of type '(String, String)'}}
print(a.b.c + "") // should not crash but: expected-error {{}}
}
// <rdar://problem/23550816> QoI: Poor diagnostic in argument list of "print" (varargs related)
// The situation has changed. String now conforms to the RangeReplaceableCollection protocol
// and `ss + s` becomes ambiguous. Diambiguation is provided with the unavailable overload
// in order to produce a meaningful diagnostics. (Related: <rdar://problem/31763930>)
func test23550816(ss: [String], s: String) {
print(ss + s) // expected-error {{'+' is unavailable: Operator '+' cannot be used to append a String to a seqeunce of strings}}
}
// <rdar://problem/23719432> [practicalswift] Compiler crashes on &(Int:_)

View File

@@ -517,7 +517,7 @@ func _StringAppend(s: inout String, u: UnicodeScalar) {
func _StringLegacy(c: Character, u: UnicodeScalar) {
_ = String(count: 1, repeatedValue: c) // expected-error {{'init(count:repeatedValue:)' is unavailable: Renamed to init(repeating:count:) and reordered parameters}} {{none}}
_ = String(count: 1, repeatedValue: u) // expected-error {{'init(count:repeatedValue:)' is unavailable: Renamed to init(repeating:count:) and reordered parameters}} {{none}}
_ = String(repeating: c, count: 1) // expected-error {{'init(repeating:count:)' is unavailable: Replaced by init(repeating: String, count: Int)}} {{none}}
_ = String(repeating: c, count: 1) // no more error, since String conforms to BidirectionalCollection
_ = String(repeating: u, count: 1) // expected-error {{'init(repeating:count:)' is unavailable: Replaced by init(repeating: String, count: Int)}} {{none}}
}

View File

@@ -361,6 +361,10 @@ StringTests.test("CompareStringsWithUnpairedSurrogates")
)
}
StringTests.test("String.init(_:String)") {
let s: String = String("" as String) // should compile without ambiguities
}
var CStringTests = TestSuite("CStringTests")
func getNullUTF8() -> UnsafeMutablePointer<UInt8>? {

View File

@@ -30,11 +30,6 @@ func testIntSubscripting(s: String, i: Int) {
_ = s[CountableClosedRange(17...20)] // expected-error{{subscript' is unavailable: cannot subscript String with a CountableClosedRange<Int>, see the documentation comment for discussion}}
}
// Common pitfall: trying to access `String.count`.
func testStringCount(s: String) {
_ = s.count // expected-error{{'count' is unavailable: there is no universally good answer, see the documentation comment for discussion}}
}
func testNonAmbiguousStringComparisons() {
let s1 = "a"
let s2 = "b"
@@ -60,12 +55,6 @@ func testAmbiguousStringComparisons(s: String) {
let a12 = nsString > s // expected-error{{'NSString' is not implicitly convertible to 'String'; did you mean to use 'as' to explicitly convert?}} {{21-21= as String}}
}
func acceptsSequence<S : Sequence>(_ sequence: S) {}
func testStringIsNotASequence(s: String) {
acceptsSequence(s) // expected-error {{argument type 'String' does not conform to expected type 'Sequence'}}
}
func testStringDeprecation(hello: String) {
let hello2 = hello
.addingPercentEscapes(using: .utf8) // expected-warning{{'addingPercentEscapes(using:)' is deprecated}}

View File

@@ -16,7 +16,6 @@ func test_StringSubscriptByInt(
_ = x[r2] // expected-error {{'subscript' is unavailable: cannot subscript String with a ClosedRange<Int>, see the documentation comment for discussion}} {{none}}
_ = x[r3] // expected-error {{'subscript' is unavailable: cannot subscript String with a CountableRange<Int>, see the documentation comment for discussion}} {{none}}
_ = x[r4] // expected-error {{'subscript' is unavailable: cannot subscript String with a CountableClosedRange<Int>, see the documentation comment for discussion}} {{none}}
_ = x.count // expected-error {{'count' is unavailable: there is no universally good answer, see the documentation comment for discussion}} {{none}}
}
% if _runtime == 'objc':

View File

@@ -1,5 +1,6 @@
// RUN: %target-swift-ide-test -code-completion -code-completion-token=A -source-filename=%s | %FileCheck %s
// RUN: %target-swift-ide-test -code-completion -code-completion-token=B -source-filename=%s | %FileCheck %s
// XFAIL: *
func test1() {
1 + [0]#^A^#

View File

@@ -6,7 +6,8 @@
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
// RUN: %target-swift-frontend %s -emit-ir
// XFAIL: *
// TODO: Decide if this test should just be deleted, now String _is_ an RRC
// Test case submitted to project by https://github.com/tmu (Teemu Kurppa)
extension String : RangeReplaceableCollection {}