@@ -65,21 +65,6 @@ expression:
65
65
of borrowing.)
66
66
- Otherwise, the baseline mode is * consuming* .
67
67
68
- While looking through the patterns:
69
-
70
- - if there is a ` borrowing ` binding subpattern (described below), then the
71
- ` switch ` behavior is at least * borrowing* .
72
- - if there is a ` var ` binding subpattern, and the subpattern is of
73
- a noncopyable type, then the ` switch ` behavior is * consuming* . If the
74
- subpattern is copyable, then ` var ` bindings do not affect the behavior
75
- of the ` switch ` , since the binding value can be copied if necessary to
76
- form the binding.
77
- - if there is an ` as T ` subpattern, and the type of the value being matched
78
- is noncopyable, then the ` switch ` behavior is * consuming* . If the value
79
- being matched is copyable, there is no effect on the behavior of the
80
- ` switch ` . This is because some forms of dynamic cast on noncopyable types
81
- may require consuming the input value.
82
-
83
68
For example, given the following copyable definition:
84
69
85
70
```
@@ -93,15 +78,8 @@ then the following patterns have ownership behavior as indicated below:
93
78
94
79
```
95
80
case let x: // copying
96
- case borrowing x: // borrowing
97
-
98
81
case .foo(let x): // copying
99
- case .foo(borrowing x): // borrowing
100
-
101
82
case .bar(let x, let y): // copying
102
- case .bar(borrowing x, let y): // borrowing
103
- case .bar(let x, borrowing y): // borrowing
104
- case .bar(borrowing x, borrowing y): // borrowing
105
83
```
106
84
107
85
And for a noncopyable enum definition:
@@ -122,26 +100,18 @@ var foo: NoncopyableEnum // stored variable
122
100
123
101
switch foo {
124
102
case let x: // borrowing
125
- case borrowing x: // borrowing
126
103
127
104
case .copyable(let x): // borrowing (because `x: Int` is copyable)
128
- case .copyable(borrowing x): // borrowing
129
105
130
106
case .noncopyable(let x): // borrowing
131
- case .noncopyable(borrowing x): // borrowing
132
107
}
133
108
134
109
func bar() -> NoncopyableEnum {...} // function returning a temporary
135
110
136
111
switch bar() {
137
112
case let x: // consuming
138
- case borrowing x: // borrowing
139
-
140
113
case .copyable(let x): // borrowing (because `x: Int` is copyable)
141
- case .copyable(borrowing x): // borrowing
142
-
143
114
case .noncopyable(let x): // consuming
144
- case .noncopyable(borrowing x): // borrowing
145
115
}
146
116
```
147
117
@@ -229,133 +199,12 @@ including casts that bridge or which wrap the value in an existential
229
199
container, need to consume or copy parts of the input value in order to form
230
200
the result. The cast can still be separated into a check whether the type
231
201
matches, using a borrowing access, followed by constructing the actual cast
232
- result by consuming if necessary. However, for this to be allowed, the
202
+ result by consuming if necessary. To do this, the switch would have already
203
+ be a consuming switch. But also, for a consuming ` as T ` pattern to work, the
233
204
subpattern ` p ` of the ` p as T ` pattern would need to be irrefutable, and the
234
205
pattern could not have an associated ` where ` clause, since we would be unable
235
206
to back out of the pattern match once a consuming cast is performed.
236
207
237
- ### ` borrowing ` bindings
238
-
239
- In order to explicitly declare a binding as ` borrowing ` ,
240
- we introduce a new ` borrowing ` binding modifier in patterns. A ` borrowing `
241
- binding references the matched part of the value as it currently exists in the
242
- value from the pattern match without copying it, instead putting the subject
243
- under a * borrowing access* in order to access the matched part. Like other
244
- borrow bindings, the borrowed value cannot be consumed or mutated.
245
-
246
- ```
247
- var x: MyNCEnum = ...
248
- switch x {
249
- case .foo(borrowing y):
250
- // `y` is now borrowed directly out of `x`. This means we can access it
251
- // borrowing operations:
252
- y.access()
253
-
254
- // and we can still access `x` with borrowing operations as well:
255
- x.doStuff()
256
-
257
- // However, we can't consume `y` or extend its lifetime beyond the borrow
258
- Task.detached {
259
- y.access() // error, can't capture borrow `y` in an escaping closure
260
- }
261
- y.close() // error, can't consume `y`
262
-
263
- // And we also can't consume or modify `x` while `y` is borrowed out of it
264
- x = .foo(Handle(value: 42)) // error, can't modify x while borrowed
265
- x.throwAway() // error, can't consume x while borrowed
266
- }
267
-
268
- // And now `x` was only borrowed by the `switch`, so we can continue using
269
- // it afterward
270
- x.doStuff()
271
- x.throwAway()
272
- x = .foo(Handle(value: 1738))
273
-
274
- // Even if we `consume x` in the switch subject, a `borrowing` binding cannot
275
- // be locally consumed.
276
- switch consume x {
277
- case .foo(borrowing y):
278
- y.access()
279
-
280
- x.doStuff()
281
-
282
- // Even though we consumed `x`, `y` is still only a borrow binding so
283
- // can't consume or extend its lifetime.
284
- Task.detached {
285
- y.access() // error, can't capture borrow `y` in an escaping closure
286
- }
287
- y.close() // error, can't consume `y`
288
- }
289
-
290
- ```
291
-
292
- ` borrowing ` bindings can also be formed when the subject of the pattern
293
- match and/or the subpattern have ` Copyable ` types. Like ` borrowing ` parameter
294
- bindings, a ` borrowing ` pattern binding is not implicitly copyable in the
295
- body of the ` case ` , but can be explicitly copied using the ` copy ` operator.
296
-
297
- ```
298
- var x: MyCopyableEnum = ...
299
-
300
- switch x {
301
- case .foo(borrowing y):
302
- // We can use `y` in borrowing ways.
303
-
304
- // But we can't implicitly extend its lifetime or perform consuming
305
- // operations on it, since those would need to copy
306
- var myString = "hello"
307
- myString.append(y) // error, consumes `y`
308
- Task.detached {
309
- print(y) // error, can't extend lifetime of borrow without copying
310
- }
311
-
312
- // Explicit copying makes it ok
313
- Task.detached {[y = copy y] in
314
- print(y)
315
- }
316
- myString.append(copy y)
317
-
318
- // `x` is still copyable, so we can update it independently without
319
- // disturbing `y`
320
- x.doStuff()
321
- x = MyEnum.foo("38")
322
-
323
- }
324
- ```
325
-
326
- To maintain source compatibility, ` borrowing ` is parsed as a contextual
327
- keyword only when it appears immediately before an identifier name. In
328
- other positions, it parses as a declaration reference as before, forming
329
- an enum case pattern or expression pattern depending on what the name
330
- ` borrowing ` refers to.
331
-
332
- ```
333
- switch y {
334
- case borrowing(x): // parses as an expression pattern
335
- ...
336
- case borrowing(let x): // parses as an enum case pattern binding `x` as a let
337
- ...
338
- case borrowing.foo(x): // parses as an expression pattern
339
- ...
340
- case borrowing.foo(let x): // parses as an enum case pattern binding `x` as a let
341
- ...
342
- case borrowing x: // parses as a pattern binding `x` as a borrow
343
- ...
344
- case borrowing(borrowing x) // parses as an enum case pattern binding `x` as a borrow
345
- ...
346
- }
347
- ```
348
-
349
- This does mean that, unlike ` let ` and ` var ` , ` borrowing ` cannot be applied
350
- over a compound pattern to mark all of the identifiers in the subpatterns
351
- as bindings.
352
-
353
- ```
354
- case borrowing .foo(x, y): // parses as `borrowing.foo(x, y)`, a method call expression pattern
355
-
356
- case borrowing (x, y): // parses as `borrowing(x, y)`, a function call expression pattern
357
- ```
358
-
359
208
### ` case ` conditions in ` if ` , ` while ` , ` for ` , and ` guard `
360
209
361
210
Patterns can also appear in ` if ` , ` while ` , ` for ` , and ` guard ` forms as part
@@ -446,11 +295,22 @@ temporary, as in:
446
295
let x: String? = "hello"
447
296
448
297
switch borrow x {
449
- case .some(borrowing y): // ensure y is bound from a borrow of x, no copies
298
+ case .some(let y): // ensure y is bound from a borrow of x, no copies
450
299
...
451
300
}
452
301
```
453
302
303
+ ### ` borrowing ` bindings in patterns
304
+
305
+ In the future, we want to support ` borrowing ` and ` inout ` local bindings
306
+ in functions and potentially even as fields in nonescapable types. It might
307
+ also be useful to specify explicitly ` borrowing ` bindings within patterns.
308
+ Although the default behavior for a ` let ` binding within a noncopyable
309
+ borrowing ` switch ` pattern is to borrow the matched value, an explicitly
310
+ ` borrowing ` binding could be used to indicate that a copyable binding should
311
+ have its local implicit copyability suppressed, like a ` borrowing ` parameter
312
+ binding.
313
+
454
314
## Alternatives considered
455
315
456
316
### Determining pattern match ownership wholly from patterns
0 commit comments