From abae2f65476fb9e0dfa670f808ba216f29fe03a9 Mon Sep 17 00:00:00 2001 From: Rick van Voorden Date: Thu, 16 Oct 2025 14:42:38 -0700 Subject: [PATCH 01/16] [stdlib] string identical Co-Authored-By: Karoy Lorentey --- benchmark/single-source/StringTests.swift | 19 ++ benchmark/single-source/SubstringTest.swift | 56 ++++-- stdlib/public/core/String.swift | 40 +++- stdlib/public/core/Substring.swift | 41 ++++ test/abi/Inputs/macOS/arm64/stdlib/baseline | 2 + .../macOS/arm64/stdlib/baseline-asserts | 2 + test/abi/Inputs/macOS/x86_64/stdlib/baseline | 2 + .../macOS/x86_64/stdlib/baseline-asserts | 2 + test/stdlib/StringAPI.swift | 58 ++++++ test/stdlib/subString.swift | 188 ++++++++++++++++++ 10 files changed, 390 insertions(+), 20 deletions(-) diff --git a/benchmark/single-source/StringTests.swift b/benchmark/single-source/StringTests.swift index bcc43a2633777..579ac6f3d3ce8 100644 --- a/benchmark/single-source/StringTests.swift +++ b/benchmark/single-source/StringTests.swift @@ -49,6 +49,14 @@ public var benchmarks: [BenchmarkInfo] { runFunction: run_iterateWords, tags: [.validation, .String])) } + + if #available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, visionOS 9999, *) { + result.append( + BenchmarkInfo( + name: "StringIdentical", + runFunction: run_StringIdentical, + tags: [.validation, .api, .String])) + } return result } @@ -1676,3 +1684,14 @@ public func run_iterateWords(_ n: Int) { blackHole(swiftOrgHTML._words) } } + +@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, visionOS 9999, *) +public func run_StringIdentical(_ n: Int) { + let str1 = "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. " + let str2 = str1 + for _ in 0 ..< n { + for _ in 0 ..< 100_000 { + check(str1.isTriviallyIdentical(to: str2)) + } + } +} diff --git a/benchmark/single-source/SubstringTest.swift b/benchmark/single-source/SubstringTest.swift index 71ef0c774f26f..a7652ff1064bc 100644 --- a/benchmark/single-source/SubstringTest.swift +++ b/benchmark/single-source/SubstringTest.swift @@ -12,25 +12,34 @@ import TestsUtils -public let benchmarks = [ - BenchmarkInfo(name: "EqualStringSubstring", runFunction: run_EqualStringSubstring, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "EqualSubstringString", runFunction: run_EqualSubstringString, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "EqualSubstringSubstring", runFunction: run_EqualSubstringSubstring, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "EqualSubstringSubstringGenericEquatable", runFunction: run_EqualSubstringSubstringGenericEquatable, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "SubstringRemoveFirst1", runFunction: run_SubstringRemoveFirst1, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "SubstringRemoveLast1", runFunction: run_SubstringRemoveLast1, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "LessSubstringSubstring", runFunction: run_LessSubstringSubstring, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "LessSubstringSubstringGenericComparable", runFunction: run_LessSubstringSubstringGenericComparable, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "StringFromLongWholeSubstring", runFunction: run_StringFromLongWholeSubstring, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "StringFromLongWholeSubstringGeneric", runFunction: run_StringFromLongWholeSubstringGeneric, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "SubstringComparable", runFunction: run_SubstringComparable, tags: [.validation, .api, .String], - setUpFunction: { blackHole(_comparison) }), - BenchmarkInfo(name: "SubstringEqualString", runFunction: run_SubstringEqualString, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "SubstringEquatable", runFunction: run_SubstringEquatable, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "SubstringFromLongString2", runFunction: run_SubstringFromLongString, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "SubstringFromLongStringGeneric2", runFunction: run_SubstringFromLongStringGeneric, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "SubstringTrimmingASCIIWhitespace", runFunction: run_SubstringTrimmingASCIIWhitespace, tags: [.validation, .api, .String]), -] +public var benchmarks: [BenchmarkInfo] { + var result = [ + BenchmarkInfo(name: "EqualStringSubstring", runFunction: run_EqualStringSubstring, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "EqualSubstringString", runFunction: run_EqualSubstringString, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "EqualSubstringSubstring", runFunction: run_EqualSubstringSubstring, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "EqualSubstringSubstringGenericEquatable", runFunction: run_EqualSubstringSubstringGenericEquatable, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "SubstringRemoveFirst1", runFunction: run_SubstringRemoveFirst1, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "SubstringRemoveLast1", runFunction: run_SubstringRemoveLast1, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "LessSubstringSubstring", runFunction: run_LessSubstringSubstring, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "LessSubstringSubstringGenericComparable", runFunction: run_LessSubstringSubstringGenericComparable, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "StringFromLongWholeSubstring", runFunction: run_StringFromLongWholeSubstring, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "StringFromLongWholeSubstringGeneric", runFunction: run_StringFromLongWholeSubstringGeneric, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "SubstringComparable", runFunction: run_SubstringComparable, tags: [.validation, .api, .String], + setUpFunction: { blackHole(_comparison) }), + BenchmarkInfo(name: "SubstringEqualString", runFunction: run_SubstringEqualString, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "SubstringEquatable", runFunction: run_SubstringEquatable, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "SubstringFromLongString2", runFunction: run_SubstringFromLongString, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "SubstringFromLongStringGeneric2", runFunction: run_SubstringFromLongStringGeneric, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "SubstringTrimmingASCIIWhitespace", runFunction: run_SubstringTrimmingASCIIWhitespace, tags: [.validation, .api, .String]), + ] + + if #available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, visionOS 9999, *) { + result.append( + BenchmarkInfo(name: "SubstringIdentical", runFunction: run_SubstringIdentical, tags: [.validation, .String]), + ) + } + return result +} // A string that doesn't fit in small string storage and doesn't fit in Latin-1 let longWide = "fὢasὢodὢijὢadὢolὢsjὢalὢsdὢjlὢasὢdfὢijὢliὢsdὢjøὢslὢdiὢalὢiὢ" @@ -332,3 +341,12 @@ public func run _LessSubstringSubstringGenericStringProtocol(_ n: Int) { } } */ + +@inline(never) +@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, visionOS 9999, *) +public func run_SubstringIdentical(_ n: Int) { + let (a, b) = (ss1, ss1) + for _ in 1...n*500 { + blackHole(a.isTriviallyIdentical(to: b)) + } +} diff --git a/stdlib/public/core/String.swift b/stdlib/public/core/String.swift index e6715e91cc6ed..12d0413f36f66 100644 --- a/stdlib/public/core/String.swift +++ b/stdlib/public/core/String.swift @@ -1112,4 +1112,42 @@ extension String { } } - +extension String { + /// Returns a boolean value indicating whether this string is identical to + /// `other`. + /// + /// Two string values are identical if there is no way to distinguish between + /// them. + /// + /// For any values `a`, `b`, and `c`: + /// + /// - `a.isTriviallyIdentical(to: a)` is always `true`. (Reflexivity) + /// - `a.isTriviallyIdentical(to: b)` implies `b.isTriviallyIdentical(to: a)`. + /// (Symmetry) + /// - If `a.isTriviallyIdentical(to: b)` and `b.isTriviallyIdentical(to: c)` + /// are both `true`, then `a.isTriviallyIdentical(to: c)` is also `true`. + /// (Transitivity) + /// - `a.isTriviallyIdentical(b)` implies `a == b` + /// - `a == b` does not imply `a.isTriviallyIdentical(b)` + /// + /// Values produced by copying the same value, with no intervening mutations, + /// will compare identical: + /// + /// ```swift + /// let d = c + /// print(c.isTriviallyIdentical(to: d)) + /// // Prints true + /// ``` + /// + /// Comparing strings this way includes comparing (normally) hidden + /// implementation details such as the memory location of any underlying + /// string storage object. Therefore, identical strings are guaranteed to + /// compare equal with `==`, but not all equal strings are considered + /// identical. + /// + /// - Complexity: O(1) + @available(SwiftStdlib 9999, *) + public func isTriviallyIdentical(to other: Self) -> Bool { + self._guts.rawBits == other._guts.rawBits + } +} diff --git a/stdlib/public/core/Substring.swift b/stdlib/public/core/Substring.swift index e4e91b6a02a4c..ef70c842b6720 100644 --- a/stdlib/public/core/Substring.swift +++ b/stdlib/public/core/Substring.swift @@ -1385,3 +1385,44 @@ extension Substring { return Substring(_unchecked: Slice(base: base, bounds: r)) } } + +extension Substring { + /// Returns a boolean value indicating whether this substring is identical to + /// `other`. + /// + /// Two substring values are identical if there is no way to distinguish + /// between them. + /// + /// For any values `a`, `b`, and `c`: + /// + /// - `a.isTriviallyIdentical(to: a)` is always `true`. (Reflexivity) + /// - `a.isTriviallyIdentical(to: b)` implies `b.isTriviallyIdentical(to: a)`. + /// (Symmetry) + /// - If `a.isTriviallyIdentical(to: b)` and `b.isTriviallyIdentical(to: c)` + /// are both `true`, then `a.isTriviallyIdentical(to: c)` is also `true`. + /// (Transitivity) + /// - `a.isTriviallyIdentical(b)` implies `a == b` + /// - `a == b` does not imply `a.isTriviallyIdentical(b)` + /// + /// Values produced by copying the same value, with no intervening mutations, + /// will compare identical: + /// + /// ```swift + /// let d = c + /// print(c.isTriviallyIdentical(to: d)) + /// // Prints true + /// ``` + /// + /// Comparing substrings this way includes comparing (normally) hidden + /// implementation details such as the memory location of any underlying + /// substring storage object. Therefore, identical substrings are guaranteed + /// to compare equal with `==`, but not all equal substrings are considered + /// identical. + /// + /// - Complexity: O(1) + @available(SwiftStdlib 9999, *) + public func isTriviallyIdentical(to other: Self) -> Bool { + self._wholeGuts.rawBits == other._wholeGuts.rawBits && + self._offsetRange == other._offsetRange + } +} diff --git a/test/abi/Inputs/macOS/arm64/stdlib/baseline b/test/abi/Inputs/macOS/arm64/stdlib/baseline index e2cefe00d8792..e774cbcd1cb14 100644 --- a/test/abi/Inputs/macOS/arm64/stdlib/baseline +++ b/test/abi/Inputs/macOS/arm64/stdlib/baseline @@ -1285,6 +1285,7 @@ _$sSS19_uncheckedFromUTF16ySSSRys6UInt16VGFZ _$sSS19stringInterpolationSSs013DefaultStringB0V_tcfC _$sSS1loiySbSS_SStFZ _$sSS1poiyS2S_SStFZ +_$sSS20isTriviallyIdentical2toSbSS_tF _$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC _$sSS21withMutableCharactersyxxSSzXElF _$sSS23_bridgeToObjectiveCImplyXlyF @@ -3614,6 +3615,7 @@ _$sSs17UnicodeScalarViewVyABSnySS5IndexVGcipMV _$sSs17UnicodeScalarViewVys0A0O0B0VSS5IndexVcig _$sSs17UnicodeScalarViewVys0A0O0B0VSS5IndexVcipMV _$sSs19stringInterpolationSss013DefaultStringB0V_tcfC +_$sSs20isTriviallyIdentical2toSbSs_tF _$sSs20unicodeScalarLiteralSsSS_tcfC _$sSs21withMutableCharactersyxxSszXElF _$sSs25customPlaygroundQuickLooks01_bcD0Ovg diff --git a/test/abi/Inputs/macOS/arm64/stdlib/baseline-asserts b/test/abi/Inputs/macOS/arm64/stdlib/baseline-asserts index b4c2cd5b74e43..737987666e9c1 100644 --- a/test/abi/Inputs/macOS/arm64/stdlib/baseline-asserts +++ b/test/abi/Inputs/macOS/arm64/stdlib/baseline-asserts @@ -1285,6 +1285,7 @@ _$sSS19_uncheckedFromUTF16ySSSRys6UInt16VGFZ _$sSS19stringInterpolationSSs013DefaultStringB0V_tcfC _$sSS1loiySbSS_SStFZ _$sSS1poiyS2S_SStFZ +_$sSS20isTriviallyIdentical2toSbSS_tF _$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC _$sSS21withMutableCharactersyxxSSzXElF _$sSS23_bridgeToObjectiveCImplyXlyF @@ -3614,6 +3615,7 @@ _$sSs17UnicodeScalarViewVyABSnySS5IndexVGcipMV _$sSs17UnicodeScalarViewVys0A0O0B0VSS5IndexVcig _$sSs17UnicodeScalarViewVys0A0O0B0VSS5IndexVcipMV _$sSs19stringInterpolationSss013DefaultStringB0V_tcfC +_$sSs20isTriviallyIdentical2toSbSs_tF _$sSs20unicodeScalarLiteralSsSS_tcfC _$sSs21withMutableCharactersyxxSszXElF _$sSs25customPlaygroundQuickLooks01_bcD0Ovg diff --git a/test/abi/Inputs/macOS/x86_64/stdlib/baseline b/test/abi/Inputs/macOS/x86_64/stdlib/baseline index 48dc1820c1982..f00d1e3a78b21 100644 --- a/test/abi/Inputs/macOS/x86_64/stdlib/baseline +++ b/test/abi/Inputs/macOS/x86_64/stdlib/baseline @@ -1287,6 +1287,7 @@ _$sSS19_uncheckedFromUTF16ySSSRys6UInt16VGFZ _$sSS19stringInterpolationSSs013DefaultStringB0V_tcfC _$sSS1loiySbSS_SStFZ _$sSS1poiyS2S_SStFZ +_$sSS20isTriviallyIdentical2toSbSS_tF _$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC _$sSS21withMutableCharactersyxxSSzXElF _$sSS23_bridgeToObjectiveCImplyXlyF @@ -3616,6 +3617,7 @@ _$sSs17UnicodeScalarViewVyABSnySS5IndexVGcipMV _$sSs17UnicodeScalarViewVys0A0O0B0VSS5IndexVcig _$sSs17UnicodeScalarViewVys0A0O0B0VSS5IndexVcipMV _$sSs19stringInterpolationSss013DefaultStringB0V_tcfC +_$sSs20isTriviallyIdentical2toSbSs_tF _$sSs20unicodeScalarLiteralSsSS_tcfC _$sSs21withMutableCharactersyxxSszXElF _$sSs25customPlaygroundQuickLooks01_bcD0Ovg diff --git a/test/abi/Inputs/macOS/x86_64/stdlib/baseline-asserts b/test/abi/Inputs/macOS/x86_64/stdlib/baseline-asserts index e9d6bfe251c0e..7412236cb6ceb 100644 --- a/test/abi/Inputs/macOS/x86_64/stdlib/baseline-asserts +++ b/test/abi/Inputs/macOS/x86_64/stdlib/baseline-asserts @@ -1287,6 +1287,7 @@ _$sSS19_uncheckedFromUTF16ySSSRys6UInt16VGFZ _$sSS19stringInterpolationSSs013DefaultStringB0V_tcfC _$sSS1loiySbSS_SStFZ _$sSS1poiyS2S_SStFZ +_$sSS20isTriviallyIdentical2toSbSS_tF _$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC _$sSS21withMutableCharactersyxxSSzXElF _$sSS23_bridgeToObjectiveCImplyXlyF @@ -3616,6 +3617,7 @@ _$sSs17UnicodeScalarViewVyABSnySS5IndexVGcipMV _$sSs17UnicodeScalarViewVys0A0O0B0VSS5IndexVcig _$sSs17UnicodeScalarViewVys0A0O0B0VSS5IndexVcipMV _$sSs19stringInterpolationSss013DefaultStringB0V_tcfC +_$sSs20isTriviallyIdentical2toSbSs_tF _$sSs20unicodeScalarLiteralSsSS_tcfC _$sSs21withMutableCharactersyxxSszXElF _$sSs25customPlaygroundQuickLooks01_bcD0Ovg diff --git a/test/stdlib/StringAPI.swift b/test/stdlib/StringAPI.swift index fb33db9b53ee7..91e2fe4ae5995 100644 --- a/test/stdlib/StringAPI.swift +++ b/test/stdlib/StringAPI.swift @@ -533,4 +533,62 @@ StringTests.test("hasPrefix/hasSuffix vs Character boundaries") { expectFalse(s2.hasSuffix("\n")) } +StringTests.test("isTriviallyIdentical(to:) small ascii") +.skip(.custom( + { if #available(SwiftStdlib 9999, *) { false } else { true } }, + reason: "Requires Swift 6.3's standard library" +)) +.code { + guard #available(SwiftStdlib 9999, *) else { return } + + let a = "Hello" + let b = "Hello" + + precondition(a == b) + + expectTrue(a.isTriviallyIdentical(to: a)) + expectTrue(b.isTriviallyIdentical(to: b)) + expectTrue(a.isTriviallyIdentical(to: b)) // Both small ASCII strings + expectTrue(b.isTriviallyIdentical(to: a)) +} + +StringTests.test("isTriviallyIdentical(to:) small unicode") +.skip(.custom( + { if #available(SwiftStdlib 9999, *) { false } else { true } }, + reason: "Requires Swift 6.3's standard library" +)) +.code { + guard #available(SwiftStdlib 9999, *) else { return } + + let a = "Cafe\u{301}" + let b = "Cafe\u{301}" + let c = "Café" + + precondition(a == b) + precondition(b == c) + + expectTrue(a.isTriviallyIdentical(to: b)) + expectTrue(b.isTriviallyIdentical(to: a)) + expectFalse(a.isTriviallyIdentical(to: c)) + expectFalse(b.isTriviallyIdentical(to: c)) +} + +StringTests.test("isTriviallyIdentical(to:) large ascii") +.skip(.custom( + { if #available(SwiftStdlib 9999, *) { false } else { true } }, + reason: "Requires Swift 6.3's standard library" +)) +.code { + guard #available(SwiftStdlib 9999, *) else { return } + + let a = String(repeating: "foo", count: 1000) + let b = String(repeating: "foo", count: 1000) + + precondition(a == b) + + expectFalse(a.isTriviallyIdentical(to: b)) // Two large, distinct native strings + expectTrue(a.isTriviallyIdentical(to: a)) + expectTrue(b.isTriviallyIdentical(to: b)) +} + runAllTests() diff --git a/test/stdlib/subString.swift b/test/stdlib/subString.swift index 2a7b9e58db2d8..10351bfd9ee60 100644 --- a/test/stdlib/subString.swift +++ b/test/stdlib/subString.swift @@ -31,6 +31,41 @@ func checkHasContiguousStorageSubstring(_ x: Substring.UTF8View) { expectTrue(hasStorage) } +fileprivate func slices( + _ s: String, + from: Int, + to: Int +) -> ( + Substring, + Substring, + Substring +) { + let s1 = s[s.index(s.startIndex, offsetBy: from) ..< + s.index(s.startIndex, offsetBy: to)] + let s2 = s1[s1.startIndex.. Bool { + s.allSatisfy { $0.isEmpty == false } +} + +fileprivate func allEqual( + _ s: Substring... +) -> Bool { + for i in 0.. Date: Mon, 8 Dec 2025 13:41:17 -0800 Subject: [PATCH 02/16] [stdlib] Define availability for the 6.4 stdlib and runtime --- include/swift/AST/RuntimeVersions.def | 5 +++++ stdlib/public/core/Availability.swift | 4 +++- utils/availability-macros.def | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/swift/AST/RuntimeVersions.def b/include/swift/AST/RuntimeVersions.def index 39d0a279c6f28..4ab18020ff311 100644 --- a/include/swift/AST/RuntimeVersions.def +++ b/include/swift/AST/RuntimeVersions.def @@ -171,6 +171,11 @@ RUNTIME_VERSION( FUTURE ) +RUNTIME_VERSION( + (6, 4), + FUTURE +) + END_MAJOR_VERSION(6) // .......................................................................... // diff --git a/stdlib/public/core/Availability.swift b/stdlib/public/core/Availability.swift index a8fbce3e06e37..1c321827456bc 100644 --- a/stdlib/public/core/Availability.swift +++ b/stdlib/public/core/Availability.swift @@ -258,8 +258,10 @@ extension _SwiftStdlibVersion { public static var v6_2_0: Self { Self(_value: 0x060200) } @_alwaysEmitIntoClient public static var v6_3_0: Self { Self(_value: 0x060300) } + @_alwaysEmitIntoClient + public static var v6_4_0: Self { Self(_value: 0x060400) } - private static var _current: Self { .v6_3_0 } + private static var _current: Self { .v6_4_0 } #if hasFeature(Macros) @available(SwiftStdlib 5.7, *) diff --git a/utils/availability-macros.def b/utils/availability-macros.def index 87030665aacbd..d11224e928a0d 100644 --- a/utils/availability-macros.def +++ b/utils/availability-macros.def @@ -47,6 +47,7 @@ SwiftStdlib 6.0:macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0 SwiftStdlib 6.1:macOS 15.4, iOS 18.4, watchOS 11.4, tvOS 18.4, visionOS 2.4 SwiftStdlib 6.2:macOS 26.0, iOS 26.0, watchOS 26.0, tvOS 26.0, visionOS 26.0 SwiftStdlib 6.3:macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, visionOS 9999 +SwiftStdlib 6.4:macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, visionOS 9999 # Like SwiftStdlib 5.0, but also the oldest visionOS. SwiftCompatibilitySpan 5.0:macOS 10.14.4, iOS 12.2, watchOS 5.2, tvOS 12.2, visionOS 1.0 From b7e32db4533f3d7552224352504a8153abe03080 Mon Sep 17 00:00:00 2001 From: Karoy Lorentey Date: Mon, 8 Dec 2025 14:03:51 -0800 Subject: [PATCH 03/16] [stdlib] Update availability of isTriviallyIdentical methods --- stdlib/public/core/String.swift | 2 +- stdlib/public/core/Substring.swift | 2 +- test/stdlib/StringAPI.swift | 18 +++++++++--------- test/stdlib/subString.swift | 18 +++++++++--------- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/stdlib/public/core/String.swift b/stdlib/public/core/String.swift index 12d0413f36f66..bc02ebcbdcc1a 100644 --- a/stdlib/public/core/String.swift +++ b/stdlib/public/core/String.swift @@ -1146,7 +1146,7 @@ extension String { /// identical. /// /// - Complexity: O(1) - @available(SwiftStdlib 9999, *) + @available(StdlibDeploymentTarget 6.4, *) public func isTriviallyIdentical(to other: Self) -> Bool { self._guts.rawBits == other._guts.rawBits } diff --git a/stdlib/public/core/Substring.swift b/stdlib/public/core/Substring.swift index ef70c842b6720..7ce0bafc6f6b5 100644 --- a/stdlib/public/core/Substring.swift +++ b/stdlib/public/core/Substring.swift @@ -1420,7 +1420,7 @@ extension Substring { /// identical. /// /// - Complexity: O(1) - @available(SwiftStdlib 9999, *) + @available(StdlibDeploymentTarget 6.4, *) public func isTriviallyIdentical(to other: Self) -> Bool { self._wholeGuts.rawBits == other._wholeGuts.rawBits && self._offsetRange == other._offsetRange diff --git a/test/stdlib/StringAPI.swift b/test/stdlib/StringAPI.swift index 91e2fe4ae5995..9cfbe9f66396e 100644 --- a/test/stdlib/StringAPI.swift +++ b/test/stdlib/StringAPI.swift @@ -535,11 +535,11 @@ StringTests.test("hasPrefix/hasSuffix vs Character boundaries") { StringTests.test("isTriviallyIdentical(to:) small ascii") .skip(.custom( - { if #available(SwiftStdlib 9999, *) { false } else { true } }, - reason: "Requires Swift 6.3's standard library" + { if #available(StdlibDeploymentTarget 6.4, *) { false } else { true } }, + reason: "Requires Swift 6.4's standard library" )) .code { - guard #available(SwiftStdlib 9999, *) else { return } + guard #available(StdlibDeploymentTarget 6.4, *) else { return } let a = "Hello" let b = "Hello" @@ -554,11 +554,11 @@ StringTests.test("isTriviallyIdentical(to:) small ascii") StringTests.test("isTriviallyIdentical(to:) small unicode") .skip(.custom( - { if #available(SwiftStdlib 9999, *) { false } else { true } }, - reason: "Requires Swift 6.3's standard library" + { if #available(StdlibDeploymentTarget 6.4, *) { false } else { true } }, + reason: "Requires Swift 6.4's standard library" )) .code { - guard #available(SwiftStdlib 9999, *) else { return } + guard #available(StdlibDeploymentTarget 6.4, *) else { return } let a = "Cafe\u{301}" let b = "Cafe\u{301}" @@ -575,11 +575,11 @@ StringTests.test("isTriviallyIdentical(to:) small unicode") StringTests.test("isTriviallyIdentical(to:) large ascii") .skip(.custom( - { if #available(SwiftStdlib 9999, *) { false } else { true } }, - reason: "Requires Swift 6.3's standard library" + { if #available(StdlibDeploymentTarget 6.4, *) { false } else { true } }, + reason: "Requires Swift 6.4's standard library" )) .code { - guard #available(SwiftStdlib 9999, *) else { return } + guard #available(StdlibDeploymentTarget 6.4, *) else { return } let a = String(repeating: "foo", count: 1000) let b = String(repeating: "foo", count: 1000) diff --git a/test/stdlib/subString.swift b/test/stdlib/subString.swift index 10351bfd9ee60..be31908699e2c 100644 --- a/test/stdlib/subString.swift +++ b/test/stdlib/subString.swift @@ -319,11 +319,11 @@ SubstringTests.test("Substring.base") { SubstringTests.test("isTriviallyIdentical(to:) small ascii") .skip(.custom( - { if #available(SwiftStdlib 9999, *) { false } else { true } }, - reason: "Requires Swift 6.3's standard library" + { if #available(StdlibDeploymentTarget 6.4, *) { false } else { true } }, + reason: "Requires Swift 6.4's standard library" )) .code { - guard #available(SwiftStdlib 9999, *) else { return } + guard #available(StdlibDeploymentTarget 6.4, *) else { return } let a = "Hello" let b = "Hello" @@ -378,11 +378,11 @@ SubstringTests.test("isTriviallyIdentical(to:) small ascii") SubstringTests.test("isTriviallyIdentical(to:) small unicode") .skip(.custom( - { if #available(SwiftStdlib 9999, *) { false } else { true } }, - reason: "Requires Swift 6.3's standard library" + { if #available(StdlibDeploymentTarget 6.4, *) { false } else { true } }, + reason: "Requires Swift 6.4's standard library" )) .code { - guard #available(SwiftStdlib 9999, *) else { return } + guard #available(StdlibDeploymentTarget 6.4, *) else { return } let a = "Cafe\u{301}" let b = "Cafe\u{301}" @@ -431,11 +431,11 @@ SubstringTests.test("isTriviallyIdentical(to:) small unicode") SubstringTests.test("isTriviallyIdentical(to:) large ascii") .skip(.custom( - { if #available(SwiftStdlib 9999, *) { false } else { true } }, - reason: "Requires Swift 6.3's standard library" + { if #available(StdlibDeploymentTarget 6.4, *) { false } else { true } }, + reason: "Requires Swift 6.4's standard library" )) .code { - guard #available(SwiftStdlib 9999, *) else { return } + guard #available(StdlibDeploymentTarget 6.4, *) else { return } let a = String(repeating: "foo", count: 1000) let b = String(repeating: "foo", count: 1000) From a7b152b94b9730e905b7cca15841632f3600629c Mon Sep 17 00:00:00 2001 From: Karoy Lorentey Date: Mon, 8 Dec 2025 14:09:12 -0800 Subject: [PATCH 04/16] [benchmark] Remove new benchmarks --- benchmark/single-source/StringTests.swift | 23 +-------- benchmark/single-source/SubstringTest.swift | 56 +++++++-------------- 2 files changed, 21 insertions(+), 58 deletions(-) diff --git a/benchmark/single-source/StringTests.swift b/benchmark/single-source/StringTests.swift index 579ac6f3d3ce8..d3890e241cb48 100644 --- a/benchmark/single-source/StringTests.swift +++ b/benchmark/single-source/StringTests.swift @@ -14,7 +14,7 @@ import TestsUtils @_spi(_Unicode) import Swift -public var benchmarks: [BenchmarkInfo] { +public let benchmarks: [BenchmarkInfo] = { var result = [ BenchmarkInfo( name: "StringEqualPointerComparison", @@ -49,16 +49,8 @@ public var benchmarks: [BenchmarkInfo] { runFunction: run_iterateWords, tags: [.validation, .String])) } - - if #available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, visionOS 9999, *) { - result.append( - BenchmarkInfo( - name: "StringIdentical", - runFunction: run_StringIdentical, - tags: [.validation, .api, .String])) - } return result -} +}() // FIXME(string) public func run_StringHasPrefixAscii(_ n: Int) { @@ -1684,14 +1676,3 @@ public func run_iterateWords(_ n: Int) { blackHole(swiftOrgHTML._words) } } - -@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, visionOS 9999, *) -public func run_StringIdentical(_ n: Int) { - let str1 = "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. " - let str2 = str1 - for _ in 0 ..< n { - for _ in 0 ..< 100_000 { - check(str1.isTriviallyIdentical(to: str2)) - } - } -} diff --git a/benchmark/single-source/SubstringTest.swift b/benchmark/single-source/SubstringTest.swift index a7652ff1064bc..7db0000393d51 100644 --- a/benchmark/single-source/SubstringTest.swift +++ b/benchmark/single-source/SubstringTest.swift @@ -12,34 +12,25 @@ import TestsUtils -public var benchmarks: [BenchmarkInfo] { - var result = [ - BenchmarkInfo(name: "EqualStringSubstring", runFunction: run_EqualStringSubstring, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "EqualSubstringString", runFunction: run_EqualSubstringString, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "EqualSubstringSubstring", runFunction: run_EqualSubstringSubstring, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "EqualSubstringSubstringGenericEquatable", runFunction: run_EqualSubstringSubstringGenericEquatable, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "SubstringRemoveFirst1", runFunction: run_SubstringRemoveFirst1, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "SubstringRemoveLast1", runFunction: run_SubstringRemoveLast1, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "LessSubstringSubstring", runFunction: run_LessSubstringSubstring, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "LessSubstringSubstringGenericComparable", runFunction: run_LessSubstringSubstringGenericComparable, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "StringFromLongWholeSubstring", runFunction: run_StringFromLongWholeSubstring, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "StringFromLongWholeSubstringGeneric", runFunction: run_StringFromLongWholeSubstringGeneric, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "SubstringComparable", runFunction: run_SubstringComparable, tags: [.validation, .api, .String], - setUpFunction: { blackHole(_comparison) }), - BenchmarkInfo(name: "SubstringEqualString", runFunction: run_SubstringEqualString, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "SubstringEquatable", runFunction: run_SubstringEquatable, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "SubstringFromLongString2", runFunction: run_SubstringFromLongString, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "SubstringFromLongStringGeneric2", runFunction: run_SubstringFromLongStringGeneric, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "SubstringTrimmingASCIIWhitespace", runFunction: run_SubstringTrimmingASCIIWhitespace, tags: [.validation, .api, .String]), - ] - - if #available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, visionOS 9999, *) { - result.append( - BenchmarkInfo(name: "SubstringIdentical", runFunction: run_SubstringIdentical, tags: [.validation, .String]), - ) - } - return result -} +public let benchmarks: [BenchmarkInfo] = [ + BenchmarkInfo(name: "EqualStringSubstring", runFunction: run_EqualStringSubstring, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "EqualSubstringString", runFunction: run_EqualSubstringString, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "EqualSubstringSubstring", runFunction: run_EqualSubstringSubstring, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "EqualSubstringSubstringGenericEquatable", runFunction: run_EqualSubstringSubstringGenericEquatable, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "SubstringRemoveFirst1", runFunction: run_SubstringRemoveFirst1, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "SubstringRemoveLast1", runFunction: run_SubstringRemoveLast1, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "LessSubstringSubstring", runFunction: run_LessSubstringSubstring, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "LessSubstringSubstringGenericComparable", runFunction: run_LessSubstringSubstringGenericComparable, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "StringFromLongWholeSubstring", runFunction: run_StringFromLongWholeSubstring, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "StringFromLongWholeSubstringGeneric", runFunction: run_StringFromLongWholeSubstringGeneric, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "SubstringComparable", runFunction: run_SubstringComparable, tags: [.validation, .api, .String], + setUpFunction: { blackHole(_comparison) }), + BenchmarkInfo(name: "SubstringEqualString", runFunction: run_SubstringEqualString, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "SubstringEquatable", runFunction: run_SubstringEquatable, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "SubstringFromLongString2", runFunction: run_SubstringFromLongString, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "SubstringFromLongStringGeneric2", runFunction: run_SubstringFromLongStringGeneric, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "SubstringTrimmingASCIIWhitespace", runFunction: run_SubstringTrimmingASCIIWhitespace, tags: [.validation, .api, .String]), +] // A string that doesn't fit in small string storage and doesn't fit in Latin-1 let longWide = "fὢasὢodὢijὢadὢolὢsjὢalὢsdὢjlὢasὢdfὢijὢliὢsdὢjøὢslὢdiὢalὢiὢ" @@ -341,12 +332,3 @@ public func run _LessSubstringSubstringGenericStringProtocol(_ n: Int) { } } */ - -@inline(never) -@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, visionOS 9999, *) -public func run_SubstringIdentical(_ n: Int) { - let (a, b) = (ss1, ss1) - for _ in 1...n*500 { - blackHole(a.isTriviallyIdentical(to: b)) - } -} From 3833cbdd87ee6302abdf56aed536a0e8ce626c49 Mon Sep 17 00:00:00 2001 From: Karoy Lorentey Date: Mon, 8 Dec 2025 14:10:04 -0800 Subject: [PATCH 05/16] [test] Fix ABI expectations --- test/abi/Inputs/macOS/arm64/stdlib/baseline | 2 -- test/abi/Inputs/macOS/arm64/stdlib/baseline-asserts | 2 -- test/abi/Inputs/macOS/x86_64/stdlib/baseline | 2 -- test/abi/Inputs/macOS/x86_64/stdlib/baseline-asserts | 2 -- test/abi/macOS/arm64/stdlib.swift | 4 ++++ test/abi/macOS/x86_64/stdlib.swift | 4 ++++ 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/abi/Inputs/macOS/arm64/stdlib/baseline b/test/abi/Inputs/macOS/arm64/stdlib/baseline index e774cbcd1cb14..e2cefe00d8792 100644 --- a/test/abi/Inputs/macOS/arm64/stdlib/baseline +++ b/test/abi/Inputs/macOS/arm64/stdlib/baseline @@ -1285,7 +1285,6 @@ _$sSS19_uncheckedFromUTF16ySSSRys6UInt16VGFZ _$sSS19stringInterpolationSSs013DefaultStringB0V_tcfC _$sSS1loiySbSS_SStFZ _$sSS1poiyS2S_SStFZ -_$sSS20isTriviallyIdentical2toSbSS_tF _$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC _$sSS21withMutableCharactersyxxSSzXElF _$sSS23_bridgeToObjectiveCImplyXlyF @@ -3615,7 +3614,6 @@ _$sSs17UnicodeScalarViewVyABSnySS5IndexVGcipMV _$sSs17UnicodeScalarViewVys0A0O0B0VSS5IndexVcig _$sSs17UnicodeScalarViewVys0A0O0B0VSS5IndexVcipMV _$sSs19stringInterpolationSss013DefaultStringB0V_tcfC -_$sSs20isTriviallyIdentical2toSbSs_tF _$sSs20unicodeScalarLiteralSsSS_tcfC _$sSs21withMutableCharactersyxxSszXElF _$sSs25customPlaygroundQuickLooks01_bcD0Ovg diff --git a/test/abi/Inputs/macOS/arm64/stdlib/baseline-asserts b/test/abi/Inputs/macOS/arm64/stdlib/baseline-asserts index 737987666e9c1..b4c2cd5b74e43 100644 --- a/test/abi/Inputs/macOS/arm64/stdlib/baseline-asserts +++ b/test/abi/Inputs/macOS/arm64/stdlib/baseline-asserts @@ -1285,7 +1285,6 @@ _$sSS19_uncheckedFromUTF16ySSSRys6UInt16VGFZ _$sSS19stringInterpolationSSs013DefaultStringB0V_tcfC _$sSS1loiySbSS_SStFZ _$sSS1poiyS2S_SStFZ -_$sSS20isTriviallyIdentical2toSbSS_tF _$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC _$sSS21withMutableCharactersyxxSSzXElF _$sSS23_bridgeToObjectiveCImplyXlyF @@ -3615,7 +3614,6 @@ _$sSs17UnicodeScalarViewVyABSnySS5IndexVGcipMV _$sSs17UnicodeScalarViewVys0A0O0B0VSS5IndexVcig _$sSs17UnicodeScalarViewVys0A0O0B0VSS5IndexVcipMV _$sSs19stringInterpolationSss013DefaultStringB0V_tcfC -_$sSs20isTriviallyIdentical2toSbSs_tF _$sSs20unicodeScalarLiteralSsSS_tcfC _$sSs21withMutableCharactersyxxSszXElF _$sSs25customPlaygroundQuickLooks01_bcD0Ovg diff --git a/test/abi/Inputs/macOS/x86_64/stdlib/baseline b/test/abi/Inputs/macOS/x86_64/stdlib/baseline index f00d1e3a78b21..48dc1820c1982 100644 --- a/test/abi/Inputs/macOS/x86_64/stdlib/baseline +++ b/test/abi/Inputs/macOS/x86_64/stdlib/baseline @@ -1287,7 +1287,6 @@ _$sSS19_uncheckedFromUTF16ySSSRys6UInt16VGFZ _$sSS19stringInterpolationSSs013DefaultStringB0V_tcfC _$sSS1loiySbSS_SStFZ _$sSS1poiyS2S_SStFZ -_$sSS20isTriviallyIdentical2toSbSS_tF _$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC _$sSS21withMutableCharactersyxxSSzXElF _$sSS23_bridgeToObjectiveCImplyXlyF @@ -3617,7 +3616,6 @@ _$sSs17UnicodeScalarViewVyABSnySS5IndexVGcipMV _$sSs17UnicodeScalarViewVys0A0O0B0VSS5IndexVcig _$sSs17UnicodeScalarViewVys0A0O0B0VSS5IndexVcipMV _$sSs19stringInterpolationSss013DefaultStringB0V_tcfC -_$sSs20isTriviallyIdentical2toSbSs_tF _$sSs20unicodeScalarLiteralSsSS_tcfC _$sSs21withMutableCharactersyxxSszXElF _$sSs25customPlaygroundQuickLooks01_bcD0Ovg diff --git a/test/abi/Inputs/macOS/x86_64/stdlib/baseline-asserts b/test/abi/Inputs/macOS/x86_64/stdlib/baseline-asserts index 7412236cb6ceb..e9d6bfe251c0e 100644 --- a/test/abi/Inputs/macOS/x86_64/stdlib/baseline-asserts +++ b/test/abi/Inputs/macOS/x86_64/stdlib/baseline-asserts @@ -1287,7 +1287,6 @@ _$sSS19_uncheckedFromUTF16ySSSRys6UInt16VGFZ _$sSS19stringInterpolationSSs013DefaultStringB0V_tcfC _$sSS1loiySbSS_SStFZ _$sSS1poiyS2S_SStFZ -_$sSS20isTriviallyIdentical2toSbSS_tF _$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC _$sSS21withMutableCharactersyxxSSzXElF _$sSS23_bridgeToObjectiveCImplyXlyF @@ -3617,7 +3616,6 @@ _$sSs17UnicodeScalarViewVyABSnySS5IndexVGcipMV _$sSs17UnicodeScalarViewVys0A0O0B0VSS5IndexVcig _$sSs17UnicodeScalarViewVys0A0O0B0VSS5IndexVcipMV _$sSs19stringInterpolationSss013DefaultStringB0V_tcfC -_$sSs20isTriviallyIdentical2toSbSs_tF _$sSs20unicodeScalarLiteralSsSS_tcfC _$sSs21withMutableCharactersyxxSszXElF _$sSs25customPlaygroundQuickLooks01_bcD0Ovg diff --git a/test/abi/macOS/arm64/stdlib.swift b/test/abi/macOS/arm64/stdlib.swift index d299100e8e000..15b990049ec0a 100644 --- a/test/abi/macOS/arm64/stdlib.swift +++ b/test/abi/macOS/arm64/stdlib.swift @@ -1161,3 +1161,7 @@ Added: _$ss13EncodingErrorO16debugDescriptionSSvg Added: _$ss13EncodingErrorO16debugDescriptionSSvpMV Added: _$ss13EncodingErrorOs28CustomDebugStringConvertiblesMc Added: _$ss13EncodingErrorOs28CustomDebugStringConvertiblesWP + +// SE-0494 Add isTriviallyIdentical(to:) Methods to String and Substring +Added: _$sSS20isTriviallyIdentical2toSbSS_tF +Added: _$sSs20isTriviallyIdentical2toSbSs_tF diff --git a/test/abi/macOS/x86_64/stdlib.swift b/test/abi/macOS/x86_64/stdlib.swift index a75fc1bd26ac0..09fa99fb77ff2 100644 --- a/test/abi/macOS/x86_64/stdlib.swift +++ b/test/abi/macOS/x86_64/stdlib.swift @@ -1156,3 +1156,7 @@ Added: _$ss13EncodingErrorO16debugDescriptionSSvg Added: _$ss13EncodingErrorO16debugDescriptionSSvpMV Added: _$ss13EncodingErrorOs28CustomDebugStringConvertiblesMc Added: _$ss13EncodingErrorOs28CustomDebugStringConvertiblesWP + +// SE-0494 Add isTriviallyIdentical(to:) Methods to String and Substring +Added: _$sSS20isTriviallyIdentical2toSbSS_tF +Added: _$sSs20isTriviallyIdentical2toSbSs_tF From c8202c6f9a62dd6f1c0cdffaa3df69dc77552e92 Mon Sep 17 00:00:00 2001 From: Karoy Lorentey Date: Mon, 8 Dec 2025 14:17:33 -0800 Subject: [PATCH 06/16] Apply suggestions from code review --- stdlib/public/core/String.swift | 3 +-- stdlib/public/core/Substring.swift | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/stdlib/public/core/String.swift b/stdlib/public/core/String.swift index bc02ebcbdcc1a..bbcc33326e16e 100644 --- a/stdlib/public/core/String.swift +++ b/stdlib/public/core/String.swift @@ -1127,8 +1127,7 @@ extension String { /// - If `a.isTriviallyIdentical(to: b)` and `b.isTriviallyIdentical(to: c)` /// are both `true`, then `a.isTriviallyIdentical(to: c)` is also `true`. /// (Transitivity) - /// - `a.isTriviallyIdentical(b)` implies `a == b` - /// - `a == b` does not imply `a.isTriviallyIdentical(b)` + /// - `a.isTriviallyIdentical(b)` implies `a == b`. `a == b` does not imply `a.isTriviallyIdentical(b)` /// /// Values produced by copying the same value, with no intervening mutations, /// will compare identical: diff --git a/stdlib/public/core/Substring.swift b/stdlib/public/core/Substring.swift index 7ce0bafc6f6b5..b6e40464b1051 100644 --- a/stdlib/public/core/Substring.swift +++ b/stdlib/public/core/Substring.swift @@ -1401,8 +1401,7 @@ extension Substring { /// - If `a.isTriviallyIdentical(to: b)` and `b.isTriviallyIdentical(to: c)` /// are both `true`, then `a.isTriviallyIdentical(to: c)` is also `true`. /// (Transitivity) - /// - `a.isTriviallyIdentical(b)` implies `a == b` - /// - `a == b` does not imply `a.isTriviallyIdentical(b)` + /// - `a.isTriviallyIdentical(b)` implies `a == b`. `a == b` does not imply `a.isTriviallyIdentical(b)` /// /// Values produced by copying the same value, with no intervening mutations, /// will compare identical: From be5ec1aed43b0842597de0a0e54f2be25245a240 Mon Sep 17 00:00:00 2001 From: WindowsMEMZ Date: Tue, 28 Oct 2025 18:56:18 +0800 Subject: [PATCH 07/16] Add `isTriviallyIdentical` for unicode views --- stdlib/public/core/StringUTF16View.swift | 11 ++++++ stdlib/public/core/StringUTF8View.swift | 11 ++++++ .../public/core/StringUnicodeScalarView.swift | 11 ++++++ stdlib/public/core/Substring.swift | 36 +++++++++++++++++++ 4 files changed, 69 insertions(+) diff --git a/stdlib/public/core/StringUTF16View.swift b/stdlib/public/core/StringUTF16View.swift index f4811c3ac98ba..d0e75f3842c44 100644 --- a/stdlib/public/core/StringUTF16View.swift +++ b/stdlib/public/core/StringUTF16View.swift @@ -1056,3 +1056,14 @@ extension String.UTF16View { } } } + +extension String.UTF16View { + /// Returns a boolean value indicating whether this UTF16 view + /// is trivially identical to `other`. + /// + /// - Complexity: O(1) + @_alwaysEmitIntoClient + public func isTriviallyIdentical(to other: Self) -> Bool { + self._guts.rawBits == other._guts.rawBits + } +} diff --git a/stdlib/public/core/StringUTF8View.swift b/stdlib/public/core/StringUTF8View.swift index 20f97379c460b..a239da30da0ec 100644 --- a/stdlib/public/core/StringUTF8View.swift +++ b/stdlib/public/core/StringUTF8View.swift @@ -684,3 +684,14 @@ extension String.UTF8View { return unsafe try _guts.withFastUTF8(body) } } + +extension String.UTF8View { + /// Returns a boolean value indicating whether this UTF8 view + /// is trivially identical to `other`. + /// + /// - Complexity: O(1) + @_alwaysEmitIntoClient + public func isTriviallyIdentical(to other: Self) -> Bool { + self._guts.rawBits == other._guts.rawBits + } +} diff --git a/stdlib/public/core/StringUnicodeScalarView.swift b/stdlib/public/core/StringUnicodeScalarView.swift index 271cd9b1ece77..60dd589f3d31c 100644 --- a/stdlib/public/core/StringUnicodeScalarView.swift +++ b/stdlib/public/core/StringUnicodeScalarView.swift @@ -527,3 +527,14 @@ extension String.UnicodeScalarView { return r._knownUTF16 } } + +extension String.UnicodeScalarView { + /// Returns a boolean value indicating whether this unicode scalar view + /// is trivially identical to `other`. + /// + /// - Complexity: O(1) + @_alwaysEmitIntoClient + public func isTriviallyIdentical(to other: Self) -> Bool { + self._guts.rawBits == other._guts.rawBits + } +} diff --git a/stdlib/public/core/Substring.swift b/stdlib/public/core/Substring.swift index b6e40464b1051..826c7c52359e7 100644 --- a/stdlib/public/core/Substring.swift +++ b/stdlib/public/core/Substring.swift @@ -882,6 +882,18 @@ extension Substring.UTF8View { #endif // !(os(watchOS) && _pointerBitWidth(_32)) } +extension Substring.UTF8View { + /// Returns a boolean value indicating whether this UTF8 view + /// is trivially identical to `other`. + /// + /// - Complexity: O(1) + @_alwaysEmitIntoClient + public func isTriviallyIdentical(to other: Self) -> Bool { + self._base.isTriviallyIdentical(to: other._base) + && self._bounds == other._bounds + } +} + extension Substring { @inlinable public var utf8: UTF8View { @@ -1037,6 +1049,18 @@ extension Substring.UTF16View: BidirectionalCollection { } } +extension Substring.UTF16View { + /// Returns a boolean value indicating whether this UTF16 view + /// is trivially identical to `other`. + /// + /// - Complexity: O(1) + @_alwaysEmitIntoClient + public func isTriviallyIdentical(to other: Self) -> Bool { + self._base.isTriviallyIdentical(to: other._base) + && self._bounds == other._bounds + } +} + extension Substring { @inlinable public var utf16: UTF16View { @@ -1281,6 +1305,18 @@ extension Substring.UnicodeScalarView: RangeReplaceableCollection { } } +extension Substring.UnicodeScalarView { + /// Returns a boolean value indicating whether this unicode scalar view + /// is trivially identical to `other`. + /// + /// - Complexity: O(1) + @_alwaysEmitIntoClient + public func isTriviallyIdentical(to other: Self) -> Bool { + self._slice._base.isTriviallyIdentical(to: other._slice._base) + && self._bounds == other._bounds + } +} + extension Substring: RangeReplaceableCollection { @_specialize(where S == String) @_specialize(where S == Substring) From 5b22d2a46757b957185d125f1ec1e243195074cc Mon Sep 17 00:00:00 2001 From: WindowsMEMZ Date: Tue, 28 Oct 2025 20:29:33 +0800 Subject: [PATCH 08/16] Add tests --- test/stdlib/StringAPI.swift | 88 +++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/test/stdlib/StringAPI.swift b/test/stdlib/StringAPI.swift index 9cfbe9f66396e..7584492cdfa1a 100644 --- a/test/stdlib/StringAPI.swift +++ b/test/stdlib/StringAPI.swift @@ -522,6 +522,94 @@ StringTests.test("_isIdentical(to:)") { expectTrue(g._isIdentical(to: g)) } +StringTests.test("String.UnicodeScalarView.isTriviallyIdentical(to:)") { + let a = "Hello".unicodeScalars + let b = "Hello".unicodeScalars + expectTrue(a.isTriviallyIdentical(to: a)) + expectTrue(b.isTriviallyIdentical(to: b)) + expectTrue(a.isTriviallyIdentical(to: b)) + expectTrue(b.isTriviallyIdentical(to: a)) + + let c = "Abcde".unicodeScalars + expectFalse(a.isTriviallyIdentical(to: c)) + expectFalse(c.isTriviallyIdentical(to: a)) +} +StringTests.test("String.UTF8View.isTriviallyIdentical(to:)") { + let a = "Hello".utf8 + let b = "Hello".utf8 + expectTrue(a.isTriviallyIdentical(to: a)) + expectTrue(b.isTriviallyIdentical(to: b)) + expectTrue(a.isTriviallyIdentical(to: b)) + expectTrue(b.isTriviallyIdentical(to: a)) + + + let c = "Abcde".utf8 + expectFalse(a.isTriviallyIdentical(to: c)) + expectFalse(c.isTriviallyIdentical(to: a)) +} +StringTests.test("String.UTF16View.isTriviallyIdentical(to:)") { + let a = "Hello".utf16 + let b = "Hello".utf16 + expectTrue(a.isTriviallyIdentical(to: a)) + expectTrue(b.isTriviallyIdentical(to: b)) + expectTrue(a.isTriviallyIdentical(to: b)) + expectTrue(b.isTriviallyIdentical(to: a)) + + + let c = "Abcde".utf16 + expectFalse(a.isTriviallyIdentical(to: c)) + expectFalse(c.isTriviallyIdentical(to: a)) +} + +StringTests.test("Substring.UnicodeScalarView.isTriviallyIdentical(to:)") { + let base1 = "Test String" + let a = base1[base1.index(base1.startIndex, offsetBy: 5).. Date: Thu, 30 Oct 2025 09:49:24 +0800 Subject: [PATCH 09/16] Make `isIdentical` opaque for clients --- stdlib/public/core/StringUTF16View.swift | 2 +- stdlib/public/core/StringUTF8View.swift | 2 +- stdlib/public/core/StringUnicodeScalarView.swift | 2 +- stdlib/public/core/Substring.swift | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/stdlib/public/core/StringUTF16View.swift b/stdlib/public/core/StringUTF16View.swift index d0e75f3842c44..6f217b7a25d56 100644 --- a/stdlib/public/core/StringUTF16View.swift +++ b/stdlib/public/core/StringUTF16View.swift @@ -1062,7 +1062,7 @@ extension String.UTF16View { /// is trivially identical to `other`. /// /// - Complexity: O(1) - @_alwaysEmitIntoClient + @available(SwiftStdlib 6.3, *) public func isTriviallyIdentical(to other: Self) -> Bool { self._guts.rawBits == other._guts.rawBits } diff --git a/stdlib/public/core/StringUTF8View.swift b/stdlib/public/core/StringUTF8View.swift index a239da30da0ec..4ab74d7af886b 100644 --- a/stdlib/public/core/StringUTF8View.swift +++ b/stdlib/public/core/StringUTF8View.swift @@ -690,7 +690,7 @@ extension String.UTF8View { /// is trivially identical to `other`. /// /// - Complexity: O(1) - @_alwaysEmitIntoClient + @available(SwiftStdlib 6.3, *) public func isTriviallyIdentical(to other: Self) -> Bool { self._guts.rawBits == other._guts.rawBits } diff --git a/stdlib/public/core/StringUnicodeScalarView.swift b/stdlib/public/core/StringUnicodeScalarView.swift index 60dd589f3d31c..19a10cb5eaf2c 100644 --- a/stdlib/public/core/StringUnicodeScalarView.swift +++ b/stdlib/public/core/StringUnicodeScalarView.swift @@ -533,7 +533,7 @@ extension String.UnicodeScalarView { /// is trivially identical to `other`. /// /// - Complexity: O(1) - @_alwaysEmitIntoClient + @available(SwiftStdlib 6.3, *) public func isTriviallyIdentical(to other: Self) -> Bool { self._guts.rawBits == other._guts.rawBits } diff --git a/stdlib/public/core/Substring.swift b/stdlib/public/core/Substring.swift index 826c7c52359e7..62e499a2c55ac 100644 --- a/stdlib/public/core/Substring.swift +++ b/stdlib/public/core/Substring.swift @@ -887,7 +887,7 @@ extension Substring.UTF8View { /// is trivially identical to `other`. /// /// - Complexity: O(1) - @_alwaysEmitIntoClient + @available(SwiftStdlib 6.3, *) public func isTriviallyIdentical(to other: Self) -> Bool { self._base.isTriviallyIdentical(to: other._base) && self._bounds == other._bounds @@ -1054,7 +1054,7 @@ extension Substring.UTF16View { /// is trivially identical to `other`. /// /// - Complexity: O(1) - @_alwaysEmitIntoClient + @available(SwiftStdlib 6.3, *) public func isTriviallyIdentical(to other: Self) -> Bool { self._base.isTriviallyIdentical(to: other._base) && self._bounds == other._bounds @@ -1310,7 +1310,7 @@ extension Substring.UnicodeScalarView { /// is trivially identical to `other`. /// /// - Complexity: O(1) - @_alwaysEmitIntoClient + @available(SwiftStdlib 6.3, *) public func isTriviallyIdentical(to other: Self) -> Bool { self._slice._base.isTriviallyIdentical(to: other._slice._base) && self._bounds == other._bounds From 288a69842dd1027ed6c76fb83894a37b35a3c293 Mon Sep 17 00:00:00 2001 From: WindowsMEMZ Date: Thu, 30 Oct 2025 10:00:39 +0800 Subject: [PATCH 10/16] Add `isIdentical` to StringGuts and use it for comparation --- stdlib/public/core/StringGuts.swift | 7 +++++++ stdlib/public/core/StringUTF16View.swift | 2 +- stdlib/public/core/StringUTF8View.swift | 2 +- stdlib/public/core/StringUnicodeScalarView.swift | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/stdlib/public/core/StringGuts.swift b/stdlib/public/core/StringGuts.swift index 4ae5123bc2f44..fb89a21b57a62 100644 --- a/stdlib/public/core/StringGuts.swift +++ b/stdlib/public/core/StringGuts.swift @@ -418,6 +418,13 @@ extension _StringGuts { } } +extension _StringGuts { + @inline(__always) // Performance + internal func isTriviallyIdentical(to other: Self) -> Bool { + self.rawBits == other.rawBits + } +} + #if _runtime(_ObjC) extension _StringGuts { diff --git a/stdlib/public/core/StringUTF16View.swift b/stdlib/public/core/StringUTF16View.swift index 6f217b7a25d56..9e6acbc26d098 100644 --- a/stdlib/public/core/StringUTF16View.swift +++ b/stdlib/public/core/StringUTF16View.swift @@ -1064,6 +1064,6 @@ extension String.UTF16View { /// - Complexity: O(1) @available(SwiftStdlib 6.3, *) public func isTriviallyIdentical(to other: Self) -> Bool { - self._guts.rawBits == other._guts.rawBits + self._guts.isTriviallyIdentical(to: other._guts) } } diff --git a/stdlib/public/core/StringUTF8View.swift b/stdlib/public/core/StringUTF8View.swift index 4ab74d7af886b..d471db4beeaed 100644 --- a/stdlib/public/core/StringUTF8View.swift +++ b/stdlib/public/core/StringUTF8View.swift @@ -692,6 +692,6 @@ extension String.UTF8View { /// - Complexity: O(1) @available(SwiftStdlib 6.3, *) public func isTriviallyIdentical(to other: Self) -> Bool { - self._guts.rawBits == other._guts.rawBits + self._guts.isTriviallyIdentical(to: other._guts) } } diff --git a/stdlib/public/core/StringUnicodeScalarView.swift b/stdlib/public/core/StringUnicodeScalarView.swift index 19a10cb5eaf2c..5bdb2c5e65da2 100644 --- a/stdlib/public/core/StringUnicodeScalarView.swift +++ b/stdlib/public/core/StringUnicodeScalarView.swift @@ -535,6 +535,6 @@ extension String.UnicodeScalarView { /// - Complexity: O(1) @available(SwiftStdlib 6.3, *) public func isTriviallyIdentical(to other: Self) -> Bool { - self._guts.rawBits == other._guts.rawBits + self._guts.isTriviallyIdentical(to: other._guts) } } From 8055d913161dbb7a4eb322f6f39d3b393c2e03c0 Mon Sep 17 00:00:00 2001 From: WindowsMEMZ Date: Thu, 30 Oct 2025 11:09:17 +0800 Subject: [PATCH 11/16] Update tests for availability checking --- test/stdlib/StringAPI.swift | 208 +++++++++++++++++++++--------------- 1 file changed, 122 insertions(+), 86 deletions(-) diff --git a/test/stdlib/StringAPI.swift b/test/stdlib/StringAPI.swift index 7584492cdfa1a..fc6af2d85f814 100644 --- a/test/stdlib/StringAPI.swift +++ b/test/stdlib/StringAPI.swift @@ -522,93 +522,129 @@ StringTests.test("_isIdentical(to:)") { expectTrue(g._isIdentical(to: g)) } -StringTests.test("String.UnicodeScalarView.isTriviallyIdentical(to:)") { - let a = "Hello".unicodeScalars - let b = "Hello".unicodeScalars - expectTrue(a.isTriviallyIdentical(to: a)) - expectTrue(b.isTriviallyIdentical(to: b)) - expectTrue(a.isTriviallyIdentical(to: b)) - expectTrue(b.isTriviallyIdentical(to: a)) - - let c = "Abcde".unicodeScalars - expectFalse(a.isTriviallyIdentical(to: c)) - expectFalse(c.isTriviallyIdentical(to: a)) -} -StringTests.test("String.UTF8View.isTriviallyIdentical(to:)") { - let a = "Hello".utf8 - let b = "Hello".utf8 - expectTrue(a.isTriviallyIdentical(to: a)) - expectTrue(b.isTriviallyIdentical(to: b)) - expectTrue(a.isTriviallyIdentical(to: b)) - expectTrue(b.isTriviallyIdentical(to: a)) - - - let c = "Abcde".utf8 - expectFalse(a.isTriviallyIdentical(to: c)) - expectFalse(c.isTriviallyIdentical(to: a)) -} -StringTests.test("String.UTF16View.isTriviallyIdentical(to:)") { - let a = "Hello".utf16 - let b = "Hello".utf16 - expectTrue(a.isTriviallyIdentical(to: a)) - expectTrue(b.isTriviallyIdentical(to: b)) - expectTrue(a.isTriviallyIdentical(to: b)) - expectTrue(b.isTriviallyIdentical(to: a)) - - - let c = "Abcde".utf16 - expectFalse(a.isTriviallyIdentical(to: c)) - expectFalse(c.isTriviallyIdentical(to: a)) -} +StringTests.test("String.UnicodeScalarView.isTriviallyIdentical(to:)") + .skip(.custom({ + if #available(SwiftStdlib 6.3, *) { false } else { true } + }, reason: "Requires Swift stdlib 6.3")) + .code { + guard #available(SwiftStdlib 6.3, *) else { return } + + let a = "Hello".unicodeScalars + let b = "Hello".unicodeScalars + expectTrue(a.isTriviallyIdentical(to: a)) + expectTrue(b.isTriviallyIdentical(to: b)) + expectTrue(a.isTriviallyIdentical(to: b)) + expectTrue(b.isTriviallyIdentical(to: a)) + + let c = "Abcde".unicodeScalars + expectFalse(a.isTriviallyIdentical(to: c)) + expectFalse(c.isTriviallyIdentical(to: a)) + } +StringTests.test("String.UTF8View.isTriviallyIdentical(to:)") + .skip(.custom({ + if #available(SwiftStdlib 6.3, *) { false } else { true } + }, reason: "Requires Swift stdlib 6.3")) + .code { + guard #available(SwiftStdlib 6.3, *) else { return } + + let a = "Hello".utf8 + let b = "Hello".utf8 + expectTrue(a.isTriviallyIdentical(to: a)) + expectTrue(b.isTriviallyIdentical(to: b)) + expectTrue(a.isTriviallyIdentical(to: b)) + expectTrue(b.isTriviallyIdentical(to: a)) + + + let c = "Abcde".utf8 + expectFalse(a.isTriviallyIdentical(to: c)) + expectFalse(c.isTriviallyIdentical(to: a)) + } +StringTests.test("String.UTF16View.isTriviallyIdentical(to:)") + .skip(.custom({ + if #available(SwiftStdlib 6.3, *) { false } else { true } + }, reason: "Requires Swift stdlib 6.3")) + .code { + guard #available(SwiftStdlib 6.3, *) else { return } + + let a = "Hello".utf16 + let b = "Hello".utf16 + expectTrue(a.isTriviallyIdentical(to: a)) + expectTrue(b.isTriviallyIdentical(to: b)) + expectTrue(a.isTriviallyIdentical(to: b)) + expectTrue(b.isTriviallyIdentical(to: a)) + + + let c = "Abcde".utf16 + expectFalse(a.isTriviallyIdentical(to: c)) + expectFalse(c.isTriviallyIdentical(to: a)) + } -StringTests.test("Substring.UnicodeScalarView.isTriviallyIdentical(to:)") { - let base1 = "Test String" - let a = base1[base1.index(base1.startIndex, offsetBy: 5).. Date: Mon, 8 Dec 2025 14:34:35 -0800 Subject: [PATCH 12/16] [stdlib] Update availability of String view additions --- stdlib/public/core/StringUTF16View.swift | 2 +- stdlib/public/core/StringUTF8View.swift | 2 +- .../public/core/StringUnicodeScalarView.swift | 2 +- stdlib/public/core/Substring.swift | 6 ++-- test/stdlib/StringAPI.swift | 36 +++++++++---------- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/stdlib/public/core/StringUTF16View.swift b/stdlib/public/core/StringUTF16View.swift index 9e6acbc26d098..bae33dd151ddd 100644 --- a/stdlib/public/core/StringUTF16View.swift +++ b/stdlib/public/core/StringUTF16View.swift @@ -1062,7 +1062,7 @@ extension String.UTF16View { /// is trivially identical to `other`. /// /// - Complexity: O(1) - @available(SwiftStdlib 6.3, *) + @available(StdlibDeploymentTarget 6.4, *) public func isTriviallyIdentical(to other: Self) -> Bool { self._guts.isTriviallyIdentical(to: other._guts) } diff --git a/stdlib/public/core/StringUTF8View.swift b/stdlib/public/core/StringUTF8View.swift index d471db4beeaed..12b239843a6c5 100644 --- a/stdlib/public/core/StringUTF8View.swift +++ b/stdlib/public/core/StringUTF8View.swift @@ -690,7 +690,7 @@ extension String.UTF8View { /// is trivially identical to `other`. /// /// - Complexity: O(1) - @available(SwiftStdlib 6.3, *) + @available(StdlibDeploymentTarget 6.4, *) public func isTriviallyIdentical(to other: Self) -> Bool { self._guts.isTriviallyIdentical(to: other._guts) } diff --git a/stdlib/public/core/StringUnicodeScalarView.swift b/stdlib/public/core/StringUnicodeScalarView.swift index 5bdb2c5e65da2..122f4a524f0a0 100644 --- a/stdlib/public/core/StringUnicodeScalarView.swift +++ b/stdlib/public/core/StringUnicodeScalarView.swift @@ -533,7 +533,7 @@ extension String.UnicodeScalarView { /// is trivially identical to `other`. /// /// - Complexity: O(1) - @available(SwiftStdlib 6.3, *) + @available(StdlibDeploymentTarget 6.4, *) public func isTriviallyIdentical(to other: Self) -> Bool { self._guts.isTriviallyIdentical(to: other._guts) } diff --git a/stdlib/public/core/Substring.swift b/stdlib/public/core/Substring.swift index 62e499a2c55ac..1086154212f8a 100644 --- a/stdlib/public/core/Substring.swift +++ b/stdlib/public/core/Substring.swift @@ -887,7 +887,7 @@ extension Substring.UTF8View { /// is trivially identical to `other`. /// /// - Complexity: O(1) - @available(SwiftStdlib 6.3, *) + @available(StdlibDeploymentTarget 6.4, *) public func isTriviallyIdentical(to other: Self) -> Bool { self._base.isTriviallyIdentical(to: other._base) && self._bounds == other._bounds @@ -1054,7 +1054,7 @@ extension Substring.UTF16View { /// is trivially identical to `other`. /// /// - Complexity: O(1) - @available(SwiftStdlib 6.3, *) + @available(StdlibDeploymentTarget 6.4, *) public func isTriviallyIdentical(to other: Self) -> Bool { self._base.isTriviallyIdentical(to: other._base) && self._bounds == other._bounds @@ -1310,7 +1310,7 @@ extension Substring.UnicodeScalarView { /// is trivially identical to `other`. /// /// - Complexity: O(1) - @available(SwiftStdlib 6.3, *) + @available(StdlibDeploymentTarget 6.4, *) public func isTriviallyIdentical(to other: Self) -> Bool { self._slice._base.isTriviallyIdentical(to: other._slice._base) && self._bounds == other._bounds diff --git a/test/stdlib/StringAPI.swift b/test/stdlib/StringAPI.swift index fc6af2d85f814..835cf70758b78 100644 --- a/test/stdlib/StringAPI.swift +++ b/test/stdlib/StringAPI.swift @@ -524,10 +524,10 @@ StringTests.test("_isIdentical(to:)") { StringTests.test("String.UnicodeScalarView.isTriviallyIdentical(to:)") .skip(.custom({ - if #available(SwiftStdlib 6.3, *) { false } else { true } - }, reason: "Requires Swift stdlib 6.3")) + if #available(StdlibDeploymentTarget 6.4, *) { false } else { true } + }, reason: "Requires Swift stdlib 6.4")) .code { - guard #available(SwiftStdlib 6.3, *) else { return } + guard #available(StdlibDeploymentTarget 6.4, *) else { return } let a = "Hello".unicodeScalars let b = "Hello".unicodeScalars @@ -542,10 +542,10 @@ StringTests.test("String.UnicodeScalarView.isTriviallyIdentical(to:)") } StringTests.test("String.UTF8View.isTriviallyIdentical(to:)") .skip(.custom({ - if #available(SwiftStdlib 6.3, *) { false } else { true } - }, reason: "Requires Swift stdlib 6.3")) + if #available(StdlibDeploymentTarget 6.4, *) { false } else { true } + }, reason: "Requires Swift stdlib 6.4")) .code { - guard #available(SwiftStdlib 6.3, *) else { return } + guard #available(StdlibDeploymentTarget 6.4, *) else { return } let a = "Hello".utf8 let b = "Hello".utf8 @@ -561,10 +561,10 @@ StringTests.test("String.UTF8View.isTriviallyIdentical(to:)") } StringTests.test("String.UTF16View.isTriviallyIdentical(to:)") .skip(.custom({ - if #available(SwiftStdlib 6.3, *) { false } else { true } - }, reason: "Requires Swift stdlib 6.3")) + if #available(StdlibDeploymentTarget 6.4, *) { false } else { true } + }, reason: "Requires Swift stdlib 6.4")) .code { - guard #available(SwiftStdlib 6.3, *) else { return } + guard #available(StdlibDeploymentTarget 6.4, *) else { return } let a = "Hello".utf16 let b = "Hello".utf16 @@ -581,10 +581,10 @@ StringTests.test("String.UTF16View.isTriviallyIdentical(to:)") StringTests.test("Substring.UnicodeScalarView.isTriviallyIdentical(to:)") .skip(.custom({ - if #available(SwiftStdlib 6.3, *) { false } else { true } - }, reason: "Requires Swift stdlib 6.3")) + if #available(StdlibDeploymentTarget 6.4, *) { false } else { true } + }, reason: "Requires Swift stdlib 6.4")) .code { - guard #available(SwiftStdlib 6.3, *) else { return } + guard #available(StdlibDeploymentTarget 6.4, *) else { return } let base1 = "Test String" let a = base1[base1.index(base1.startIndex, offsetBy: 5).. Date: Mon, 8 Dec 2025 14:34:59 -0800 Subject: [PATCH 13/16] [stdlib] String, Substring: Use new _StringGuts helper --- stdlib/public/core/String.swift | 2 +- stdlib/public/core/Substring.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/public/core/String.swift b/stdlib/public/core/String.swift index bbcc33326e16e..7bf955d79e0e7 100644 --- a/stdlib/public/core/String.swift +++ b/stdlib/public/core/String.swift @@ -1147,6 +1147,6 @@ extension String { /// - Complexity: O(1) @available(StdlibDeploymentTarget 6.4, *) public func isTriviallyIdentical(to other: Self) -> Bool { - self._guts.rawBits == other._guts.rawBits + self._guts.isTriviallyIdentical(to: other._guts) } } diff --git a/stdlib/public/core/Substring.swift b/stdlib/public/core/Substring.swift index 1086154212f8a..c117c7110f7c2 100644 --- a/stdlib/public/core/Substring.swift +++ b/stdlib/public/core/Substring.swift @@ -1457,7 +1457,7 @@ extension Substring { /// - Complexity: O(1) @available(StdlibDeploymentTarget 6.4, *) public func isTriviallyIdentical(to other: Self) -> Bool { - self._wholeGuts.rawBits == other._wholeGuts.rawBits && + self._wholeGuts.isTriviallyIdentical(to: other._wholeGuts) && self._offsetRange == other._offsetRange } } From a3650e79e65bfe095df2e1a27e543640d9ae2d8d Mon Sep 17 00:00:00 2001 From: Karoy Lorentey Date: Mon, 8 Dec 2025 14:45:41 -0800 Subject: [PATCH 14/16] [test] Update tests, acknowledging new additions --- test/Interop/SwiftToCxx/stdlib/swift-stdlib-in-cxx.swift | 1 + test/abi/macOS/arm64/stdlib.swift | 6 ++++++ test/abi/macOS/x86_64/stdlib.swift | 6 ++++++ 3 files changed, 13 insertions(+) diff --git a/test/Interop/SwiftToCxx/stdlib/swift-stdlib-in-cxx.swift b/test/Interop/SwiftToCxx/stdlib/swift-stdlib-in-cxx.swift index e3455dfdf2efb..0812d31515b7b 100644 --- a/test/Interop/SwiftToCxx/stdlib/swift-stdlib-in-cxx.swift +++ b/test/Interop/SwiftToCxx/stdlib/swift-stdlib-in-cxx.swift @@ -124,6 +124,7 @@ // CHECK: SWIFT_INLINE_THUNK uint8_t operator [](const __StringNested::Index& i) const SWIFT_SYMBOL({{.*}}); // CHECK: SWIFT_INLINE_THUNK String getDescription() const SWIFT_SYMBOL({{.*}}); // CHECK: SWIFT_INLINE_THUNK swift::Int getCount() const SWIFT_SYMBOL({{.*}}); +// CHECK: SWIFT_INLINE_THUNK bool isTriviallyIdenticalTo(const __StringNested::UTF8View& other) const SWIFT_SYMBOL({{.*}}) {{.*}}; // CHECK-NEXT: private: // CHECK: class AnyKeyPath { } SWIFT_UNAVAILABLE_MSG("class 'AnyKeyPath' is not yet exposed to C++"); diff --git a/test/abi/macOS/arm64/stdlib.swift b/test/abi/macOS/arm64/stdlib.swift index 15b990049ec0a..ea687ad8139e3 100644 --- a/test/abi/macOS/arm64/stdlib.swift +++ b/test/abi/macOS/arm64/stdlib.swift @@ -1165,3 +1165,9 @@ Added: _$ss13EncodingErrorOs28CustomDebugStringConvertiblesWP // SE-0494 Add isTriviallyIdentical(to:) Methods to String and Substring Added: _$sSS20isTriviallyIdentical2toSbSS_tF Added: _$sSs20isTriviallyIdentical2toSbSs_tF +Added: _$sSS17UnicodeScalarViewV20isTriviallyIdentical2toSbAB_tF +Added: _$sSS8UTF8ViewV20isTriviallyIdentical2toSbAB_tF +Added: _$sSS9UTF16ViewV20isTriviallyIdentical2toSbAB_tF +Added: _$sSs17UnicodeScalarViewV20isTriviallyIdentical2toSbAB_tF +Added: _$sSs8UTF8ViewV20isTriviallyIdentical2toSbAB_tF +Added: _$sSs9UTF16ViewV20isTriviallyIdentical2toSbAB_tF diff --git a/test/abi/macOS/x86_64/stdlib.swift b/test/abi/macOS/x86_64/stdlib.swift index 09fa99fb77ff2..9b7cf5e72df07 100644 --- a/test/abi/macOS/x86_64/stdlib.swift +++ b/test/abi/macOS/x86_64/stdlib.swift @@ -1160,3 +1160,9 @@ Added: _$ss13EncodingErrorOs28CustomDebugStringConvertiblesWP // SE-0494 Add isTriviallyIdentical(to:) Methods to String and Substring Added: _$sSS20isTriviallyIdentical2toSbSS_tF Added: _$sSs20isTriviallyIdentical2toSbSs_tF +Added: _$sSS17UnicodeScalarViewV20isTriviallyIdentical2toSbAB_tF +Added: _$sSS8UTF8ViewV20isTriviallyIdentical2toSbAB_tF +Added: _$sSS9UTF16ViewV20isTriviallyIdentical2toSbAB_tF +Added: _$sSs17UnicodeScalarViewV20isTriviallyIdentical2toSbAB_tF +Added: _$sSs8UTF8ViewV20isTriviallyIdentical2toSbAB_tF +Added: _$sSs9UTF16ViewV20isTriviallyIdentical2toSbAB_tF From 8c9f084d8624192c6fa4e15d5a2352101364fc50 Mon Sep 17 00:00:00 2001 From: Rick van Voorden Date: Mon, 8 Dec 2025 17:35:19 -0800 Subject: [PATCH 15/16] substring test nits --- benchmark/single-source/SubstringTest.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmark/single-source/SubstringTest.swift b/benchmark/single-source/SubstringTest.swift index 7db0000393d51..71ef0c774f26f 100644 --- a/benchmark/single-source/SubstringTest.swift +++ b/benchmark/single-source/SubstringTest.swift @@ -12,7 +12,7 @@ import TestsUtils -public let benchmarks: [BenchmarkInfo] = [ +public let benchmarks = [ BenchmarkInfo(name: "EqualStringSubstring", runFunction: run_EqualStringSubstring, tags: [.validation, .api, .String]), BenchmarkInfo(name: "EqualSubstringString", runFunction: run_EqualSubstringString, tags: [.validation, .api, .String]), BenchmarkInfo(name: "EqualSubstringSubstring", runFunction: run_EqualSubstringSubstring, tags: [.validation, .api, .String]), @@ -24,7 +24,7 @@ public let benchmarks: [BenchmarkInfo] = [ BenchmarkInfo(name: "StringFromLongWholeSubstring", runFunction: run_StringFromLongWholeSubstring, tags: [.validation, .api, .String]), BenchmarkInfo(name: "StringFromLongWholeSubstringGeneric", runFunction: run_StringFromLongWholeSubstringGeneric, tags: [.validation, .api, .String]), BenchmarkInfo(name: "SubstringComparable", runFunction: run_SubstringComparable, tags: [.validation, .api, .String], - setUpFunction: { blackHole(_comparison) }), + setUpFunction: { blackHole(_comparison) }), BenchmarkInfo(name: "SubstringEqualString", runFunction: run_SubstringEqualString, tags: [.validation, .api, .String]), BenchmarkInfo(name: "SubstringEquatable", runFunction: run_SubstringEquatable, tags: [.validation, .api, .String]), BenchmarkInfo(name: "SubstringFromLongString2", runFunction: run_SubstringFromLongString, tags: [.validation, .api, .String]), From 0ab8884657510173d37dfa16964eeaf5bbb368cc Mon Sep 17 00:00:00 2001 From: Rick van Voorden Date: Tue, 9 Dec 2025 09:35:34 -0800 Subject: [PATCH 16/16] add 6.4 symbols to abi tests --- test/abi/macOS/arm64/stdlib.swift | 1 + test/abi/macOS/x86_64/stdlib.swift | 1 + 2 files changed, 2 insertions(+) diff --git a/test/abi/macOS/arm64/stdlib.swift b/test/abi/macOS/arm64/stdlib.swift index ea687ad8139e3..8c4e44927e5b4 100644 --- a/test/abi/macOS/arm64/stdlib.swift +++ b/test/abi/macOS/arm64/stdlib.swift @@ -771,6 +771,7 @@ Added: _$ss7UnicodeO5UTF32O27encodedReplacementCharacters15CollectionOfOneVys6UI Added: _$sSo19_SwiftStdlibVersionasE6v6_1_0ABvpZMV Added: _$sSo19_SwiftStdlibVersionasE6v6_2_0ABvpZMV Added: _$sSo19_SwiftStdlibVersionasE6v6_3_0ABvpZMV +Added: _$sSo19_SwiftStdlibVersionasE6v6_4_0ABvpZMV Added: _$sSBsE5radixSivpZMV Added: _$sSFsE8ulpOfOnexvpZMV Added: _$sSUsE8isSignedSbvpZMV diff --git a/test/abi/macOS/x86_64/stdlib.swift b/test/abi/macOS/x86_64/stdlib.swift index 9b7cf5e72df07..766f0924a606f 100644 --- a/test/abi/macOS/x86_64/stdlib.swift +++ b/test/abi/macOS/x86_64/stdlib.swift @@ -752,6 +752,7 @@ Added: _$ss8SIMDMaskVss6SIMD64Vys5Int64VGRszrlE7allTrueAByAGGvpZMV Added: _$sSo19_SwiftStdlibVersionasE6v6_1_0ABvpZMV Added: _$sSo19_SwiftStdlibVersionasE6v6_2_0ABvpZMV Added: _$sSo19_SwiftStdlibVersionasE6v6_3_0ABvpZMV +Added: _$sSo19_SwiftStdlibVersionasE6v6_4_0ABvpZMV Added: _$ss7Float80V12signalingNaNABvpZMV Added: _$ss7Float80V13_exponentBiasSuvpZMV Added: _$ss7Float80V13_quietNaNMasks6UInt64VvpZMV