Skip to content

Commit 62da7d5

Browse files
authored
Merge pull request #1325 from swiftlang/automerge/merge-main-2025-06-02_09-00
Merge `main` into `release/6.2`
2 parents 3df3260 + cb06baa commit 62da7d5

File tree

19 files changed

+314
-65
lines changed

19 files changed

+314
-65
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
name: Bug report
3+
about: Create a report to help us improve
4+
title: ''
5+
labels: bug
6+
assignees: ''
7+
8+
---
9+
10+
**Describe the bug**
11+
A clear and concise description of what the bug is.
12+
13+
**To Reproduce**
14+
Sample code to reproduce the behavior.
15+
16+
```swift
17+
Sample code goes here
18+
```
19+
20+
**Expected behavior**
21+
A clear and concise description of what you expected to happen.
22+
23+
**Configuration (please complete the following information):**
24+
- Swift Version: [e.g. Swift 6.1, `main` branch under development, etc]
25+
- OS: [e.g. iOS, macOS, Linux Distribution, Windows, Android]
26+
- OS Version: [e.g. iOS 18]
27+
28+
**Regression information:**
29+
If applicable, please list older versions where this issue did not occur.
30+
31+
**Additional context**
32+
Add any other context about the problem here.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
name: Feature request
3+
about: Request a new API or other enhancement
4+
title: ''
5+
labels: enhancement
6+
assignees: ''
7+
8+
---
9+
10+
**Is your feature request related to a problem? Please describe.**
11+
A clear and concise description of what the problem is.
12+
13+
**Describe the solution you'd like**
14+
A clear and concise description of what you want to happen.
15+
16+
**Additional context**
17+
Add any other context about the feature request here.

.github/workflows/pull_request.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ name: Pull request
33
on:
44
pull_request:
55
types: [opened, reopened, synchronize]
6+
paths-ignore:
7+
- '*.md'
8+
- 'Proposals/**'
69

710
jobs:
811
tests:

Benchmarks/Benchmarks/Essentials/BenchmarkEssentials.swift

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,91 @@ let benchmarks = {
3434
assert(u1 != u2)
3535
}
3636
}
37+
38+
// MARK: Data
39+
40+
func createSomeData(_ length: Int) -> Data {
41+
var d = Data(repeating: 42, count: length)
42+
// Set a byte to be another value just so we know we have a unique pointer to the backing
43+
// For maximum inefficiency in the not equal case, set the last byte
44+
d[length - 1] = UInt8.random(in: UInt8.min..<UInt8.max)
45+
return d
46+
}
47+
48+
/// A box `Data`. Intentionally turns the value type into a reference, so we can make a promise that the inner value is not copied due to mutation during a test of insertion or replacing.
49+
class TwoDatasBox {
50+
var d1: Data
51+
var d2: Data
52+
53+
init(d1: Data, d2: Data) {
54+
self.d1 = d1
55+
self.d2 = d2
56+
}
57+
}
58+
59+
// MARK: -
60+
61+
Benchmark("DataEqualEmpty", closure: { benchmark, box in
62+
blackHole(box.d1 == box.d2)
63+
}, setup: { () -> TwoDatasBox in
64+
let d1 = Data()
65+
let d2 = d1
66+
let box = TwoDatasBox(d1: d1, d2: d2)
67+
return box
68+
})
69+
70+
Benchmark("DataEqualInline", closure: { benchmark, box in
71+
blackHole(box.d1 == box.d2)
72+
}, setup: { () -> TwoDatasBox in
73+
let d1 = createSomeData(12) // Less than size of InlineData.Buffer
74+
let d2 = d1
75+
let box = TwoDatasBox(d1: d1, d2: d2)
76+
return box
77+
})
78+
79+
Benchmark("DataNotEqualInline", closure: { benchmark, box in
80+
blackHole(box.d1 != box.d2)
81+
}, setup: { () -> TwoDatasBox in
82+
let d1 = createSomeData(12) // Less than size of InlineData.Buffer
83+
let d2 = createSomeData(12)
84+
let box = TwoDatasBox(d1: d1, d2: d2)
85+
return box
86+
})
87+
88+
Benchmark("DataEqualLarge", closure: { benchmark, box in
89+
blackHole(box.d1 == box.d2)
90+
}, setup: { () -> TwoDatasBox in
91+
let d1 = createSomeData(1024 * 8)
92+
let d2 = d1
93+
let box = TwoDatasBox(d1: d1, d2: d2)
94+
return box
95+
})
96+
97+
Benchmark("DataNotEqualLarge", closure: { benchmark, box in
98+
blackHole(box.d1 != box.d2)
99+
}, setup: { () -> TwoDatasBox in
100+
let d1 = createSomeData(1024 * 8)
101+
let d2 = createSomeData(1024 * 8)
102+
let box = TwoDatasBox(d1: d1, d2: d2)
103+
return box
104+
})
105+
106+
Benchmark("DataEqualReallyLarge", closure: { benchmark, box in
107+
blackHole(box.d1 == box.d2)
108+
}, setup: { () -> TwoDatasBox in
109+
let d1 = createSomeData(1024 * 1024 * 8)
110+
let d2 = d1
111+
let box = TwoDatasBox(d1: d1, d2: d2)
112+
return box
113+
})
114+
115+
Benchmark("DataNotEqualReallyLarge", closure: { benchmark, box in
116+
blackHole(box.d1 != box.d2)
117+
}, setup: { () -> TwoDatasBox in
118+
let d1 = createSomeData(1024 * 1024 * 8)
119+
let d2 = createSomeData(1024 * 1024 * 8)
120+
let box = TwoDatasBox(d1: d1, d2: d2)
121+
return box
122+
})
123+
37124
}

