Skip to content

Commit 67ac2fd

Browse files
authored
Merge pull request #16999 from CodaFi/witness-tampering
Allow Copyable Types To Elide Ownership Conventions
2 parents 7b3d6c0 + 9bd02e1 commit 67ac2fd

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)