Skip to content

Commit 9bd02e1

Browse files
committed
Allow eliding ownership conventions in a copyable context
Allow witnesses to protocols in a copyable context to elide explicit ownership conventions. This allows clients like the standard library to standardize on one ownership convention without an ABI or API breaking change in 3rd party code. In the future, moveonly contexts must disallow this default behavior else the witness thunks could silently transfer ownership. rdar://40774922 protocol P { __consuming func implicit(x: __shared String) __consuming func explicit(x: __owned String) __consuming func mismatch(x: __shared String) } class C : P { // C.implicit(x:) takes self and x '@guaranteed' thru the witness thunk func implicit(x: String) {} // C.explicit(x:) takes self and x @owned with no convention changes __consuming func explicit(x: __owned String) {} // Would inherit __consuming, but x has been spelled __owned so the requirement match fails. func mismatch(x: __owned String) {} }
1 parent 9f30ed6 commit 9bd02e1

File tree

5 files changed

+72
-21
lines changed

5 files changed

+72
-21
lines changed

include/swift/AST/Types.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2652,6 +2652,10 @@ class AnyFunctionType : public TypeBase {
26522652
/// Whether the parameter is marked 'owned'
26532653
bool isOwned() const { return Flags.isOwned(); }
26542654

2655+
ValueOwnership getValueOwnership() const {
2656+
return Flags.getValueOwnership();
2657+
}
2658+
26552659
bool operator==(Param const &b) const {
26562660
return Label == b.Label && getType()->isEqual(b.getType()) &&
26572661
Flags == b.Flags;

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -396,10 +396,6 @@ swift::matchWitness(
396396
// Check that the mutating bit is ok.
397397
if (checkMutating(funcReq, funcWitness, funcWitness))
398398
return RequirementMatch(witness, MatchKind::MutatingConflict);
399-
if (funcWitness->isNonMutating() && funcReq->isConsuming())
400-
return RequirementMatch(witness, MatchKind::NonMutatingConflict);
401-
if (funcWitness->isConsuming() && !funcReq->isConsuming())
402-
return RequirementMatch(witness, MatchKind::ConsumingConflict);
403399

404400
// If the requirement is rethrows, the witness must either be
405401
// rethrows or be non-throwing.
@@ -536,9 +532,6 @@ swift::matchWitness(
536532
if (reqParams[i].isVariadic() != witnessParams[i].isVariadic())
537533
return RequirementMatch(witness, MatchKind::TypeConflict, witnessType);
538534

539-
if (reqParams[i].isShared() != witnessParams[i].isShared())
540-
return RequirementMatch(witness, MatchKind::TypeConflict, witnessType);
541-
542535
if (reqParams[i].isInOut() != witnessParams[i].isInOut())
543536
return RequirementMatch(witness, MatchKind::TypeConflict, witnessType);
544537

test/SILGen/value_ownership.swift

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// RUN: %target-swift-emit-silgen -enable-sil-ownership -emit-verbose-sil %s | %FileCheck %s
2+
3+
// REQUIRES: plus_zero_runtime
4+
5+
protocol OwnershipProto {
6+
__consuming func elided(_ default: String, _ shared: __shared String, _ owned: __owned String)
7+
8+
__consuming func explicit(_ default: String, _ shared: __shared String, _ owned: __owned String)
9+
}
10+
11+
struct Witness: OwnershipProto {
12+
func elided(_ default: String, _ shared: String, _ owned: String) { }
13+
14+
__consuming func explicit(_ default: String, _ toShared: __shared String, _ toOwned: __owned String) { }
15+
}
16+
17+
// Check the conventions of the witnesses
18+
19+
// CHECK-LABEL: sil hidden @$S15value_ownership7WitnessV6elidedyySS_S2StF : $@convention(method) (@guaranteed String, @guaranteed String, @guaranteed String, Witness) -> () {
20+
// CHECK: } // end sil function '$S15value_ownership7WitnessV6elidedyySS_S2StF'
21+
22+
// CHECK-LABEL: sil hidden @$S15value_ownership7WitnessV8explicityySS_SShSSntF : $@convention(method) (@guaranteed String, @guaranteed String, @owned String, Witness) -> () {
23+
// CHECK: } // end sil function '$S15value_ownership7WitnessV8explicityySS_SShSSntF'
24+
25+
// Check the elided witness' thunk has the right conventions and borrows where necessary
26+
27+
// CHECK-LABEL: @$S15value_ownership7WitnessVAA14OwnershipProtoA2aDP6elidedyySS_SShSSntFTW : $@convention(witness_method: OwnershipProto) (@guaranteed String, @guaranteed String, @owned String, @in_guaranteed Witness) -> ()
28+
// CHECK: bb0([[DEFAULT2DEFAULT:%.*]] : @guaranteed $String, [[SHARED2DEFAULT:%.*]] : @guaranteed $String, [[OWNED2DEFAULT:%.*]] : @owned $String, [[WITNESS_VALUE:%.*]] : @trivial $*Witness):
29+
// CHECK: [[LOAD_WITNESS:%.*]] = load [trivial] [[WITNESS_VALUE]] : $*Witness
30+
// CHECK: [[WITNESS_FUNC:%.*]] = function_ref @$S15value_ownership7WitnessV6elidedyySS_S2StF
31+
// CHECK: [[BORROWOWNED2DEFAULT:%.*]] = begin_borrow [[OWNED2DEFAULT]] : $String
32+
// CHECK: apply [[WITNESS_FUNC]]([[DEFAULT2DEFAULT]], [[SHARED2DEFAULT]], [[BORROWOWNED2DEFAULT]], [[LOAD_WITNESS]])
33+
// CHECK: end_borrow [[BORROWOWNED2DEFAULT]] from [[OWNED2DEFAULT]] : $String, $String
34+
// CHECK: } // end sil function '$S15value_ownership7WitnessVAA14OwnershipProtoA2aDP6elidedyySS_SShSSntFTW'
35+
36+
// Check that the explicit witness' thunk doesn't copy or borrow
37+
38+
// CHECK-LABEL: @$S15value_ownership7WitnessVAA14OwnershipProtoA2aDP8explicityySS_SShSSntFTW : $@convention(witness_method: OwnershipProto) (@guaranteed String, @guaranteed String, @owned String, @in_guaranteed Witness) -> () {
39+
// CHECK: bb0([[ARG0:%.*]] : @guaranteed $String, [[ARG1:%.*]] : @guaranteed $String, [[ARG2:%.*]] : @owned $String, [[WITNESS_VALUE:%.*]] : @trivial $*Witness):
40+
// CHECK-NEXT: [[LOAD_WITNESS:%.*]] = load [trivial] [[WITNESS_VALUE]] : $*Witness
41+
// CHECK-NEXT: // function_ref Witness.explicit(_:_:_:)
42+
// CHECK-NEXT: [[WITNESS_FUNC:%.*]] = function_ref @$S15value_ownership7WitnessV8explicityySS_SShSSntF
43+
// CHECK-NEXT: apply [[WITNESS_FUNC]]([[ARG0]], [[ARG1]], [[ARG2]], [[LOAD_WITNESS]])
44+
// CHECK: } // end sil function '$S15value_ownership7WitnessVAA14OwnershipProtoA2aDP8explicityySS_SShSSntFTW'

test/Sema/immutability.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -246,9 +246,9 @@ protocol MutatingTestProto {
246246
mutating
247247
func mutatingfunc()
248248

249-
func nonmutatingfunc() // expected-note 2 {{protocol requires}}
249+
func nonmutatingfunc() // expected-note {{protocol requires}}
250250
__consuming
251-
func consuming_nonmutating_func() // expected-note 2 {{protocol requires}}
251+
func consuming_nonmutating_func() // expected-note {{protocol requires}}
252252
}
253253

254254
class TestClass : MutatingTestProto {
@@ -281,18 +281,18 @@ struct TestStruct3 : MutatingTestProto { // expected-error {{type 'TestStruct3
281281
func consuming_nonmutating_func() {} // expected-note {{candidate is marked 'mutating' but protocol does not allow it}}
282282
}
283283

284-
struct TestStruct4 : MutatingTestProto { // expected-error {{type 'TestStruct4' does not conform to protocol 'MutatingTestProto'}}
284+
struct TestStruct4 : MutatingTestProto {
285285
mutating
286286
func mutatingfunc() {} // Ok, can be mutating.
287287
func nonmutatingfunc() {}
288-
nonmutating func consuming_nonmutating_func() {} // expected-note {{candidate is marked 'nonmutating' but protocol does not allow it}}
288+
nonmutating func consuming_nonmutating_func() {}
289289
}
290290

291-
struct TestStruct5 : MutatingTestProto { // expected-error {{type 'TestStruct5' does not conform to protocol 'MutatingTestProto'}}
291+
struct TestStruct5 : MutatingTestProto {
292292
mutating
293293
func mutatingfunc() {} // Ok, can be mutating.
294294
__consuming
295-
func nonmutatingfunc() {} // expected-note {{candidate is marked '__consuming' but protocol does not allow it}}
295+
func nonmutatingfunc() {}
296296
__consuming func consuming_nonmutating_func() {}
297297
}
298298

test/decl/protocol/req/func.swift

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -196,16 +196,26 @@ struct X6 : P6 { // expected-error{{type 'X6' does not conform to protocol 'P6'}
196196
}
197197

198198
protocol P6Ownership {
199-
func foo(_ x: __shared Int) // expected-note{{protocol requires function 'foo' with type '(__shared Int) -> ()'}}
200-
func foo2(_ x: Int) // expected-note{{protocol requires function 'foo2' with type '(Int) -> ()'}}
201-
func bar(x: Int)
202-
func bar2(x: __owned Int)
199+
func thunk__shared(_ x: __shared Int)
200+
func mismatch__shared(_ x: Int)
201+
func mismatch__owned(x: Int)
202+
func thunk__owned__owned(x: __owned Int)
203+
204+
__consuming func inherits__consuming(x: Int)
205+
func mismatch__consuming(x: Int)
206+
__consuming func mismatch__consuming_mutating(x: Int) // expected-note {{protocol requires function 'mismatch__consuming_mutating(x:)' with type '(Int) -> ()'}}
207+
mutating func mismatch__mutating_consuming(x: Int)
203208
}
204209
struct X6Ownership : P6Ownership { // expected-error{{type 'X6Ownership' does not conform to protocol 'P6Ownership'}}
205-
func foo(_ x: Int) { } // expected-note{{candidate has non-matching type '(Int) -> ()'}}
206-
func foo2(_ x: __shared Int) { } // expected-note{{candidate has non-matching type '(__shared Int) -> ()'}}
207-
func bar(x: __owned Int) { } // no diagnostic
208-
func bar2(x: Int) { } // no diagnostic
210+
func thunk__shared(_ x: Int) { } // OK
211+
func mismatch__shared(_ x: __shared Int) { } // OK
212+
func mismatch__owned(x: __owned Int) { } // OK
213+
func thunk__owned__owned(x: Int) { } // OK
214+
215+
func inherits__consuming(x: Int) { } // OK
216+
__consuming func mismatch__consuming(x: Int) { } // OK
217+
mutating func mismatch__consuming_mutating(x: Int) { } // expected-note {{candidate is marked 'mutating' but protocol does not allow it}}
218+
__consuming func mismatch__mutating_consuming(x: Int) { } // OK - '__consuming' acts as a counterpart to 'nonmutating'
209219
}
210220

211221
protocol P7 {

0 commit comments

Comments
 (0)