Skip to content

Commit ddeb192

Browse files
[DiagnosticQol][SR-14505] Use DeclDescriptive kind in missing return data flow diagnostics (#36952)
* [Diagnostics] Use DeclDescriptiveKind on data flow diagnostics to improve diagnostic message * [tests] Add regression tests to SILOptimizer/return.swift * [tests] Adapt other tests to changes of SR-14505 * [Diagnostics] Adapt message for missing return diagnostics, remove article * [Diagnostics] Adapt message for missing return diagnostics to have a note with fix * [tests] Adjust tests in validation suit
1 parent f3eff4a commit ddeb192

File tree

9 files changed

+124
-58
lines changed

9 files changed

+124
-58
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -250,17 +250,25 @@ NOTE(designated_init_c_struct_fix,none,
250250

251251

252252
// Control flow diagnostics.
253-
ERROR(missing_return,none,
254-
"missing return in a %select{function|closure}1 expected to return %0",
255-
(Type, unsigned))
256-
ERROR(missing_return_last_expr,none,
257-
"missing return in a %select{function|closure}1 expected to return %0; "
258-
"did you mean to return the last expression?",
259-
(Type, unsigned))
260-
ERROR(missing_never_call,none,
261-
"%select{function|closure}1 with uninhabited return type %0 is missing "
253+
ERROR(missing_return_closure,none,
254+
"missing return in closure expected to return %0",
255+
(Type))
256+
ERROR(missing_never_call_closure,none,
257+
"closure with uninhabited return type %0 is missing "
258+
"call to another never-returning function on all paths",
259+
(Type))
260+
261+
ERROR(missing_return_decl,none,
262+
"missing return in %1 expected to return %0",
263+
(Type, DescriptiveDeclKind))
264+
ERROR(missing_never_call_decl,none,
265+
"%1 with uninhabited return type %0 is missing "
262266
"call to another never-returning function on all paths",
263-
(Type, unsigned))
267+
(Type, DescriptiveDeclKind))
268+
269+
NOTE(missing_return_last_expr_note,none,
270+
"did you mean to return the last expression?", ())
271+
264272
ERROR(guard_body_must_not_fallthrough,none,
265273
"'guard' body must not fall through, consider using a 'return' or 'throw'"
266274
" to exit the scope", ())

lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -64,22 +64,37 @@ static void diagnoseMissingReturn(const UnreachableInst *UI,
6464
auto element = BS->getLastElement();
6565
if (auto expr = element.dyn_cast<Expr *>()) {
6666
if (expr->getType()->getRValueType()->isEqual(ResTy)) {
67-
Context.Diags.diagnose(
68-
expr->getStartLoc(),
69-
diag::missing_return_last_expr, ResTy,
70-
FLoc.isASTNode<ClosureExpr>() ? 1 : 0)
71-
.fixItInsert(expr->getStartLoc(), "return ");
67+
if (FLoc.isASTNode<ClosureExpr>()) {
68+
Context.Diags.diagnose(expr->getStartLoc(),
69+
diag::missing_return_closure, ResTy);
70+
} else {
71+
auto *DC = FLoc.getAsDeclContext();
72+
assert(DC && DC->getAsDecl() && "not a declaration?");
73+
Context.Diags.diagnose(expr->getStartLoc(), diag::missing_return_decl,
74+
ResTy, DC->getAsDecl()->getDescriptiveKind());
75+
}
76+
Context.Diags
77+
.diagnose(expr->getStartLoc(), diag::missing_return_last_expr_note)
78+
.fixItInsert(expr->getStartLoc(), "return ");
79+
7280
return;
7381
}
7482
}
7583
}
76-
auto diagID = F->isNoReturnFunction(F->getTypeExpansionContext())
77-
? diag::missing_never_call
78-
: diag::missing_return;
79-
diagnose(Context,
80-
L.getEndSourceLoc(),
81-
diagID, ResTy,
82-
FLoc.isASTNode<ClosureExpr>() ? 1 : 0);
84+
85+
bool isNoReturnFn = F->isNoReturnFunction(F->getTypeExpansionContext());
86+
if (FLoc.isASTNode<ClosureExpr>()) {
87+
auto diagID = isNoReturnFn ? diag::missing_never_call_closure
88+
: diag::missing_return_closure;
89+
diagnose(Context, L.getEndSourceLoc(), diagID, ResTy);
90+
} else {
91+
auto *DC = FLoc.getAsDeclContext();
92+
assert(DC && DC->getAsDecl() && "not a declaration?");
93+
auto diagID = isNoReturnFn ? diag::missing_never_call_decl
94+
: diag::missing_return_decl;
95+
diagnose(Context, L.getEndSourceLoc(), diagID, ResTy,
96+
DC->getAsDecl()->getDescriptiveKind());
97+
}
8398
}
8499

85100
static void diagnoseUnreachable(const SILInstruction *I,

test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func try_apply_rethrows(_ x: Float) -> Float {
5555
@differentiable(reverse)
5656
func noReturn(_ x: Float) -> Float {
5757
let _ = x
58-
// expected-error @+2 {{missing return in a function expected to return 'Float'}}
58+
// expected-error @+2 {{missing return in global function expected to return 'Float'}}
5959
// expected-note @+1 {{missing return for differentiation}}
6060
}
6161

test/FixCode/fixits-omit-return.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,28 @@
22

33
func ff_fixit_addreturn() -> String {
44
print("entering ff_fixit_addreturn()")
5-
"foo" // expected-warning {{string literal is unused}} expected-error {{missing return in a function expected to return 'String'; did you mean to return the last expression?}} {{5-5=return }}
5+
"foo" // expected-warning {{string literal is unused}} expected-error {{missing return in global function expected to return 'String'}}
6+
// expected-note@-1 {{did you mean to return the last expression?}}{{5-5=return }}
67
}
78

89
let cl_fixit_addreturn: () -> String = {
910
print("entering cl_fixit_addreturn()")
10-
"foo" // expected-warning {{string literal is unused}} expected-error {{missing return in a closure expected to return 'String'; did you mean to return the last expression?}} {{5-5=return }}
11+
"foo" // expected-warning {{string literal is unused}} expected-error {{missing return in closure expected to return 'String'}}
12+
// expected-note@-1 {{did you mean to return the last expression?}}{{5-5=return }}
1113
}
1214

1315
func ff_fixit_addreturn_ifdecl() -> String {
1416
#if true
1517
print("entering ff_fixit_addreturn_ifdecl()")
16-
"foo" // expected-warning {{string literal is unused}} expected-error {{missing return in a function expected to return 'String'; did you mean to return the last expression?}} {{5-5=return }}
18+
"foo" // expected-warning {{string literal is unused}} expected-error {{missing return in global function expected to return 'String'}}
19+
// expected-note@-1 {{did you mean to return the last expression?}}{{5-5=return }}
1720
#endif
1821
}
1922

2023
let cl_fixit_addreturn_ifdecl: () -> String = {
2124
#if true
2225
print("entering cl_fixit_addreturn_ifdecl()")
23-
"foo" // expected-warning {{string literal is unused}} expected-error {{missing return in a closure expected to return 'String'; did you mean to return the last expression?}} {{5-5=return }}
26+
"foo" // expected-warning {{string literal is unused}} expected-error {{missing return in closure expected to return 'String'}}
27+
// expected-note@-1 {{did you mean to return the last expression?}}{{5-5=return }}
2428
#endif
2529
}

test/Frontend/allow-errors.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,9 @@ func test(s: ValidStructInvalidMember) {
7070
// Check SIL diagnostics are still output (no reason not to output SIL since
7171
// there were no errors)
7272
func other() -> Int {}
73-
// CHECK-VALID: allow-errors.swift:[[@LINE-1]]:22: error: missing return in a function expected to return 'Int'
73+
// CHECK-VALID: allow-errors.swift:[[@LINE-1]]:22: error: missing return in global function expected to return 'Int'
7474
func other2() -> Bool {}
75-
// CHECK-VALID: allow-errors.swift:[[@LINE-1]]:24: error: missing return in a function expected to return 'Bool'
75+
// CHECK-VALID: allow-errors.swift:[[@LINE-1]]:24: error: missing return in global function expected to return 'Bool'
7676
#endif
7777

7878
// All invalid uses should have no errors in the file itself, all referenced

test/SILOptimizer/return.swift

Lines changed: 58 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22

33
func singleBlock() -> Int {
44
_ = 0
5-
} // expected-error {{missing return in a function expected to return 'Int'}}
5+
} // expected-error {{missing return in global function expected to return 'Int'}}
66

77
func singleBlock2() -> Int {
88
var y = 0
99
y += 1
10-
} // expected-error {{missing return in a function expected to return 'Int'}}
10+
} // expected-error {{missing return in global function expected to return 'Int'}}
1111

1212
enum NoCasesButNotNever {}
1313

@@ -36,7 +36,7 @@ func diagnoseNeverWithBody(i : Int) -> Never {
3636
} // expected-error {{function with uninhabited return type 'Never' is missing call to another never-returning function on all paths}}
3737

3838
class MyClassWithClosure {
39-
var f : (_ s: String) -> String = { (_ s: String) -> String in } // expected-error {{missing return in a closure expected to return 'String'}}
39+
var f : (_ s: String) -> String = { (_ s: String) -> String in } // expected-error {{missing return in closure expected to return 'String'}}
4040
}
4141

4242
func multipleBlocksSingleMissing(b: Bool) -> (String, Int) {
@@ -46,7 +46,7 @@ func multipleBlocksSingleMissing(b: Bool) -> (String, Int) {
4646
} else if (y == 0) {
4747
y += 1
4848
}
49-
} // expected-error {{missing return in a function expected to return '(String, Int)'}}
49+
} // expected-error {{missing return in global function expected to return '(String, Int)'}}
5050

5151
func multipleBlocksAllMissing(x: Int) -> Int {
5252
var y : Int = x + 1
@@ -56,15 +56,15 @@ func multipleBlocksAllMissing(x: Int) -> Int {
5656
}
5757
var x = 0
5858
x += 1
59-
} // expected-error {{missing return in a function expected to return 'Int'}}
59+
} // expected-error {{missing return in global function expected to return 'Int'}}
6060

