From 96cc4b85489efb7072b571cdb85b4ee43668bc70 Mon Sep 17 00:00:00 2001 From: Arsen Gasparyan Date: Sat, 25 Jun 2016 23:59:47 +0300 Subject: [PATCH 1/3] Rename string reflection init --- .../unit-tests/ObjectiveCBridging.swift | 2 +- .../StdlibUnittest/StdlibCoreExtras.swift | 2 +- .../StdlibUnittest/StringConvertible.swift.gyb | 2 +- stdlib/public/core/Bool.swift | 12 ++++++++++++ stdlib/public/core/Character.swift | 8 ++++++++ .../core/ImplicitlyUnwrappedOptional.swift | 2 +- stdlib/public/core/Mirror.swift | 6 +++--- stdlib/public/core/OutputStream.swift | 4 ++++ stdlib/public/core/StaticString.swift | 2 +- stdlib/public/core/String.swift | 17 +++++++++++++++++ .../public/core/StringInterpolation.swift.gyb | 2 +- stdlib/public/core/StringUTF16.swift | 2 +- stdlib/public/core/StringUTF8.swift | 2 +- stdlib/public/core/UnicodeScalar.swift | 13 ++++++++++++- .../public/core/UnsafeBufferPointer.swift.gyb | 2 +- 15 files changed, 65 insertions(+), 13 deletions(-) diff --git a/benchmark/single-source/unit-tests/ObjectiveCBridging.swift b/benchmark/single-source/unit-tests/ObjectiveCBridging.swift index 68409e06d6ea1..b103717d4fbc8 100644 --- a/benchmark/single-source/unit-tests/ObjectiveCBridging.swift +++ b/benchmark/single-source/unit-tests/ObjectiveCBridging.swift @@ -73,7 +73,7 @@ public func run_ObjectiveCBridgeFromNSStringForced(_ N: Int) { @inline(never) func testObjectiveCBridgeToNSString() { - let nativeString = String("Native") + let nativeString = "Native" var s: NSString? for _ in 0 ..< 10_000 { diff --git a/stdlib/private/StdlibUnittest/StdlibCoreExtras.swift b/stdlib/private/StdlibUnittest/StdlibCoreExtras.swift index e9f872ba780a2..96bc10c974237 100644 --- a/stdlib/private/StdlibUnittest/StdlibCoreExtras.swift +++ b/stdlib/private/StdlibUnittest/StdlibCoreExtras.swift @@ -127,7 +127,7 @@ public func == (lhs: TypeIdentifier, rhs: TypeIdentifier) -> Bool { extension TypeIdentifier : CustomStringConvertible, CustomDebugStringConvertible { public var description: String { - return String(value) + return String(describing: value) } public var debugDescription: String { return "TypeIdentifier(\(description))" diff --git a/stdlib/private/StdlibUnittest/StringConvertible.swift.gyb b/stdlib/private/StdlibUnittest/StringConvertible.swift.gyb index 512162656d50a..2494b1d0fe40f 100644 --- a/stdlib/private/StdlibUnittest/StringConvertible.swift.gyb +++ b/stdlib/private/StdlibUnittest/StringConvertible.swift.gyb @@ -112,7 +112,7 @@ extension CustomPrintableValue : CustomDebugStringConvertible { public func expectPrinted( expectedOneOf patterns: [String], _ object: T, ${TRACE} ) { - let actual = String(object) + let actual = String(describing: object) if !patterns.contains(actual) { expectationFailure( "expected: any of \(String(reflecting: patterns))\n" diff --git a/stdlib/public/core/Bool.swift b/stdlib/public/core/Bool.swift index 6e56c66fcd5fa..ec7cf22353596 100644 --- a/stdlib/public/core/Bool.swift +++ b/stdlib/public/core/Bool.swift @@ -146,6 +146,18 @@ extension Bool : Equatable, Hashable { } } +extension Bool : LosslessStringConvertible { + public init?(_ description: String) { + if description == "true" { + self = true + } else if description == "false" { + self = false + } else { + return nil + } + } +} + //===----------------------------------------------------------------------===// // Operators //===----------------------------------------------------------------------===// diff --git a/stdlib/public/core/Character.swift b/stdlib/public/core/Character.swift index d9b3f2099b3f2..577ea7df42218 100644 --- a/stdlib/public/core/Character.swift +++ b/stdlib/public/core/Character.swift @@ -353,6 +353,14 @@ public struct Character : internal var _representation: Representation } +extension Character : CustomStringConvertible { + public var description: String { + return String(self) + } +} + +extension Character : LosslessStringConvertible {} + extension Character : CustomDebugStringConvertible { /// A textual representation of the character, suitable for debugging. public var debugDescription: String { diff --git a/stdlib/public/core/ImplicitlyUnwrappedOptional.swift b/stdlib/public/core/ImplicitlyUnwrappedOptional.swift index 8fb76e12e2988..ff4b40e060523 100644 --- a/stdlib/public/core/ImplicitlyUnwrappedOptional.swift +++ b/stdlib/public/core/ImplicitlyUnwrappedOptional.swift @@ -45,7 +45,7 @@ extension ImplicitlyUnwrappedOptional : CustomStringConvertible { public var description: String { switch self { case .some(let value): - return String(value) + return String(describing: value) case .none: return "nil" } diff --git a/stdlib/public/core/Mirror.swift b/stdlib/public/core/Mirror.swift index 21499d4a62c48..be73882b3628d 100644 --- a/stdlib/public/core/Mirror.swift +++ b/stdlib/public/core/Mirror.swift @@ -855,7 +855,7 @@ extension String { /// } /// /// let p = Point(x: 21, y: 30) - /// print(String(p)) + /// print(String(describing: p)) /// // Prints "Point(x: 21, y: 30)" /// /// After adding `CustomStringConvertible` conformance by implementing the @@ -867,11 +867,11 @@ extension String { /// } /// } /// - /// print(String(p)) + /// print(String(describing: p)) /// // Prints "(21, 30)" /// /// - SeeAlso: `String.init(reflecting: Subject)` - public init(_ instance: Subject) { + public init(describing instance: Subject) { self.init() _print_unlocked(instance, &self) } diff --git a/stdlib/public/core/OutputStream.swift b/stdlib/public/core/OutputStream.swift index 0ff684ad22b5e..77edac6523669 100644 --- a/stdlib/public/core/OutputStream.swift +++ b/stdlib/public/core/OutputStream.swift @@ -164,6 +164,10 @@ public protocol CustomStringConvertible { var description: String { get } } +public protocol LosslessStringConvertible : CustomStringConvertible { + init?(_ description: String) +} + /// A type with a customized textual representation suitable for debugging /// purposes. /// diff --git a/stdlib/public/core/StaticString.swift b/stdlib/public/core/StaticString.swift index df124432fb058..0e5d5664e96d4 100644 --- a/stdlib/public/core/StaticString.swift +++ b/stdlib/public/core/StaticString.swift @@ -255,7 +255,7 @@ public struct StaticString extension StaticString { public var customMirror: Mirror { - return Mirror(reflecting: String(self)) + return Mirror(reflecting: String(describing: self)) } } diff --git a/stdlib/public/core/String.swift b/stdlib/public/core/String.swift index 614b58c559e6f..4b772e5adf08c 100644 --- a/stdlib/public/core/String.swift +++ b/stdlib/public/core/String.swift @@ -974,6 +974,23 @@ extension String { return _nativeUnicodeUppercaseString(self) #endif } + + public // @testable + init(_ v: T) { + self = v.description + } +} + +extension String : CustomStringConvertible { + public var description: String { + return self + } +} + +extension String : LosslessStringConvertible { + public init?(_ description: String) { + self = description + } } extension String { diff --git a/stdlib/public/core/StringInterpolation.swift.gyb b/stdlib/public/core/StringInterpolation.swift.gyb index bec13b14e3e76..384785dec715c 100644 --- a/stdlib/public/core/StringInterpolation.swift.gyb +++ b/stdlib/public/core/StringInterpolation.swift.gyb @@ -65,7 +65,7 @@ extension String : ExpressibleByStringInterpolation { /// /// - SeeAlso: `ExpressibleByStringInterpolation` public init(stringInterpolationSegment expr: T) { - self = String(expr) + self = String(describing: expr) } % for Type in StreamableTypes: diff --git a/stdlib/public/core/StringUTF16.swift b/stdlib/public/core/StringUTF16.swift index ff043d00c2cc1..28ad2ae8c9b8a 100644 --- a/stdlib/public/core/StringUTF16.swift +++ b/stdlib/public/core/StringUTF16.swift @@ -314,7 +314,7 @@ extension String { return UTF16View(_core) } set { - self = String(newValue) + self = String(describing: newValue) } } diff --git a/stdlib/public/core/StringUTF8.swift b/stdlib/public/core/StringUTF8.swift index d43b15b502aff..10828d1cc1afe 100644 --- a/stdlib/public/core/StringUTF8.swift +++ b/stdlib/public/core/StringUTF8.swift @@ -375,7 +375,7 @@ extension String { return UTF8View(self._core) } set { - self = String(newValue) + self = String(describing: newValue) } } diff --git a/stdlib/public/core/UnicodeScalar.swift b/stdlib/public/core/UnicodeScalar.swift index cc5a8d3d6898a..beaf74ff91087 100644 --- a/stdlib/public/core/UnicodeScalar.swift +++ b/stdlib/public/core/UnicodeScalar.swift @@ -249,7 +249,7 @@ public struct UnicodeScalar : extension UnicodeScalar : CustomStringConvertible, CustomDebugStringConvertible { /// An escaped textual representation of the Unicode scalar. public var description: String { - return "\"\(escaped(asASCII: false))\"" + return String(value) } /// An escaped textual representation of the Unicode scalar, suitable for /// debugging. @@ -258,6 +258,17 @@ extension UnicodeScalar : CustomStringConvertible, CustomDebugStringConvertible } } +extension UnicodeScalar : LosslessStringConvertible { + public init?(_ description: String) { + if let v = UInt32(description) where (v < 0xD800 || v > 0xDFFF) + && v <= 0x10FFFF { + self = UnicodeScalar(v) + } + + return nil + } +} + extension UnicodeScalar : Hashable { /// The Unicode scalar's hash value. /// diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index eb1b29473c748..16145639ec3e9 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -219,7 +219,7 @@ extension Unsafe${Mutable}BufferPointer : CustomDebugStringConvertible { /// A textual representation of `self`, suitable for debugging. public var debugDescription: String { return "Unsafe${Mutable}BufferPointer" - + "(start: \(_position.map(String.init(_:)) ?? "nil"), count: \(count))" + + "(start: \(_position.map(String.init(describing:)) ?? "nil"), count: \(count))" } } %end From 3071b0c9dd24e418cbea591854b9a69f76aa8966 Mon Sep 17 00:00:00 2001 From: Max Moiseev Date: Fri, 15 Jul 2016 17:59:48 -0700 Subject: [PATCH 2/3] Addressing PR comments and updating some tests --- .../CheckCollectionType.swift.gyb | 6 +++--- .../CheckMutableCollectionType.swift.gyb | 6 +++--- .../CheckRangeReplaceableCollectionType.swift | 6 +++--- .../CheckRangeReplaceableSliceType.swift | 6 +++--- .../StdlibCollectionUnittest/CheckSequenceType.swift | 2 +- stdlib/public/core/Integers.swift.gyb | 2 +- stdlib/public/core/OutputStream.swift | 10 ++++++++++ stdlib/public/core/StaticString.swift | 2 +- stdlib/public/core/String.swift | 7 ++++--- stdlib/public/core/StringLegacy.swift | 6 ------ stdlib/public/core/UnicodeScalar.swift | 4 ++-- 11 files changed, 31 insertions(+), 26 deletions(-) diff --git a/stdlib/private/StdlibCollectionUnittest/CheckCollectionType.swift.gyb b/stdlib/private/StdlibCollectionUnittest/CheckCollectionType.swift.gyb index a81fa90d9cd1f..9995fed02a6fa 100644 --- a/stdlib/private/StdlibCollectionUnittest/CheckCollectionType.swift.gyb +++ b/stdlib/private/StdlibCollectionUnittest/CheckCollectionType.swift.gyb @@ -561,7 +561,7 @@ extension TestSuite { return makeCollectionOfEquatable(elements.map(wrapValueIntoEquatable)) } - testNamePrefix += String(C.Type.self) + testNamePrefix += String(describing: C.Type.self) //===------------------------------------------------------------------===// // generate() @@ -1209,7 +1209,7 @@ extension TestSuite { return makeCollection(elements.map(wrapValue)) } - testNamePrefix += String(C.Type.self) + testNamePrefix += String(describing: C.Type.self) // FIXME: swift-3-indexing-model - add tests for the follow? // index(before: of i: Index) -> Index @@ -1522,7 +1522,7 @@ extension TestSuite { addBidirectionalCollectionTests(${forwardTestArgs}) - testNamePrefix += String(C.Type.self) + testNamePrefix += String(describing: C.Type.self) func makeWrappedCollection(_ elements: [OpaqueValue]) -> C { return makeCollection(elements.map(wrapValue)) diff --git a/stdlib/private/StdlibCollectionUnittest/CheckMutableCollectionType.swift.gyb b/stdlib/private/StdlibCollectionUnittest/CheckMutableCollectionType.swift.gyb index 27689c21db50f..c80bc0273ca33 100644 --- a/stdlib/private/StdlibCollectionUnittest/CheckMutableCollectionType.swift.gyb +++ b/stdlib/private/StdlibCollectionUnittest/CheckMutableCollectionType.swift.gyb @@ -136,7 +136,7 @@ extension TestSuite { return makeCollectionOfComparable(elements.map(wrapValueIntoComparable)) } - testNamePrefix += String(C.Type.self) + testNamePrefix += String(describing: C.Type.self) //===----------------------------------------------------------------------===// // subscript(_: Index) @@ -657,7 +657,7 @@ self.test("\(testNamePrefix).sorted/${'Predicate' if predicate else 'WhereElemen return makeCollection(elements.map(wrapValue)) } - testNamePrefix += String(C.Type.self) + testNamePrefix += String(describing: C.Type.self) //===----------------------------------------------------------------------===// // subscript(_: Index) @@ -783,7 +783,7 @@ self.test("\(testNamePrefix).reverse()") { return makeCollectionOfComparable(elements.map(wrapValueIntoComparable)) } - testNamePrefix += String(C.Type.self) + testNamePrefix += String(describing: C.Type.self) //===----------------------------------------------------------------------===// // sort() diff --git a/stdlib/private/StdlibCollectionUnittest/CheckRangeReplaceableCollectionType.swift b/stdlib/private/StdlibCollectionUnittest/CheckRangeReplaceableCollectionType.swift index 9c7f02de68f5c..cadc9be4817cb 100644 --- a/stdlib/private/StdlibCollectionUnittest/CheckRangeReplaceableCollectionType.swift +++ b/stdlib/private/StdlibCollectionUnittest/CheckRangeReplaceableCollectionType.swift @@ -497,7 +497,7 @@ extension TestSuite { return makeCollection(elements.map(wrapValue)) } - testNamePrefix += String(C.Type.self) + testNamePrefix += String(describing: C.Type.self) //===----------------------------------------------------------------------===// // init() @@ -1218,7 +1218,7 @@ self.test("\(testNamePrefix).OperatorPlus") { return makeCollection(elements.map(wrapValue)) } - testNamePrefix += String(C.Type.self) + testNamePrefix += String(describing: C.Type.self) //===----------------------------------------------------------------------===// // removeLast() @@ -1340,7 +1340,7 @@ self.test("\(testNamePrefix).removeLast(n: Int)/whereIndexIsBidirectional/remove resiliencyChecks: resiliencyChecks, outOfBoundsIndexOffset: outOfBoundsIndexOffset) - testNamePrefix += String(C.Type.self) + testNamePrefix += String(describing: C.Type.self) // No extra checks for collections with random access traversal so far. } // addRangeReplaceableRandomAccessCollectionTests diff --git a/stdlib/private/StdlibCollectionUnittest/CheckRangeReplaceableSliceType.swift b/stdlib/private/StdlibCollectionUnittest/CheckRangeReplaceableSliceType.swift index a7712605f9d10..c4b682a1b5a04 100644 --- a/stdlib/private/StdlibCollectionUnittest/CheckRangeReplaceableSliceType.swift +++ b/stdlib/private/StdlibCollectionUnittest/CheckRangeReplaceableSliceType.swift @@ -65,7 +65,7 @@ extension TestSuite { return makeCollection(elements.map(wrapValue)) } - testNamePrefix += String(C.Type.self) + testNamePrefix += String(describing: C.Type.self) //===------------------------------------------------------------------===// // removeFirst() @@ -210,7 +210,7 @@ extension TestSuite { return makeCollection(elements.map(wrapValue)) } - testNamePrefix += String(C.Type.self) + testNamePrefix += String(describing: C.Type.self) //===------------------------------------------------------------------===// // removeLast() @@ -351,7 +351,7 @@ extension TestSuite { resiliencyChecks: resiliencyChecks, outOfBoundsIndexOffset: outOfBoundsIndexOffset) - testNamePrefix += String(C.Type.self) + testNamePrefix += String(describing: C.Type.self) // No tests yet. } // addRangeReplaceableRandomAccessSliceTests diff --git a/stdlib/private/StdlibCollectionUnittest/CheckSequenceType.swift b/stdlib/private/StdlibCollectionUnittest/CheckSequenceType.swift index e699a9b0ffd09..b8030968d08af 100644 --- a/stdlib/private/StdlibCollectionUnittest/CheckSequenceType.swift +++ b/stdlib/private/StdlibCollectionUnittest/CheckSequenceType.swift @@ -1484,7 +1484,7 @@ extension TestSuite { return makeSequenceOfEquatable(elements.map(wrapValueIntoEquatable)) } - testNamePrefix += String(S.Type.self) + testNamePrefix += String(describing: S.Type.self) let isMultiPass = makeSequence([]) ._preprocessingPass { true } ?? false diff --git a/stdlib/public/core/Integers.swift.gyb b/stdlib/public/core/Integers.swift.gyb index 4f002d7e737b9..be3cf35cb48c7 100644 --- a/stdlib/public/core/Integers.swift.gyb +++ b/stdlib/public/core/Integers.swift.gyb @@ -688,7 +688,7 @@ public protocol SignedInteger_ : BinaryInteger, SignedArithmetic { extension SignedInteger_ { public var description: String { - let base = String(magnitude) + let base = String(describing: magnitude) return self < 0 ? "-" + base : base } diff --git a/stdlib/public/core/OutputStream.swift b/stdlib/public/core/OutputStream.swift index 77edac6523669..567780a55e009 100644 --- a/stdlib/public/core/OutputStream.swift +++ b/stdlib/public/core/OutputStream.swift @@ -164,7 +164,17 @@ public protocol CustomStringConvertible { var description: String { get } } +/// A type that can be represented as a string in a lossless, unambiguous way. +/// +/// For example, the integer value 1050 can be represented in its entirety as +/// the string "1050". +/// +/// The description property of a conforming type must be a value-preserving +/// representation of the original value. As such, it should be possible to +/// attempt to re-create an instance from its string representation. public protocol LosslessStringConvertible : CustomStringConvertible { + /// Instantiates an instance of the conforming type from a string + /// representation. init?(_ description: String) } diff --git a/stdlib/public/core/StaticString.swift b/stdlib/public/core/StaticString.swift index 0e5d5664e96d4..2aa2ff20f7aea 100644 --- a/stdlib/public/core/StaticString.swift +++ b/stdlib/public/core/StaticString.swift @@ -255,7 +255,7 @@ public struct StaticString extension StaticString { public var customMirror: Mirror { - return Mirror(reflecting: String(describing: self)) + return Mirror(reflecting: description) } } diff --git a/stdlib/public/core/String.swift b/stdlib/public/core/String.swift index 4b772e5adf08c..a02f30db56940 100644 --- a/stdlib/public/core/String.swift +++ b/stdlib/public/core/String.swift @@ -975,9 +975,10 @@ extension String { #endif } - public // @testable - init(_ v: T) { - self = v.description + /// Creates an instance from the description of a given + /// LosslessStringConvertible instance. + public init(_ value: T) { + self = value.description } } diff --git a/stdlib/public/core/StringLegacy.swift b/stdlib/public/core/StringLegacy.swift index 4375768b305ac..04f1224248406 100644 --- a/stdlib/public/core/StringLegacy.swift +++ b/stdlib/public/core/StringLegacy.swift @@ -63,12 +63,6 @@ extension String { } } -extension String { - public init(_ _c: UnicodeScalar) { - self = String(repeating: _c, count: 1) - } -} - #if _runtime(_ObjC) /// Determines if `theString` starts with `prefix` comparing the strings under /// canonical equivalence. diff --git a/stdlib/public/core/UnicodeScalar.swift b/stdlib/public/core/UnicodeScalar.swift index beaf74ff91087..e30278e27189c 100644 --- a/stdlib/public/core/UnicodeScalar.swift +++ b/stdlib/public/core/UnicodeScalar.swift @@ -263,9 +263,9 @@ extension UnicodeScalar : LosslessStringConvertible { if let v = UInt32(description) where (v < 0xD800 || v > 0xDFFF) && v <= 0x10FFFF { self = UnicodeScalar(v) + } else { + return nil } - - return nil } } From 002fa7590c84872f0ee47ba9ec96f3d3ef2a1022 Mon Sep 17 00:00:00 2001 From: Max Moiseev Date: Fri, 15 Jul 2016 21:05:05 -0700 Subject: [PATCH 3/3] adding a test for unicode scalar lossless conversion --- test/1_stdlib/Unicode.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/1_stdlib/Unicode.swift b/test/1_stdlib/Unicode.swift index 5a442de27c4fb..31e3221a04e1d 100644 --- a/test/1_stdlib/Unicode.swift +++ b/test/1_stdlib/Unicode.swift @@ -57,4 +57,12 @@ UnicodeAPIs.test("UnicodeDecodingResult/Equatable") { checkEquatable(instances, oracle: ==) } +let UnicodeScalarTests = TestSuite("UnicodeScalar") + +UnicodeScalarTests.test("lossless conversion") { + let scalar: UnicodeScalar = "a" + let actual = UnicodeScalar(String(scalar)) + expectOptionalEqual(scalar, actual) +} + runAllTests()