Evolution.md

Lines changed: 4 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ A group of core contributors and stakeholders form the _Foundation Workgroup_, w
99
*This section outlines the general process for features with a larger scope. For minor API proposals, please refer to the [Abbreviated review for minor proposals](#abbreviated-review-for-minor-proposals) section.*
1010

1111
* **Consider the goal**: Before proposing a change, please consider how your idea fits into the goals and themes for the upcoming release.
12-
* **Socialize the idea**: Propose a rough sketch of the idea in the "pitches" section of the Swift forums, the problems it solves, what the solution looks like, etc., to gauge interest from the community.
12+
* **Socialize the idea**: Propose a rough sketch of the idea on the [Swift forums - Foundation project](https://forums.swift.org/c/related-projects/foundation/99), the problems it solves, what the solution looks like, etc., to gauge interest from the community. Please feel free to include "[Pitch]" in the title.
1313
* **Develop the proposal**: Expand the rough sketch into a complete proposal, using the [proposal template](Proposals/0000-template.md), and continue to refine the proposal on the forums. Prototyping an implementation and its uses along with the proposal is required because it helps ensure both technical feasibility of the proposal as well as validating that the proposal solves the problems it is meant to solve.
14-
* **Request a review**: Initiate a pull request to the swift-foundation repository to indicate to the workgroup that you would like the proposal to be reviewed. When the proposal is sufficiently detailed and clear, and addresses feedback from earlier discussions of the idea, the pull request will be accepted. The proposal will be assigned a proposal number as well as a Foundation Workgroup member to manage the review.
14+
* **Request a review**: Initiate a pull request to the swift-foundation repository to indicate to the workgroup that you would like the proposal to be reviewed. When the proposal is sufficiently detailed and clear, and addresses feedback from earlier discussions of the idea, the pull request will be accepted. The proposal will be assigned a proposal number as well as a Foundation Workgroup member to manage the review. This marks as the start of the review.
1515
* **Address feedback**: In general, and especially during the review period, be responsive to questions and feedback about the proposal.
1616

1717
### The review process
@@ -22,7 +22,7 @@ The review process for a particular proposal begins when a member of the Foundat
2222

2323
The review manager will work with the proposal authors to schedule the review. Reviews usually last a single week, but can run longer for particularly large or complex proposals.
2424

25-
When the scheduled review period arrives, the review manager will post the proposal to the Swift forums with the proposal title. To avoid delays, it is important that the proposal authors be available to answer questions, address feedback, and clarify their intent during the review period.
25+
When the scheduled review period arrives, the review manager will post the proposal to the [Swift forums - Foundation Project](https://forums.swift.org/c/related-projects/foundation/99) with the proposal title. To avoid delays, it is important that the proposal authors be available to answer questions, address feedback, and clarify their intent during the review period.
2626

2727
After the review has completed, the Foundation Workgroup will make a decision on the proposal. The review manager is responsible for determining consensus among the Foundation Workgroup members, then reporting their decision to the proposal authors and forums. The review manager will update the proposal's state in the repository to reflect that decision.
2828

@@ -31,53 +31,7 @@ After the review has completed, the Foundation Workgroup will make a decision on
3131
Minor API enhancement ideas that have gained community interest through GitHub issues or forum threads may take a shorter review process. Examples include extending existing types with new functions or variables, or adding new `case` to `enum`. Instead of requiring both a pitch thread and a review, these changes can be proposed directly with a proposal document on a pitch thread. The workgroup has appointed an API champion (currently @itingliu) to oversee this process. Here's what you would do:
3232

3333
* **Develop the proposal**: Prepare the proposal using the [proposal template](Proposals/0000-template.md) with a prototype.
34-
* **Request an abbreviated review**: Initiate a pull request to the swift-foundation repository to indicate to the workgroup that you would like the proposal to be reviewed. Meanwhile, post the pull request on the "pitches" section of the Swift forums. Upon seeing the pitch on the forum, a workgroup member will be assigned to manage the review.
34+
* **Request an abbreviated review**: Initiate a pull request to the swift-foundation repository to indicate to the workgroup that you would like the proposal to be reviewed. Meanwhile, post the content on the [Swift forums - Foundation project](https://forums.swift.org/c/related-projects/foundation/99). Upon seeing the pitch on the forum, a workgroup member will be assigned to manage the review. The review manager will comment in the pitch post if the proposal is deemed suitable for abbreviated review, and communicate the next steps on the pitch post.
3535
* **Address feedback**: Be responsive to questions and feedback and continue to refine the proposal as needed.
3636

3737
At the end of the review period, the review manager will accept the proposal if there is a broad agreement among workgroup members and the community.
38-
39-
40-
### Appendix: Review Announcement Template
41-
42-
(Credit: This section is adapted from [Swift-Evolution's announcement template](https://github.com/apple/swift-evolution/blob/main/process.md#review-announcement))
43-
44-
When a proposal enters review, a new topic will be posted to the [Foundation project of the Swift forums](https://forums.swift.org/c/related-projects/foundation/) using the following template.
45-
46-
<details>
47-
<summary> Template </summary>
48-
49-
---
50-
Hello Swift community,
51-
52-
The review of [\<\<PROPOSAL NAME>>]\(\<\<LINK TO PROPOSAL>>) begins now and runs through \<\<REVIEW END DATE>>
53-
54-
Reviews are an important part of the Swift-Foundation evolution process. All review feedback should be either on this forum thread or, if you would like to keep your feedback private, directly to me as the review manager by \<\<CONTACT METHOD>>. When contacting the review manager directly, please include proposal name in the subject line.
55-
56-
57-
##### Trying it out
58-
59-
If you'd like to try this proposal out, you can check out \<\<LINK TO IMPLEMENTATION>>.
60-
61-
##### What goes into a review?
62-
63-
The goal of the review process is to improve the proposal under review
64-
through constructive criticism and, eventually, determine the direction of
65-
Swift-Foundation. When writing your review, here are some questions you might want to
66-
answer in your review:
67-
68-
* What is your evaluation of the proposal?
69-
* Does this proposal fit well with the feel and direction of Swift-Foundation?
70-
* If you have used other languages or libraries with a similar
71-
feature, how do you feel that this proposal compares to those?
72-
* How much effort did you put into your review? A glance, a quick
73-
reading, or an in-depth study?
74-
75-
More information about Swift-Foundation review process is available at
76-
77-
> <https://github.com/apple/swift-foundation/blob/main/CONTRIBUTING.md>
78-
79-
Thank you,
80-
81-
-\<\<REVIEW MANAGER NAME>>
82-
83-
Review Manager

Sources/FoundationEssentials/Data/Data.swift

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2709,14 +2709,36 @@ public struct Data : Equatable, Hashable, RandomAccessCollection, MutableCollect
27092709
/// Returns `true` if the two `Data` arguments are equal.
27102710
@inlinable // This is @inlinable as emission into clients is safe -- the concept of equality on Data will not change.
27112711
public static func ==(d1 : Data, d2 : Data) -> Bool {
2712+
// See if both are empty
2713+
switch (d1._representation, d2._representation) {
2714+
case (.empty, .empty):
2715+
return true
2716+
default:
2717+
// Continue on to checks below
2718+
break
2719+
}
2720+
27122721
let length1 = d1.count
2713-
if length1 != d2.count {
2722+
let length2 = d2.count
2723+
2724+
// Unequal length data can never be equal
2725+
guard length1 == length2 else {
27142726
return false
27152727
}
2728+
27162729
if length1 > 0 {
27172730
return d1.withUnsafeBytes { (b1: UnsafeRawBufferPointer) in
27182731
return d2.withUnsafeBytes { (b2: UnsafeRawBufferPointer) in
2719-
return memcmp(b1.baseAddress!, b2.baseAddress!, b2.count) == 0
2732+
// If they have the same base address and same count, it is equal
2733+
let b1Address = b1.baseAddress!
2734+
let b2Address = b2.baseAddress!
2735+
2736+
guard b1Address != b2Address else {
2737+
return true
2738+
}
2739+
2740+
// Compare the contents
2741+
return memcmp(b1Address, b2Address, b2.count) == 0
27202742
}
27212743
}
27222744
}

Sources/FoundationEssentials/Locale/Locale+Language.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ extension Locale {
3838
if let languageCode = languageCode {
3939
result += languageCode._normalizedIdentifier
4040
}
41-
if let script = script {
41+
if let script = script, !script.identifier.isEmpty {
4242
result += "-"
4343
result += script._normalizedIdentifier
4444
}
45-
if let region = region {
45+
if let region = region, !region.identifier.isEmpty {
4646
result += "_"
4747
result += region._normalizedIdentifier
4848
}

Sources/FoundationInternationalization/Locale/Locale+Components_ICU.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,11 @@ extension Locale.Language {
525525
public var minimalIdentifier : String {
526526
let componentsIdentifier = components.identifier
527527

528+
guard !componentsIdentifier.isEmpty else {
529+
// Just return "". Nothing to reduce.
530+
return componentsIdentifier
531+
}
532+
528533
let localeIDWithLikelySubtags = _withFixedCharBuffer { buffer, size, status in
529534
return uloc_minimizeSubtags(componentsIdentifier, buffer, size, &status)
530535
}
@@ -543,6 +548,11 @@ extension Locale.Language {
543548
/// Returns a BCP-47 identifier that always includes the script: "zh-Hant-TW", "en-Latn-US"
544549
public var maximalIdentifier : String {
545550
let id = components.identifier
551+
guard !id.isEmpty else {
552+
// Just return "" instead of trying to fill it up
553+
return id
554+
}
555+
546556
let localeIDWithLikelySubtags = _withFixedCharBuffer { buffer, size, status in
547557
return uloc_addLikelySubtags(id, buffer, size, &status)
548558
}

Sources/FoundationInternationalization/Locale/Locale_ICU.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,8 +1209,8 @@ internal final class _LocaleICU: _LocaleProtocol, Sendable {
12091209
}
12101210
}
12111211

1212-
// Check prefs
1213-
if let firstWeekdayPref = prefs?.firstWeekday {
1212+
// Check prefs. The value doesn't matter here - we check it again in the `forceFirstWeekday` function, and it is immutable.
1213+
if prefs?.firstWeekday != nil {
12141214
let calendarId = calendarIdentifier
12151215
if let first = forceFirstWeekday(calendarId) {
12161216
state.firstDayOfWeek = first

Sources/FoundationInternationalization/Locale/Locale_ObjC.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,10 @@ internal class _NSSwiftLocale: _NSLocaleBridge, @unchecked Sendable {
308308
switch locale.temperatureUnit {
309309
case .celsius: return NSLocaleTemperatureUnitCelsius
310310
case .fahrenheit: return NSLocaleTemperatureUnitFahrenheit
311+
#if !FOUNDATION_FRAMEWORK
312+
// On non-framework builds, the enum is non-closed and `package` visibility, so we need a default
311313
default: return NSLocaleTemperatureUnitCelsius
314+
#endif
312315
}
313316
case .decimalSeparator: return self.decimalSeparator
314317
case .groupingSeparator: return self.groupingSeparator

0 commit comments

Comments
 (0)