Skip to content

Commit 543d649

Browse files
authored
[Diagnostics] Warn when the result of a Void-returning function is ignored (by assigning into '_') (swiftlang#29576)
1 parent d0205d8 commit 543d649

22 files changed

+61
-37
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3193,6 +3193,9 @@ ERROR(object_literal_broken_proto,none,
31933193
ERROR(discard_expr_outside_of_assignment,none,
31943194
"'_' can only appear in a pattern or on the left side of an assignment",
31953195
())
3196+
WARNING(discard_expr_void_result_redundant, none,
3197+
"using '_' to ignore the result of a Void-returning function "
3198+
"is redundant", ())
31963199
ERROR(collection_literal_heterogeneous,none,
31973200
"heterogeneous collection literal could only be inferred to %0; add"
31983201
" explicit type annotation if this is intentional", (Type))

lib/Sema/MiscDiagnostics.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,24 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
221221
}
222222

223223
// If we have an assignment expression, scout ahead for acceptable _'s.
224-
if (auto *AE = dyn_cast<AssignExpr>(E))
225-
markAcceptableDiscardExprs(AE->getDest());
224+
if (auto *AE = dyn_cast<AssignExpr>(E)) {
225+
auto destExpr = AE->getDest();
226+
markAcceptableDiscardExprs(destExpr);
227+
// If the user is assigning the result of a function that returns
228+
// Void to _ then warn, because that is redundant.
229+
if (auto DAE = dyn_cast<DiscardAssignmentExpr>(destExpr)) {
230+
if (auto CE = dyn_cast<CallExpr>(AE->getSrc())) {
231+
if (CE->getCalledValue() && isa<FuncDecl>(CE->getCalledValue()) &&
232+
CE->getType()->isVoid()) {
233+
Ctx.Diags
234+
.diagnose(DAE->getLoc(),
235+
diag::discard_expr_void_result_redundant)
236+
.fixItRemoveChars(DAE->getStartLoc(),
237+
AE->getSrc()->getStartLoc());
238+
}
239+
}
240+
}
241+
}
226242

227243
/// Diagnose a '_' that isn't on the immediate LHS of an assignment.
228244
if (auto *DAE = dyn_cast<DiscardAssignmentExpr>(E)) {
@@ -409,7 +425,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
409425
/// in simple pattern-like expressions, so we reject anything complex here.
410426
void markAcceptableDiscardExprs(Expr *E) {
411427
if (!E) return;
412-
428+
413429
if (auto *PE = dyn_cast<ParenExpr>(E))
414430
return markAcceptableDiscardExprs(PE->getSubExpr());
415431
if (auto *TE = dyn_cast<TupleExpr>(E)) {

test/ClangImporter/MixedSource/submodule.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
@_exported import Mixed.Submodule
55

66
func test() {
7-
_ = topLevel()
8-
_ = fromSubmodule()
7+
topLevel()
8+
fromSubmodule()
99
}

test/ClangImporter/private_frameworks.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@
3939
import SomeKit
4040

4141
func testWidget(widget: SKWidget) {
42-
_ = widget.someObjCMethod()
43-
_ = widget.someObjCExtensionMethod()
42+
widget.someObjCMethod()
43+
widget.someObjCExtensionMethod()
4444

4545
let ext = widget.extensionMethod()
4646
ext.foo()

test/Compatibility/special_func_name.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,16 @@ struct S3 {
3434
}
3535

3636
_ = S11(0) // expected-error {{argument passed to call that takes no arguments}}
37-
_ = S11.init(0)
38-
_ = S11.`init`(0)
37+
S11.init(0)
38+
S11.`init`(0)
3939

4040
_ = S12(0)
4141
_ = S12.init(0)
4242
_ = S12.`init`(0) // expected-error {{type 'S12' has no member 'init'}}
4343

4444
_ = S21(0) // expected-error {{argument passed to call that takes no arguments}}
45-
_ = S21.init(0)
46-
_ = S21.`init`(0)
45+
S21.init(0)
46+
S21.`init`(0)
4747

4848
_ = S22(0)
4949
_ = S22.init(0)

test/Constraints/assignment.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,8 @@ func f23798944() {
7272
}
7373

7474
.sr_3506 = 0 // expected-error {{type 'Int' has no member 'sr_3506'}}
75+
76+
// SR-1553
77+
78+
func returnsVoid() {}
79+
_ = returnsVoid() // expected-warning {{using '_' to ignore the result of a Void-returning function is redundant}}{{1-5=}}

test/Constraints/dynamic_lookup.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ let anyValue: Any = X()
224224
_ = anyValue.bar() // expected-error {{value of type 'Any' has no member 'bar'}}
225225
// expected-note@-1 {{cast 'Any' to 'AnyObject' or use 'as!' to force downcast to a more specific type to access members}}{{5-5=(}}{{13-13= as AnyObject)}}
226226
_ = (anyValue as AnyObject).bar()
227-
_ = (anyValue as! X).bar()
227+
(anyValue as! X).bar()
228228

229229
var anyDict: [String : Any] = Dictionary<String, Any>()
230230
anyDict["test"] = anyValue

test/Constraints/optional.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,8 +391,8 @@ func sr8411() {
391391

392392
_ = S(&foo) // Ok
393393
_ = S.init(&foo) // Ok
394-
_ = S.foo(&foo) // Ok
395-
_ = S.bar(&foo, 42) // Ok
394+
S.foo(&foo) // Ok
395+
S.bar(&foo, 42) // Ok
396396
}
397397

398398
// SR-11104 - Slightly misleading diagnostics for contextual failures with multiple fixes

test/Constraints/override.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ class Sub: Base {
99
}
1010

1111
func removeOverrides<SomeSub: Sub>(concrete: Sub, generic: SomeSub) {
12-
_ = concrete.foo()
13-
_ = generic.foo()
12+
concrete.foo()
13+
generic.foo()
1414
}
1515

1616
class Base1 {

test/Constraints/rdar39931475.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ protocol P {
55
}
66

77
func foo<T: P>(_ bar: T) {
8-
_ = bar.b { a in Double((a, a += 1).0) }
8+
bar.b { a in Double((a, a += 1).0) }
99
}

0 commit comments

Comments
 (0)