Skip to content

Commit 25c9a6a

Browse files
authored
Merge pull request #62855 from gottesmm/pr-9ca4f16fc6bbe7422d4aa05b732475052d170c76
[borrow-operator] Add initial support for applying _borrow to self when calling a method.
2 parents e5e9827 + ef98a3c commit 25c9a6a

File tree

2 files changed

+273
-6
lines changed

2 files changed

+273
-6
lines changed

lib/SILGen/SILGenApply.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2973,7 +2973,19 @@ ArgumentSource::findStorageReferenceExprForBorrowExpr(SILGenFunction &SGF) && {
29732973
if (!isExpr())
29742974
return nullptr;
29752975

2976-
auto argExpr = asKnownExpr();
2976+
// We support two patterns:
2977+
//
2978+
// (load_expr (borrow_expr))
2979+
// *or*
2980+
// (paren_expr (load_expr (borrow_expr)))
2981+
//
2982+
// The first happens if a borrow is used on a non-self argument. The second
2983+
// happens if we pass self as a borrow.
2984+
auto *argExpr = asKnownExpr();
2985+
2986+
if (auto *parenExpr = dyn_cast<ParenExpr>(argExpr))
2987+
argExpr = parenExpr->getSubExpr();
2988+
29772989
auto *li = dyn_cast<LoadExpr>(argExpr);
29782990
if (!li)
29792991
return nullptr;

test/SILGen/borrow_expr.swift

Lines changed: 260 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,58 @@
11
// RUN: %target-swift-frontend -enable-experimental-move-only -o - -emit-silgen %s | %FileCheck %s
22

3-
class Klass {
3+
final class Klass {
44
func useKlass() {}
5+
6+
func doSomething() {}
7+
func doSomething(_ k: Klass) {}
58
}
69

10+
func useKlass(_ k: Klass) {}
11+
712
struct Struct {
813
var k = Klass()
14+
15+
func doSomething() {}
16+
func doSomething(_ k: Klass) {}
17+
18+
var computedK: Klass { Klass() }
919
}
1020

11-
func useKlass(_ k: Klass) {}
21+
func useStruct(_ s: Struct) {}
22+
23+
/////////////////////////
24+
// Concrete Type Tests //
25+
/////////////////////////
1226

13-
// CHECK-LABEL: sil hidden [ossa] @$s11borrow_expr10simpleTestyyF : $@convention(thin) () -> () {
27+
// CHECK-LABEL: sil hidden [ossa] @$s11borrow_expr13simpleTestArgyyF : $@convention(thin) () -> () {
28+
// CHECK: [[ADDR:%.*]] = project_box
29+
//
30+
// First check without the borrow:
31+
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[ADDR]]
32+
// CHECK: [[VAL:%.*]] = load [copy] [[ACCESS]]
33+
// CHECK: end_access [[ACCESS]]
34+
// CHECK: [[FUNC:%.*]] = function_ref @$s11borrow_expr9useStructyyAA0D0VF : $@convention(thin) (@guaranteed Struct) -> ()
35+
// CHECK: apply [[FUNC]]([[VAL]])
36+
// CHECK: destroy_value [[VAL]]
37+
//
38+
// Now with the borrow:
39+
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[ADDR]]
40+
// CHECK: [[VAL:%.*]] = load_borrow [[ACCESS]]
41+
// CHECK: [[FUNC:%.*]] = function_ref @$s11borrow_expr9useStructyyAA0D0VF : $@convention(thin) (@guaranteed Struct) -> ()
42+
// CHECK: apply [[FUNC]]([[VAL]])
43+
// CHECK: end_borrow [[VAL]]
44+
// CHECK: end_access [[ACCESS]]
45+
// CHECK: } // end sil function '$s11borrow_expr13simpleTestArgyyF'
46+
func simpleTestArg() {
47+
var s = Struct()
48+
s = Struct()
49+
// Without borrow.
50+
useStruct(s)
51+
// With borrow.
52+
useStruct(_borrow s)
53+
}
54+
55+
// CHECK-LABEL: sil hidden [ossa] @$s11borrow_expr18simpleTestArgFieldyyF : $@convention(thin) () -> () {
1456
// CHECK: [[ADDR:%.*]] = project_box
1557
//
1658
// First check without the borrow:
@@ -30,12 +72,225 @@ func useKlass(_ k: Klass) {}
3072
// CHECK: apply [[FUNC]]([[VAL]])
3173
// CHECK: end_borrow [[VAL]]
3274
// CHECK: end_access [[ACCESS]]
33-
// CHECK: } // end sil function '$s11borrow_expr10simpleTestyyF'
34-
func simpleTest() {
75+
// CHECK: } // end sil function '$s11borrow_expr18simpleTestArgFieldyyF'
76+
func simpleTestArgField() {
3577
var s = Struct()
3678
s = Struct()
3779
// Without borrow.
3880
useKlass(s.k)
3981
// With borrow.
4082
useKlass(_borrow s.k)
4183
}
84+
85+
// CHECK-LABEL: sil hidden [ossa] @$s11borrow_expr14simpleTestSelfyyF : $@convention(thin) () -> () {
86+
// CHECK: [[ADDR:%.*]] = project_box
87+
//
88+
// First check without the borrow:
89+
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[ADDR]]
90+
// CHECK: [[VAL:%.*]] = load [copy] [[ACCESS]]
91+
// CHECK: end_access [[ACCESS]]
92+
// CHECK: [[FUNC:%.*]] = function_ref @$s11borrow_expr6StructV11doSomethingyyF : $@convention(method) (@guaranteed Struct) -> ()
93+
// CHECK: apply [[FUNC]]([[VAL]])
94+
// CHECK: destroy_value [[VAL]]
95+
//
96+
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[ADDR]]
97+
// CHECK: [[VAL:%.*]] = load [copy] [[ACCESS]]
98+
// CHECK: end_access [[ACCESS]]
99+
// CHECK: [[FUNC:%.*]] = function_ref @$s11borrow_expr6StructV11doSomethingyyAA5KlassCF : $@convention(method) (@guaranteed Klass, @guaranteed Struct) -> ()
100+
// CHECK: apply [[FUNC]]({{%.*}}, [[VAL]])
101+
// CHECK: destroy_value [[VAL]]
102+
//
103+
// Now with the borrow:
104+
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[ADDR]]
105+
// CHECK: [[VAL:%.*]] = load_borrow [[ACCESS]]
106+
// CHECK: [[FUNC:%.*]] = function_ref @$s11borrow_expr6StructV11doSomethingyyF : $@convention(method) (@guaranteed Struct) -> ()
107+
// CHECK: apply [[FUNC]]([[VAL]])
108+
// CHECK: end_borrow [[VAL]]
109+
// CHECK: end_access [[ACCESS]]
110+
//
111+
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[ADDR]]
112+
// CHECK: [[VAL:%.*]] = load_borrow [[ACCESS]]
113+
// CHECK: [[FUNC:%.*]] = function_ref @$s11borrow_expr6StructV11doSomethingyyAA5KlassCF : $@convention(method) (@guaranteed Klass, @guaranteed Struct) -> ()
114+
// CHECK: apply [[FUNC]]({{%.*}}, [[VAL]])
115+
// CHECK: end_borrow [[VAL]]
116+
// CHECK: end_access [[ACCESS]]
117+
//
118+
// CHECK: } // end sil function '$s11borrow_expr14simpleTestSelfyyF'
119+
func simpleTestSelf() {
120+
var s = Struct()
121+
s = Struct()
122+
// Without borrow.
123+
s.doSomething()
124+
s.doSomething(Klass())
125+
126+
// With borrow.
127+
(_borrow s).doSomething()
128+
(_borrow s).doSomething(Klass())
129+
}
130+
131+
// CHECK-LABEL: sil hidden [ossa] @$s11borrow_expr19simpleTestSelfFieldyyF : $@convention(thin) () -> () {
132+
// CHECK: [[ADDR:%.*]] = project_box
133+
//
134+
// First check without the borrow:
135+
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[ADDR]]
136+
// CHECK: [[GEP:%.*]] = struct_element_addr [[ACCESS]] : $*Struct, #Struct.k
137+
// CHECK: [[VAL:%.*]] = load [copy] [[GEP]]
138+
// CHECK: end_access [[ACCESS]]
139+
// CHECK: [[FUNC:%.*]] = function_ref @$s11borrow_expr5KlassC11doSomethingyyF : $@convention(method) (@guaranteed Klass) -> ()
140+
// CHECK: apply [[FUNC]]([[VAL]])
141+
// CHECK: destroy_value [[VAL]]
142+
//
143+
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[ADDR]]
144+
// CHECK: [[GEP:%.*]] = struct_element_addr [[ACCESS]] : $*Struct, #Struct.k
145+
// CHECK: [[VAL:%.*]] = load [copy] [[GEP]]
146+
// CHECK: end_access [[ACCESS]]
147+
// CHECK: [[FUNC:%.*]] = function_ref @$s11borrow_expr5KlassC11doSomethingyyACF : $@convention(method) (@guaranteed Klass, @guaranteed Klass) -> ()
148+
// CHECK: apply [[FUNC]]({{%.*}}, [[VAL]])
149+
// CHECK: destroy_value [[VAL]]
150+
//
151+
// Now with the borrow:
152+
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[ADDR]]
153+
// CHECK: [[GEP:%.*]] = struct_element_addr [[ACCESS]] : $*Struct, #Struct.k
154+
// CHECK: [[VAL:%.*]] = load_borrow [[GEP]]
155+
// CHECK: [[FUNC:%.*]] = function_ref @$s11borrow_expr5KlassC11doSomethingyyF : $@convention(method) (@guaranteed Klass) -> (
156+
// CHECK: apply [[FUNC]]([[VAL]])
157+
// CHECK: end_borrow [[VAL]]
158+
// CHECK: end_access [[ACCESS]]
159+
//
160+
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[ADDR]]
161+
// CHECK: [[GEP:%.*]] = struct_element_addr [[ACCESS]] : $*Struct, #Struct.k
162+
// CHECK: [[VAL:%.*]] = load_borrow [[GEP]]
163+
// CHECK: [[FUNC:%.*]] = function_ref @$s11borrow_expr5KlassC11doSomethingyyACF : $@convention(method) (@guaranteed Klass, @guaranteed Klass) -> ()
164+
// CHECK: apply [[FUNC]]({{%.*}}, [[VAL]])
165+
// CHECK: end_borrow [[VAL]]
166+
// CHECK: end_access [[ACCESS]]
167+
//
168+
// CHECK: } // end sil function '$s11borrow_expr19simpleTestSelfFieldyyF'
169+
func simpleTestSelfField() {
170+
var s = Struct()
171+
s = Struct()
172+
// Without borrow.
173+
s.k.doSomething()
174+
s.k.doSomething(Klass())
175+
176+
// With borrow.
177+
(_borrow s.k).doSomething()
178+
(_borrow s.k).doSomething(Klass())
179+
}
180+
181+
////////////////////////
182+
// Address Only Tests //
183+
////////////////////////
184+
185+
protocol Q {
186+
}
187+
188+
protocol P {
189+
var q: Q { get /*_read*/ }
190+
func doSomething()
191+
func doSomething(_ k: Klass)
192+
}
193+
194+
func usePExistential(_ p: P) {}
195+
func usePGeneric<T : P>(_ p: T) {}
196+
func useQExistential<T : Q>(_ q: T) {}
197+
func useQGeneric<T : Q>(_ q: T) {}
198+
199+
//--------------------------------------------------------------------------------
200+
// Generics
201+
//
202+
203+
// CHECK-LABEL: sil hidden [ossa] @$s11borrow_expr20simpleTestGenericArgyyxAA1PRzlF : $@convention(thin) <T where T : P> (@in_guaranteed T) -> () {
204+
// CHECK: [[ADDR:%.*]] = project_box
205+
//
206+
// First without borrow.
207+
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[ADDR]]
208+
// CHECK: [[STACK:%.*]] = alloc_stack $T
209+
// CHECK: copy_addr [[ACCESS]] to [init] [[STACK]]
210+
// CHECK: end_access [[ACCESS]]
211+
// CHECK: [[FUNC:%.*]] = function_ref @$s11borrow_expr11usePGenericyyxAA1PRzlF : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
212+
// CHECK: apply [[FUNC]]<T>([[STACK]])
213+
// CHECK: destroy_addr [[STACK]]
214+
// CHECK: dealloc_stack [[STACK]]
215+
//
216+
// Now with borrow
217+
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[ADDR]]
218+
// CHECK: [[FUNC:%.*]] = function_ref @$s11borrow_expr11usePGenericyyxAA1PRzlF : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
219+
// CHECK: apply [[FUNC]]<T>([[ACCESS]])
220+
// CHECK: end_access [[ACCESS]]
221+
// CHECK: } // end sil function '$s11borrow_expr20simpleTestGenericArgyyxAA1PRzlF'
222+
func simpleTestGenericArg<T : P>(_ pArg: T) {
223+
var p = pArg
224+
p = pArg
225+
226+
// Without borrow.
227+
usePGeneric(p)
228+
229+
// With borrow.
230+
usePGeneric(_borrow p)
231+
}
232+
233+
// CHECK-LABEL: sil hidden [ossa] @$s11borrow_expr25simpleTestGenericArgFieldyyxAA1PRzlF : $@convention(thin) <T where T : P> (@in_guaranteed T) -> () {
234+
// CHECK: } // end sil function '$s11borrow_expr25simpleTestGenericArgFieldyyxAA1PRzlF'
235+
func simpleTestGenericArgField<T : P>(_ pArg: T) {
236+
var p = pArg
237+
p = pArg
238+
239+
// Without borrow.
240+
useQGeneric(p.q)
241+
242+
// With borrow.
243+
//
244+
// TODO: This doesn't work now. We should support this potentially for
245+
// _read. But protocols seem to not support _read at this time.
246+
// useQGeneric(_borrow p.q)
247+
}
248+
249+
//--------------------------------------------------------------------------------
250+
// Exisentials
251+
//
252+
253+
// CHECK-LABEL: sil hidden [ossa] @$s11borrow_expr24simpleTestExistentialArgyyAA1P_pF : $@convention(thin) (@in_guaranteed any P) -> () {
254+
// CHECK: [[ADDR:%.*]] = project_box {{%.*}} : ${ var any P }, 0
255+
//
256+
// First without the borrow.
257+
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[ADDR]]
258+
// CHECK: [[STACK:%.*]] = alloc_stack $any P
259+
// CHECK: copy_addr [[ACCESS]] to [init] [[STACK]]
260+
// CHECK: end_access [[ACCESS]]
261+
// CHECK: [[FUNC:%.*]] = function_ref @$s11borrow_expr15usePExistentialyyAA1P_pF : $@convention(thin) (@in_guaranteed any P) -> ()
262+
// CHECK: apply [[FUNC]]([[STACK]])
263+
// CHECK: destroy_addr [[STACK]]
264+
// CHECK: dealloc_stack [[STACK]]
265+
//
266+
// Now with the borrow.
267+
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[ADDR]]
268+
// CHECK: [[FUNC:%.*]] = function_ref @$s11borrow_expr15usePExistentialyyAA1P_pF : $@convention(thin) (@in_guaranteed any P) -> ()
269+
// CHECK: apply [[FUNC]]([[ACCESS]])
270+
// CHECK: end_access [[ACCESS]]
271+
// CHECK: } // end sil function '$s11borrow_expr24simpleTestExistentialArgyyAA1P_pF'
272+
func simpleTestExistentialArg(_ pArg: P) {
273+
var p = pArg
274+
p = pArg
275+
276+
// Without borrow.
277+
usePExistential(p)
278+
279+
// With borrow.
280+
usePExistential(_borrow p)
281+
}
282+
283+
284+
func simpleTestExistentialArgField(_ pArg: P) {
285+
var p = pArg
286+
p = pArg
287+
288+
// Without borrow.
289+
useQGeneric(p.q)
290+
291+
// With borrow.
292+
//
293+
// TODO: This doesn't work now. We should support this potentially for
294+
// _read. But protocols seem to not support _read at this time.
295+
// useQGeneric(_borrow p.q)
296+
}

0 commit comments

Comments
 (0)