File: attr_rethrows_protocol.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (242 lines) | stat: -rw-r--r-- 6,395 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
// RUN: %target-typecheck-verify-swift

@rethrows
protocol RethrowingProtocol {
  func source() throws
}

struct Rethrows<Source: RethrowingProtocol>: RethrowingProtocol {
  var other: Source
  func source() rethrows { }
}

struct Throws: RethrowingProtocol {
  func source() throws { }
}

struct ThrowsWithSource<Source: RethrowingProtocol>: RethrowingProtocol {
  var other: Source
  func source() throws { }
}

struct NonThrows: RethrowingProtocol {
  func source() { }
}

struct NonThrowsWithSource<Source: RethrowingProtocol>: RethrowingProtocol {
  var other: Source
  func source() { }
}

protocol InvalidRethrowingProtocol {
  func source() throws
}

struct InvalidRethrows : InvalidRethrowingProtocol {
  func source() rethrows { }
  // expected-error@-1{{'rethrows' function must take a throwing function argument}}
}

func freeFloatingRethrowing<R: RethrowingProtocol>(_ r: R) rethrows {
  try r.source()
}

func freeFloatingRethrowingFromExistential(_ r: RethrowingProtocol) rethrows {
  // expected-error@-1{{'rethrows' function must take a throwing function argument}}
}

func invalidFreeFloatingRethrows() rethrows {
  // expected-error@-1{{'rethrows' function must take a throwing function argument}}
}

let rethrowingFromThrows = Rethrows(other: Throws())
try rethrowingFromThrows.source()

@rethrows
protocol HasAssociatedRethrowerWithEnclosedRethrow {
  associatedtype Rethrower: RethrowingProtocol

  func source() throws
}

@rethrows
protocol HasAssociatedRethrower {
  associatedtype Rethrower: RethrowingProtocol

  func makeRethrower() -> Rethrower
}

func freeFloatingRethrowing<R: HasAssociatedRethrower>(_ r: R) rethrows {
  try r.makeRethrower().source()
}

@rethrows
protocol InheritsRethrowing: RethrowingProtocol {}

func freeFloatingInheritedRethrowingFunction<I: InheritsRethrowing>(_ r: I) rethrows { }

func freeFloatingInheritedRethrowingFunctionFromExistential(_ r: InheritsRethrowing) rethrows {
  // expected-error@-1{{'rethrows' function must take a throwing function argument}}
}

func closureAndRethrowing<R: RethrowingProtocol>(_ r: R, _ closure: () throws -> Void) rethrows {
  try r.source()
  try closure()
}

closureAndRethrowing(NonThrows()) { }
try closureAndRethrowing(NonThrows()) { } // expected-warning{{no calls to throwing functions occur within 'try' expression}}
try closureAndRethrowing(Throws()) { }
try closureAndRethrowing(NonThrows()) { () throws -> Void in }

// Make sure we handle the case where both the 'self' parameter and a closure
// argument are rethrows sources.
extension RethrowingProtocol {
  func selfRethrowing() rethrows {
    try source()
  }
  func closureAndSelfRethrowing(_ closure: () throws -> Void) rethrows {
    try source()
    try closure()
  }
}

NonThrows().selfRethrowing()
try Throws().selfRethrowing()

NonThrows().closureAndSelfRethrowing { }
try NonThrows().closureAndSelfRethrowing { () throws -> Void in }

try Throws().closureAndSelfRethrowing { }
try Throws().closureAndSelfRethrowing { () throws -> Void in }

// Soundness hole
@rethrows protocol ThrowsClosure {
  func doIt() throws
  func doIt(_: () throws -> ()) throws
}

struct ThrowsClosureWitness : ThrowsClosure {
  func doIt() {}
  func doIt(_: () throws -> ()) throws {}
}

func rethrowsWithThrowsClosure<T : ThrowsClosure>(_ t: T) rethrows {
  try t.doIt() {}
}

try rethrowsWithThrowsClosure(ThrowsClosureWitness())

@rethrows protocol RethrowsClosure {
  func doIt() throws
  func doIt(_: () throws -> ()) rethrows
}

struct RethrowsClosureWitness : RethrowsClosure {
  func doIt() {}
  func doIt(_: () throws -> ()) rethrows {}
}

func rethrowsWithRethrowsClosure<T : RethrowsClosure>(_ t: T) rethrows {
  try t.doIt() {}
}

rethrowsWithRethrowsClosure(RethrowsClosureWitness())

// Empty protocol
@rethrows protocol Empty {}
struct EmptyWitness : Empty {}

func takesEmpty<T : Empty>(_: T) rethrows {}

takesEmpty(EmptyWitness())

// Rethrows kinds need to line up when a 'rethrows' function witnesses a
// 'rethrows' protocol requirement

// Note: the SimpleThrowsClosure protocol is not @rethrows
protocol SimpleThrowsClosure {
  func doIt(_: () throws -> ()) rethrows
  // expected-note@-1 {{protocol requires function 'doIt' with type '(() throws -> ()) throws -> ()'; add a stub for conformance}}

  func doIt2<T : Empty>(_: T) rethrows
  // expected-note@-1 {{protocol requires function 'doIt2' with type '<T> (T) throws -> ()'; add a stub for conformance}}
}

struct ConformsToSimpleThrowsClosure<T : RethrowingProtocol> : SimpleThrowsClosure {
// expected-error@-1 {{type 'ConformsToSimpleThrowsClosure<T>' does not conform to protocol 'SimpleThrowsClosure'}}
  let t: T

  // This cannot witness SimpleThrowsClosure.doIt(), because the
  // T : RethrowingProtocol conformance is a source here, but that
  // is not captured in the protocol's requirement signature.
  func doIt(_: () throws -> ()) rethrows {
  // expected-note@-1 {{candidate is 'rethrows' via a conformance, but the protocol requirement is not from a '@rethrows' protocol}}
    try t.source()
  }

  func doIt2<U : Empty>(_: U) rethrows {}
  // expected-note@-1 {{candidate is 'rethrows' via a conformance, but the protocol requirement is not from a '@rethrows' protocol}}
}

func soundnessHole<T : SimpleThrowsClosure>(_ t: T) {
  t.doIt {}
}

// This actually can throw...
soundnessHole(ConformsToSimpleThrowsClosure(t: Throws()))

// Test deeply-nested associated conformances
@rethrows protocol First {
  associatedtype A : Second
}

@rethrows protocol Second {
  associatedtype B : Third
}

@rethrows protocol Third {
  func f() throws
}

struct FirstWitness : First {
  typealias A = SecondWitness
}

struct SecondWitness : Second {
  typealias B = ThirdWitness
}

struct ThirdWitness : Third {
  func f() {}
}

func takesFirst<T : First>(_: T) rethrows {}

takesFirst(FirstWitness())

// Crash with enum case
@rethrows protocol WitnessedByEnumCase {
  static func foo(_: Int) throws -> Self
}

enum MyEnum : WitnessedByEnumCase {
  case foo(Int)
  case bar
}

func takesWitnessedByEnumCase<T : WitnessedByEnumCase>(_: T) rethrows {
  _ = try T.foo(123)
}

takesWitnessedByEnumCase(MyEnum.bar)

// Invalid cases
enum HorseError : Error {
  case bolted
}

func hasRethrowsConformanceAndThrowsBody<T : Empty>(_: T) rethrows {
  throw HorseError.bolted
  // expected-error@-1 {{a function declared 'rethrows' may only throw if its parameter does}}
}