Skip to content

Commit

Permalink
[stdlib] Availability checking for String.*View.popFirst
Browse files Browse the repository at this point in the history
Collection's popFirst is only present when the Collection is its own
SubSequence type. String and String's views are no longer their own
SubSequenes, so popFirst is no longer present. Unfortunately, this
breaks code in swift-version 3 and it also gives a terrible diagnostic
to users. This change introduces an implementation for swift-version 3
mode and better diagnostics for Swift 4 code. Tests included.
  • Loading branch information
milseman committed Aug 8, 2017
1 parent 0b5ee16 commit a5933d2
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 0 deletions.
36 changes: 36 additions & 0 deletions stdlib/public/core/Substring.swift.gyb
Expand Up @@ -625,3 +625,39 @@ extension Substring {
}
}
//===----------------------------------------------------------------------===//

// popFirst() is only present when a collection is its own subsequence. This was
// dropped in Swift 4.
extension String {
@available(swift, obsoleted: 4, message:
"Please use 'first', 'dropFirst()', or 'Substring.popFirst()'.")
public mutating func popFirst() -> String.Element? {
guard !isEmpty else { return nil }
let element = first!
let nextIdx = self.index(after: self.startIndex)
self = String(self[nextIdx...])
return element
}
}
extension String.CharacterView {
@available(swift, obsoleted: 4, message:
"Please use 'first', 'dropFirst()', or 'Substring.CharacterView.popFirst()'.")
public mutating func popFirst() -> String.CharacterView.Element? {
guard !isEmpty else { return nil }
let element = first!
let nextIdx = self.index(after: self.startIndex)
self = String(self[nextIdx...]).characters
return element
}
}
extension String.UnicodeScalarView {
@available(swift, obsoleted: 4, message:
"Please use 'first', 'dropFirst()', or 'Substring.UnicodeScalarView.popFirst()'.")
public mutating func popFirst() -> String.UnicodeScalarView.Element? {
guard !isEmpty else { return nil }
let element = first!
let nextIdx = self.index(after: self.startIndex)
self = String(self[nextIdx...]).unicodeScalars
return element
}
}
15 changes: 15 additions & 0 deletions test/stdlib/StringCompatibility.swift
Expand Up @@ -356,5 +356,20 @@ Tests.test("LosslessStringConvertible/force unwrap/\(swift)") {
}
#endif

#if !swift(>=4)
Tests.test("popFirst") {
var str = "abcdef"
expectEqual("a", str.popFirst()!)
expectEqual("bcdef", str)
expectEqual("b", str.characters.popFirst()!)
expectEqual("cdef", str)
expectEqual("c", str.unicodeScalars.popFirst()!)
expectEqual("def", str)
expectEqual("d", str.popFirst()!)
expectEqual("e", str.popFirst()!)
expectEqual("f", str.popFirst()!)
expectEqual(nil, str.popFirst())
}
#endif

runAllTests()
14 changes: 14 additions & 0 deletions test/stdlib/StringCompatibilityDiagnostics.swift
@@ -0,0 +1,14 @@
// RUN: %swift -typecheck -swift-version 4 %s -verify

func testPopFirst() {
var str = "abc"
_ = str.popFirst() // expected-error{{'popFirst()' is unavailable: Please use 'first', 'dropFirst()', or 'Substring.popFirst()'}}
_ = str.characters.popFirst() // expected-error{{'popFirst()' is unavailable: Please use 'first', 'dropFirst()', or 'Substring.CharacterView.popFirst()'}}
_ = str.unicodeScalars.popFirst() // expected-error{{'popFirst()' is unavailable: Please use 'first', 'dropFirst()', or 'Substring.UnicodeScalarView.popFirst()'}}

var substr = str[...]
_ = substr.popFirst() // ok
_ = substr.characters.popFirst() // ok
_ = substr.unicodeScalars.popFirst() // ok
}

0 comments on commit a5933d2

Please sign in to comment.