6161
@_silgen_name("exit") func exit () -> Never
6262

6363
func diagnose_missing_return_in_the_else_branch(i: Bool) -> Int {
6464
if (i) {
6565
exit()
6666
}
67-
} // expected-error {{missing return in a function expected to return 'Int'}}
67+
} // expected-error {{missing return in global function expected to return 'Int'}}
6868

6969
func diagnose_missing_return_no_error_after_noreturn(i: Bool) -> Int {
7070
if (i) {
@@ -92,7 +92,7 @@ func whileLoop(flag: Bool) -> Int {
9292
}
9393
b += 1
9494
}
95-
} //expected-error {{missing return in a function expected to return 'Int'}}
95+
} //expected-error {{missing return in global function expected to return 'Int'}}
9696

9797
struct S {}
9898
extension S:ExpressibleByStringLiteral {
@@ -166,21 +166,23 @@ func testSR13753() {
166166
get { 0 }
167167
set { }
168168
}
169-
x // expected-error {{missing return in a closure expected to return 'Int'; did you mean to return the last expression?}} {{5-5=return }}
170-
// expected-warning@-1 {{setter argument 'newValue' was never used, but the property was accessed}}
171-
// expected-note@-2 {{did you mean to use 'newValue' instead of accessing the property's current value?}}
172-
// expected-warning@-3 {{variable is unused}}
169+
x // expected-error {{missing return in closure expected to return 'Int'}}
170+
// expected-note@-1 {{did you mean to return the last expression?}}{{5-5=return }}
171+
// expected-warning@-2 {{setter argument 'newValue' was never used, but the property was accessed}}
172+
// expected-note@-3 {{did you mean to use 'newValue' instead of accessing the property's current value?}}
173+
// expected-warning@-4 {{variable is unused}}
173174
}
174175

