Skip to content

Commit 1bcef4a

Browse files
hamishknightslavapestov
authored andcommitted
[Sema] Don't mark apply exprs as non-throwing if they haven't been type checked yet
Apply exprs in initialiser expressions for lazy properties were being incorrectly marked as not throwing due to the fact that initialiser expressions for lazy properties don't have a solution applied to them until they get type checked as a part of the synthesised getter.
1 parent e794049 commit 1bcef4a

File tree

2 files changed

+90
-2
lines changed

2 files changed

+90
-2
lines changed

lib/Sema/TypeCheckError.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1409,7 +1409,8 @@ class CheckErrorCoverage : public ErrorHandlingWalker<CheckErrorCoverage> {
14091409

14101410
// HACK: functions can get queued multiple times in
14111411
// definedFunctions, so be sure to be idempotent.
1412-
if (!E->isThrowsSet()) {
1412+
if (!E->isThrowsSet() &&
1413+
classification.getResult() != ThrowingKind::Invalid) {
14131414
E->setThrows(classification.getResult() == ThrowingKind::RethrowingOnly ||
14141415
classification.getResult() == ThrowingKind::Throws);
14151416
}
@@ -1483,6 +1484,9 @@ class CheckErrorCoverage : public ErrorHandlingWalker<CheckErrorCoverage> {
14831484
Flags.set(ContextFlags::HasAnyThrowSite);
14841485
if (requiresTry) Flags.set(ContextFlags::HasTryThrowSite);
14851486

1487+
// We set the throwing bit of an apply expr after performing this
1488+
// analysis, so ensure we don't emit duplicate diagnostics for functions
1489+
// that have been queued multiple times.
14861490
if (auto expr = E.dyn_cast<Expr*>())
14871491
if (auto apply = dyn_cast<ApplyExpr>(expr))
14881492
if (apply->isThrowsSet())

test/decl/func/throwing_functions.swift

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,91 @@ enum MSV : Error {
162162
func genError() throws -> Int { throw MSV.Foo }
163163

164164
struct IllegalContext {
165-
var x: Int = genError() // expected-error {{call can throw, but errors cannot be thrown out of a property initializer}}
165+
var x1: Int = genError() // expected-error {{call can throw, but errors cannot be thrown out of a property initializer}}
166+
167+
let x2 = genError() // expected-error {{call can throw, but errors cannot be thrown out of a property initializer}}
168+
169+
var x3 = try genError() // expected-error {{call can throw, but errors cannot be thrown out of a property initializer}}
170+
171+
let x4: Int = try genError() // expected-error {{call can throw, but errors cannot be thrown out of a property initializer}}
172+
173+
var x5 = B() // expected-error {{call can throw, but errors cannot be thrown out of a property initializer}}
174+
175+
var x6 = try B() // expected-error {{call can throw, but errors cannot be thrown out of a property initializer}}
176+
177+
var x7 = { // expected-error {{call can throw, but errors cannot be thrown out of a property initializer}}
178+
return try genError()
179+
}()
180+
181+
var x8: Int = {
182+
do {
183+
return genError() // expected-error {{call can throw but is not marked with 'try'}}
184+
// expected-note@-1 {{did you mean to use 'try'?}}
185+
// expected-note@-2 {{did you mean to handle error as optional value?}}
186+
// expected-note@-3 {{did you mean to disable error propagation?}}
187+
} catch {
188+
return 0
189+
}
190+
}()
191+
192+
var x9: Int = {
193+
do {
194+
return try genError()
195+
} catch {
196+
return 0
197+
}
198+
}()
199+
200+
var x10: B = {
201+
do {
202+
return try B()
203+
} catch {
204+
return B(foo: 0)
205+
}
206+
}()
207+
208+
lazy var y1: Int = genError() // expected-error {{call can throw, but it is not marked with 'try' and the error is not handled}}
209+
210+
lazy var y2 = genError() // expected-error {{call can throw, but it is not marked with 'try' and the error is not handled}}
211+
212+
lazy var y3 = try genError() // expected-error {{errors thrown from here are not handled}}
213+
214+
lazy var y4: Int = try genError() // expected-error {{errors thrown from here are not handled}}
215+
216+
lazy var y5 = B() // expected-error {{call can throw, but it is not marked with 'try' and the error is not handled}}
217+
218+
lazy var y6 = try B() // expected-error {{errors thrown from here are not handled}}
219+
220+
lazy var y7 = { // expected-error {{call can throw, but it is not marked with 'try' and the error is not handled}}
221+
return try genError()
222+
}()
223+
224+
lazy var y8: Int = {
225+
do {
226+
return genError() // expected-error {{call can throw but is not marked with 'try'}}
227+
// expected-note@-1 {{did you mean to use 'try'?}}
228+
// expected-note@-2 {{did you mean to handle error as optional value?}}
229+
// expected-note@-3 {{did you mean to disable error propagation?}}
230+
} catch {
231+
return 0
232+
}
233+
}()
234+
235+
lazy var y9: Int = {
236+
do {
237+
return try genError()
238+
} catch {
239+
return 0
240+
}
241+
}()
242+
243+
lazy var y10: B = {
244+
do {
245+
return try B()
246+
} catch {
247+
return B(foo: 0)
248+
}
249+
}()
166250

167251
func foo(_ x: Int = genError()) {} // expected-error {{call can throw, but errors cannot be thrown out of a default argument}}
168252

0 commit comments

Comments
 (0)