Skip to content

Commit f8fed23

Browse files
authored
Merge pull request #73990 from kavon/changelog-and-more-tests
NFC: Update Changelog for more porposals, and add more testing.
2 parents 9accd0d + c891aeb commit f8fed23

File tree

5 files changed

+310
-42
lines changed

5 files changed

+310
-42
lines changed

CHANGELOG.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,26 @@
55
66
## Swift 6.0
77

8+
* [SE-0432][]:
9+
Noncopyable enums can be pattern-matched with switches without consuming the
10+
value you switch over:
11+
12+
```swift
13+
enum Lunch: ~Copyable {
14+
case soup
15+
case salad
16+
case sandwich
17+
}
18+
19+
func isSoup(_ lunch: borrowing Lunch) -> Bool {
20+
switch lunch {
21+
case .soup: true
22+
default: false
23+
}
24+
}
25+
```
26+
27+
828
* [SE-0428][]:
929
Distributed actors now have the ability to support complete split server /
1030
client systems, thanks to the new `@Resolvable` macro and runtime changes.
@@ -238,6 +258,24 @@ And the module structure to support such applications looks like this:
238258
}
239259
```
240260

261+
* [SE-0429][]:
262+
The noncopyable fields of certain types can now be consumed individually:
263+
264+
```swift
265+
struct Token: ~Copyable {}
266+
267+
struct Authentication: ~Copyable {
268+
let id: Token
269+
let name: String
270+
271+
mutating func exchange(_ new: consuming Token) -> Token {
272+
let old = self.id // <- partial consumption of 'self'
273+
self = .init(id: new, name: self.name)
274+
return old
275+
}
276+
}
277+
```
278+
241279
* [SE-0427][]:
242280
You can now suppress `Copyable` on protocols, generic parameters,
243281
and existentials:
@@ -10517,6 +10555,8 @@ using the `.dynamicType` member to retrieve the type of an expression should mig
1051710555
[SE-0411]: https://github.com/apple/swift-evolution/blob/main/proposals/0411-isolated-default-values.md
1051810556
[SE-0412]: https://github.com/apple/swift-evolution/blob/main/proposals/0412-strict-concurrency-for-global-variables.md
1051910557
[SE-0413]: https://github.com/apple/swift-evolution/blob/main/proposals/0413-typed-throws.md
10558+
[SE-0429]: https://github.com/apple/swift-evolution/blob/main/proposals/0429-partial-consumption.md
10559+
[SE-0432]: https://github.com/apple/swift-evolution/blob/main/proposals/0432-noncopyable-switch.md
1052010560
[SE-0414]: https://github.com/apple/swift-evolution/blob/main/proposals/0414-region-based-isolation.md
1052110561
[SE-0424]: https://github.com/apple/swift-evolution/blob/main/proposals/0424-custom-isolation-checking-for-serialexecutor.md
1052210562
[SE-0428]: https://github.com/apple/swift-evolution/blob/main/proposals/0428-resolve-distributed-actor-protocols.md

test/Generics/inverse_generics.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,3 +500,11 @@ struct TestResolution3 {
500500
var dictNC: [String: NC] = [:] // expected-error {{type 'NC' does not conform to protocol 'Copyable'}}
501501
var exampleNC: Example<NC> = Example() // expected-error {{type 'NC' does not conform to protocol 'Copyable'}}
502502
}
503+
504+
public struct Box<Wrapped: ~Copyable>: ~Copyable {}
505+
// Box is never copyable, so we can't support this conditional conformance.
506+
public enum List<Element: ~Copyable>: ~Copyable {
507+
case cons(Element, Box<List<Element>>) // expected-error {{associated value 'cons' of 'Copyable'-conforming generic enum 'List' has non-Copyable type '(Element, Box<List<Element>>)'}}
508+
case empty
509+
}
510+
extension List: Copyable where Element: Copyable {}

test/Inputs/Swiftskell.swift

Lines changed: 190 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ public protocol Show: ~Copyable {
88
borrowing func show() -> String
99
}
1010

11+
extension CustomStringConvertible {
12+
public func show() -> String { return description }
13+
}
14+
extension Int: Show {}
15+
1116
public func print(_ s: borrowing some Show & ~Copyable) {
1217
print(s.show())
1318
}
@@ -50,37 +55,47 @@ public protocol Generator: ~Copyable {
5055
func next() -> Maybe<Element>
5156
}
5257

58+
/// Eager assertion function, to avoid autoclosures.
59+
public func check(_ result: Bool, _ string: String? = nil,
60+
_ file: String = #file, _ line: Int = #line) {
61+
if result { return }
62+
var msg = "assertion failure (\(file):\(line))"
63+
if let extra = string {
64+
msg += ":\t" + extra
65+
}
66+
fatalError(msg)
67+
}
68+
5369
// MARK: Tuples
5470
public enum Pair<L: ~Copyable, R: ~Copyable>: ~Copyable {
55-
case elms(L, R)
71+
case pair(L, R)
5672
}
73+
extension Pair: Copyable where L: Copyable, R: Copyable {}
5774

5875
/// MARK: Data.Maybe
59-
60-
public enum Maybe<Value: ~Copyable>: ~Copyable {
61-
case just(Value)
76+
public enum Maybe<Wrapped: ~Copyable>: ~Copyable {
77+
case just(Wrapped)
6278
case nothing
6379
}
64-
6580
extension Maybe: Copyable {}
6681

67-
extension Maybe: Show where Value: Show & ~Copyable {
82+
extension Maybe: Show where Wrapped: Show & ~Copyable {
6883
public borrowing func show() -> String {
6984
switch self {
70-
case let .just(borrowing elm):
85+
case let .just(elm):
7186
return elm.show()
7287
case .nothing:
7388
return "<nothing>"
7489
}
7590
}
7691
}
7792

78-
extension Maybe: Eq where Value: Eq, Value: ~Copyable {
93+
extension Maybe: Eq where Wrapped: Eq, Wrapped: ~Copyable {
7994
public static func ==(_ a: borrowing Self, _ b: borrowing Self) -> Bool {
8095
switch a {
81-
case let .just(borrowing a1):
96+
case let .just(a1):
8297
switch b {
83-
case let .just(borrowing b1):
98+
case let .just(b1):
8499
return a1 == b1
85100
case .nothing:
86101
return false
@@ -96,19 +111,6 @@ extension Maybe: Eq where Value: Eq, Value: ~Copyable {
96111
}
97112
}
98113

99-
100-
// FIXME: triggers crash!
101-
// @inlinable
102-
// public func fromMaybe<A: ~Copyable>(_ defaultVal: consuming A,
103-
// _ mayb: consuming Maybe<A>) -> A {
104-
// switch mayb {
105-
// case let .just(payload):
106-
// return payload
107-
// case .nothing:
108-
// return defaultVal
109-
// }
110-
// }
111-
112114
public func isJust<A: ~Copyable>(_ m: borrowing Maybe<A>) -> Bool {
113115
switch m {
114116
case .just:
@@ -127,3 +129,168 @@ public struct UnownedRef<Instance: AnyObject> {
127129
@usableFromInline
128130
internal unowned(unsafe) var _value: Instance
129131
}
132+
133+
/// Provides underlying support so that you can create recursive enums, because
134+
/// noncopyable enums do not yet support indirect cases.
135+
public struct Box<Wrapped: ~Copyable>: ~Copyable {
136+
private let _pointer: UnsafeMutablePointer<Wrapped>
137+
138+
init(_ wrapped: consuming Wrapped) {
139+
_pointer = .allocate(capacity: 1)
140+
_pointer.initialize(to: wrapped)
141+
}
142+
143+
deinit {
144+
_pointer.deinitialize(count: 1)
145+
_pointer.deallocate()
146+
}
147+
148+
consuming func take() -> Wrapped {
149+
let wrapped = _pointer.move()
150+
_pointer.deallocate()
151+
discard self
152+
return wrapped
153+
}
154+
155+
var borrow: Wrapped {
156+
_read { yield _pointer.pointee }
157+
}
158+
159+
consuming func map(_ transform: (consuming Wrapped) -> Wrapped) -> Self {
160+
_pointer.initialize(to: transform(_pointer.move()))
161+
return self
162+
}
163+
}
164+
165+
166+
/// MARK: Data.List
167+
///
168+
/// A singly-linked list
169+
public enum List<Element: ~Copyable>: ~Copyable {
170+
case cons(Element, Box<List<Element>>)
171+
case empty
172+
173+
public init(_ head: consuming Element,
174+
_ tail: consuming List<Element>) {
175+
self = .cons(head, Box(tail))
176+
}
177+
178+
public init() { self = .empty }
179+
}
180+
181+
/// Pure Iteration
182+
extension List where Element: ~Copyable {
183+
/// Performs forward iteration through the list, accumulating a result value.
184+
/// Returns f(xn,...,f(x2, f(x1, init))...), or `init` if the list is empty.
185+
public borrowing func foldl<Out>(
186+
init initial: consuming Out,
187+
_ f: (borrowing Element, consuming Out) -> Out) -> Out
188+
where Out: ~Copyable {
189+
func loop(_ acc: consuming Out, _ lst: borrowing Self) -> Out {
190+
switch lst {
191+
case .empty:
192+
return acc
193+
case let .cons(elm, tail):
194+
return loop(f(elm, acc), tail.borrow)
195+
}
196+
}
197+
return loop(initial, self)
198+
}
199+
200+
/// Performs reverse iteration through the list, accumulating a result value.
201+
/// Returns f(x1, f(x2,...,f(xn, init)...)) or `init` if the list is empty.
202+
public borrowing func foldr<Out>(
203+
init initial: consuming Out,
204+
_ f: (borrowing Element, consuming Out) -> Out) -> Out
205+
where Out: ~Copyable {
206+
switch self {
207+
case .empty:
208+
return initial
209+
case let .cons(elm, tail):
210+
return f(elm, tail.borrow.foldr(init: initial, f))
211+
}
212+
}
213+
214+
// Forward iteration without accumulating a result.
215+
public borrowing func forEach(_ f: (borrowing Element) -> Void) -> Void {
216+
switch self {
217+
case .empty: return
218+
case let .cons(elm, tail):
219+
f(elm)
220+
return tail.borrow.forEach(f)
221+
}
222+
}
223+
}
224+
225+
/// Initialization
226+
extension List where Element: ~Copyable {
227+
// Generates a list of elements [f(0), f(1), ..., f(n-1)] from left to right.
228+
// For n < 0, the empty list is created.
229+
public init(length n: Int, _ f: (Int) -> Element) {
230+
guard n > 0 else {
231+
self = .empty
232+
return
233+
}
234+
235+
let cur = n-1
236+
let elm = f(cur)
237+
self = List(elm, List(length: cur, f))
238+
}
239+
}
240+
241+
/// Basic utilities
242+
extension List where Element: ~Copyable {
243+
/// Is this list empty?
244+
///
245+
/// Complexity: O(1)
246+
public var isEmpty: Bool {
247+
borrowing get {
248+
switch self {
249+
case .empty: true
250+
case .cons(_, _): false
251+
}
252+
}
253+
}
254+
255+
/// How many elements are in this list?
256+
///
257+
/// Complexity: O(n)
258+
public borrowing func length() -> Int {
259+
return foldl(init: 0) { $1 + 1 }
260+
}
261+
262+
/// Pop the first element off the list, if present.
263+
///
264+
/// Complexity: O(1)
265+
public consuming func pop() -> Optional<Pair<Element, List<Element>>> {
266+
switch consume self {
267+
case .empty: .none
268+
case let .cons(elm, tail): .pair(elm, tail.take())
269+
}
270+
}
271+
272+
/// Push an element onto the front of the list.
273+
///
274+
/// Complexity: O(1)
275+
public consuming func push(_ newHead: consuming Element) -> List<Element> {
276+
return List(newHead, self)
277+
}
278+
279+
/// Produces a new list that is the reverse of this list.
280+
///
281+
/// Complexity: O(n)
282+
public consuming func reverse() -> List<Element> {
283+
var new = List<Element>()
284+
while case let .pair(head, tail) = pop() {
285+
new = new.push(head)
286+
self = tail
287+
}
288+
return new
289+
}
290+
}
291+
292+
extension List: Show where Element: Show & ~Copyable {
293+
public borrowing func show() -> String {
294+
return "[" + foldl(init: "]", { $0.show() + ", " + $1 })
295+
}
296+
}

0 commit comments

Comments
 (0)