175176
func f() -> Int {
176177
var x : Int {
177178
get { 0 }
178179
set { }
179180
}
180-
x // expected-error {{missing return in a function expected to return 'Int'; did you mean to return the last expression?}} {{5-5=return }}
181-
// expected-warning@-1 {{setter argument 'newValue' was never used, but the property was accessed}}
182-
// expected-note@-2 {{did you mean to use 'newValue' instead of accessing the property's current value?}}
183-
// expected-warning@-3 {{variable is unused}}
181+
x // expected-error {{missing return in local function expected to return 'Int'}}
182+
// expected-note@-1 {{did you mean to return the last expression?}}{{5-5=return }}
183+
// expected-warning@-2 {{setter argument 'newValue' was never used, but the property was accessed}}
184+
// expected-note@-3 {{did you mean to use 'newValue' instead of accessing the property's current value?}}
185+
// expected-warning@-4 {{variable is unused}}
184186
}
185187

186188
let _ : () -> Int = {
@@ -192,7 +194,7 @@ func testSR13753() {
192194
// expected-warning@-1 {{setter argument 'newValue' was never used, but the property was accessed}}
193195
// expected-note@-2 {{did you mean to use 'newValue' instead of accessing the property's current value?}}
194196
// expected-warning@-3 {{variable is unused}}
195-
} // expected-error {{missing return in a closure expected to return 'Int'}}
197+
} // expected-error {{missing return in closure expected to return 'Int'}}
196198

