Skip to content

Commit 9a0f165

Browse files
committed
[Sema]: minor improvements to unused expression result diagnostics
Previously we would emit a diagnostic in cases in which a throwing function returning a structurally-unihabited type was called within an optional try expression. Such cases can never produce a return value, so suppress the existing diagnostic.
1 parent aca07fb commit 9a0f165

File tree

2 files changed

+83
-6
lines changed

2 files changed

+83
-6
lines changed

lib/Sema/TypeCheckStmt.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1823,9 +1823,14 @@ static bool isDiscardableType(Type type) {
18231823
if (auto *expansion = type->getAs<PackExpansionType>())
18241824
return isDiscardableType(expansion->getPatternType());
18251825

1826-
return (type->hasError() ||
1827-
type->isUninhabited() ||
1828-
type->lookThroughAllOptionalTypes()->isVoid());
1826+
if (type->hasError())
1827+
return true;
1828+
1829+
// Look through optionality and check if the type is either `Void` or
1830+
// 'structurally uninhabited'. Treat either as discardable.
1831+
auto nonOptionalType = type->lookThroughAllOptionalTypes();
1832+
return (nonOptionalType->isStructurallyUninhabited() ||
1833+
nonOptionalType->isVoid());
18291834
}
18301835

18311836
static void diagnoseIgnoredLiteral(ASTContext &Ctx, LiteralExpr *LE) {
@@ -1972,9 +1977,8 @@ void TypeChecker::checkIgnoredExpr(Expr *E) {
19721977
}
19731978
}
19741979

1975-
// If the result of this expression is of type "Never" or "()"
1976-
// (the latter potentially wrapped in optionals) then it is
1977-
// safe to ignore.
1980+
// If the result of this expression is either "structurally uninhabited" or
1981+
// `Void`, (potentially wrapped in optionals) then it is safe to ignore.
19781982
if (isDiscardableType(valueE->getType()))
19791983
return;
19801984

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
struct MyError: Error {}
4+
enum MyNever {}
5+
6+
func never_throws() throws -> Never { throw MyError() }
7+
func uninhabited_throws() throws -> (Int, MyNever) { throw MyError () }
8+
func almost_uninhabited_throws() throws -> (Int, Never?) { throw MyError () }
9+
func int_throws() throws -> Int { throw MyError() }
10+
func void_throws() throws {}
11+
12+
func maybe_never() -> Never? { nil }
13+
func maybe_uninhabited() -> (Int, MyNever)? { nil }
14+
func maybe_maybe_uninhabited() -> (Int, Never)?? { nil }
15+
func maybe_void() -> Void? { nil }
16+
func maybe_maybe_void() -> Void?? { nil }
17+
func looks_uninhabited_if_you_squint() -> (Int, Never?)? { nil }
18+
19+
// MARK: - Tests
20+
21+
func test_try() throws {
22+
try never_throws()
23+
try uninhabited_throws()
24+
try almost_uninhabited_throws()
25+
// expected-warning @-1 {{result of call to 'almost_uninhabited_throws()' is unused}}
26+
try int_throws()
27+
// expected-warning @-1 {{result of call to 'int_throws()' is unused}}
28+
try void_throws()
29+
}
30+
31+
func test_force_try() throws {
32+
try! never_throws()
33+
try! uninhabited_throws()
34+
try! almost_uninhabited_throws()
35+
// expected-warning @-1 {{result of call to 'almost_uninhabited_throws()' is unused}}
36+
try! int_throws()
37+
// expected-warning @-1 {{result of call to 'int_throws()' is unused}}
38+
try! void_throws()
39+
}
40+
41+
func test_optional_try() throws {
42+
try? never_throws()
43+
try? uninhabited_throws()
44+
try? almost_uninhabited_throws()
45+
// expected-warning @-1 {{result of 'try?' is unused}}
46+
try? int_throws()
47+
// expected-warning @-1 {{result of 'try?' is unused}}
48+
try? void_throws()
49+
}
50+
51+
func test_implicitly_discardable() {
52+
maybe_never()
53+
maybe_uninhabited()
54+
maybe_maybe_uninhabited()
55+
maybe_void()
56+
maybe_maybe_void()
57+
looks_uninhabited_if_you_squint()
58+
// expected-warning @-1 {{result of call to 'looks_uninhabited_if_you_squint()' is unused}}
59+
}
60+
61+
// https://github.com/swiftlang/swift/issues/85092
62+
63+
func test_85092() {
64+
struct MyError: Error {}
65+
66+
func f() throws -> Never {
67+
throw MyError()
68+
}
69+
70+
func g() {
71+
try? f()
72+
}
73+
}

0 commit comments

Comments
 (0)