197199
func f1() -> Int {
198200
var x : UInt {
@@ -203,13 +205,50 @@ func testSR13753() {
203205
// expected-warning@-1 {{setter argument 'newValue' was never used, but the property was accessed}}
204206
// expected-note@-2 {{did you mean to use 'newValue' instead of accessing the property's current value?}}
205207
// expected-warning@-3 {{variable is unused}}
206-
} // expected-error {{missing return in a function expected to return 'Int'}}
208+
} // expected-error {{missing return in local function expected to return 'Int'}}
207209

208210
let _ : () -> Int = {
209211
var x : Int = 0 // expected-warning {{variable 'x' was never mutated; consider changing to 'let' constant}}
210212
var _ : Int = 0
211213

212-
x // expected-error{{missing return in a closure expected to return 'Int'; did you mean to return the last expression?}} {{5-5=return }}
213-
//expected-warning@-1{{variable is unused}}
214+
x // expected-error{{missing return in closure expected to return 'Int'}}
215+
// expected-note@-1 {{did you mean to return the last expression?}}{{5-5=return }}
216+
//expected-warning@-2{{variable is unused}}
214217
}
215218
}
219+
220+
// SR-14505
221+
struct SR14505 {
222+
let b = true
223+
var x: Int {
224+
if b {
225+
return 0
226+
}
227+
} // expected-error {{missing return in getter expected to return 'Int'}}
228+
229+
var y: Int {
230+
get {
231+
if b {
232+
return 0
233+
}
234+
} // expected-error {{missing return in getter expected to return 'Int'}}
235+
set {}
236+
}
237+
}
238+
239+
class SR14505_C {
240+
static let a = false
241+
let b = true
242+
243+
func method() -> Int {
244+
if b {
245+
return 0
246+
}
247+
} // expected-error {{missing return in instance method expected to return 'Int'}}
248+
249+
class func method1() -> Int {
250+
if a {
251+
return 0
252+
}
253+
} // expected-error {{missing return in class method expected to return 'Int'}}
254+
}

test/SourceKit/Sema/enum-toraw/enum-toraw.swift.response

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
key.column: 1,
1919
key.filepath: t2.swift,
2020
key.severity: source.diagnostic.severity.error,
21-
key.description: "missing return in a function expected to return 'Bool'",
21+
key.description: "missing return in global function expected to return 'Bool'",
2222
key.diagnostic_stage: source.diagnostic.stage.swift.sema
2323
}
2424
]

validation-test/stdlib/AssertDiagnosticsSIL.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
func assertionFailure_isNotNoreturn() -> Int {
44
_ = 0 // Don't implicitly return the assertionFailure call.
55
assertionFailure("")
6-
} // expected-error {{missing return in a function expected to return 'Int'}}
6+
} // expected-error {{missing return in global function expected to return 'Int'}}
77

validation-test/stdlib/BoolDiagnostics_Dataflow.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,49 +8,49 @@ func test_constantFoldAnd1() -> Int {
88
return 42
99
}
1010
// FIXME: this is a false positive.
11-
} // expected-error {{missing return in a function expected to return 'Int'}}
11+
} // expected-error {{missing return in global function expected to return 'Int'}}
1212

1313
func test_constantFoldAnd2() -> Int {
1414
while true && false {
1515
return 42
1616
}
17-
} // expected-error {{missing return in a function expected to return 'Int'}}
17+
} // expected-error {{missing return in global function expected to return 'Int'}}
1818

1919
func test_constantFoldAnd3() -> Int {
2020
while false && true {
2121
return 42
2222
}
23-
} // expected-error {{missing return in a function expected to return 'Int'}}
23+
} // expected-error {{missing return in global function expected to return 'Int'}}
2424

2525
func test_constantFoldAnd4() -> Int {
2626
while false && false {
2727
return 42
2828
}
29-
} // expected-error {{missing return in a function expected to return 'Int'}}
29+
} // expected-error {{missing return in global function expected to return 'Int'}}
3030

3131
func test_constantFoldOr1() -> Int {
3232
while true || true {
3333
return 42
3434
}
3535
// FIXME: this is a false positive.
36-
} // expected-error {{missing return in a function expected to return 'Int'}}
36+
} // expected-error {{missing return in global function expected to return 'Int'}}
3737

3838
func test_constantFoldOr2() -> Int {
3939
while true || false {
4040
return 42
4141
}
4242
// FIXME: this is a false positive.
43-
} // expected-error {{missing return in a function expected to return 'Int'}}
43+
} // expected-error {{missing return in global function expected to return 'Int'}}
4444

4545
func test_constantFoldOr3() -> Int {
4646
while false || true {
4747
return 42
4848
}
4949
// FIXME: this is a false positive.
50-
} // expected-error {{missing return in a function expected to return 'Int'}}
50+
} // expected-error {{missing return in global function expected to return 'Int'}}
5151

5252
func test_constantFoldOr4() -> Int {
5353
while false || false {
5454
return 42
5555
}
56-
} // expected-error {{missing return in a function expected to return 'Int'}}
56+
} // expected-error {{missing return in global function expected to return 'Int'}}

0 commit comments

Comments
 (0)