Skip to content

Commit f0c6f00

Browse files
committed
Suggest adding return if the type of unused semi return value can coerce to the fn return type
1 parent 9f5fc1b commit f0c6f00

17 files changed

+333
-119
lines changed

compiler/rustc_errors/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,7 @@ pub enum StashKey {
505505
CallAssocMethod,
506506
TraitMissingMethod,
507507
OpaqueHiddenTypeMismatch,
508+
MaybeForgetReturn,
508509
}
509510

510511
fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+1
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
580580
if !errors.is_empty() {
581581
self.adjust_fulfillment_errors_for_expr_obligation(&mut errors);
582582
self.err_ctxt().report_fulfillment_errors(&errors);
583+
self.collect_unused_for_coerce_return_ty(&mut errors);
583584
}
584585
}
585586

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

+54-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::{
1111
use rustc_ast as ast;
1212
use rustc_data_structures::fx::FxIndexSet;
1313
use rustc_errors::{
14-
pluralize, Applicability, Diagnostic, DiagnosticId, ErrorGuaranteed, MultiSpan,
14+
pluralize, Applicability, Diagnostic, DiagnosticId, ErrorGuaranteed, MultiSpan, StashKey,
1515
};
1616
use rustc_hir as hir;
1717
use rustc_hir::def::{CtorOf, DefKind, Res};
@@ -26,6 +26,7 @@ use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
2626
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
2727
use rustc_infer::infer::TypeTrace;
2828
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
29+
use rustc_middle::traits::ObligationCauseCode::ExprBindingObligation;
2930
use rustc_middle::ty::adjustment::AllowTwoPhase;
3031
use rustc_middle::ty::visit::TypeVisitableExt;
3132
use rustc_middle::ty::{self, IsSuggestable, Ty};
@@ -1834,6 +1835,58 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18341835
}
18351836
}
18361837

1838+
pub(super) fn collect_unused_for_coerce_return_ty(
1839+
&self,
1840+
errors: &[traits::FulfillmentError<'tcx>],
1841+
) {
1842+
for fillment_error in &*errors {
1843+
let obligation = &fillment_error.obligation;
1844+
let span = obligation.cause.span;
1845+
1846+
let Some(mut diag) =
1847+
self.tcx.sess.diagnostic().steal_diagnostic(span, StashKey::MaybeForgetReturn)
1848+
else {
1849+
continue;
1850+
};
1851+
1852+
let root_obligation = &fillment_error.root_obligation;
1853+
if let Some(fn_sig) = self.body_fn_sig()
1854+
&& let ExprBindingObligation(_, _, hir_id, ..) = root_obligation.cause.code()
1855+
&& !fn_sig.output().is_unit() {
1856+
let mut block_num = 0;
1857+
let mut found_semi = false;
1858+
for (_, node) in self.tcx.hir().parent_iter(*hir_id) {
1859+
match node {
1860+
hir::Node::Stmt(stmt) => if let hir::StmtKind::Semi(ref expr) = stmt.kind {
1861+
let expr_ty = self.typeck_results.borrow().expr_ty(expr);
1862+
let return_ty = fn_sig.output();
1863+
if !matches!(expr.kind, hir::ExprKind::Ret(..)) &&
1864+
self.can_coerce(expr_ty, return_ty) {
1865+
found_semi = true;
1866+
}
1867+
},
1868+
hir::Node::Block(_block) => if found_semi {
1869+
block_num += 1;
1870+
}
1871+
hir::Node::Item(item) => if let hir::ItemKind::Fn(..) = item.kind {
1872+
break;
1873+
}
1874+
_ => {}
1875+
}
1876+
}
1877+
if block_num > 1 && found_semi {
1878+
diag.span_suggestion_verbose(
1879+
span.shrink_to_lo(),
1880+
"you might have meant to return this to infer its type parameters",
1881+
"return ",
1882+
Applicability::MaybeIncorrect,
1883+
);
1884+
}
1885+
}
1886+
diag.emit();
1887+
}
1888+
}
1889+
18371890
/// Given a vector of fulfillment errors, try to adjust the spans of the
18381891
/// errors to more accurately point at the cause of the failure.
18391892
///

compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt a
1919
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
2020
use rustc_errors::{
2121
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
22-
MultiSpan, Style,
22+
MultiSpan, StashKey, Style,
2323
};
2424
use rustc_hir as hir;
2525
use rustc_hir::def::Namespace;
@@ -2236,14 +2236,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
22362236
// begin with in those cases.
22372237
if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
22382238
if let None = self.tainted_by_errors() {
2239-
self.emit_inference_failure_err(
2239+
let err = self.emit_inference_failure_err(
22402240
obligation.cause.body_id,
22412241
span,
22422242
trait_ref.self_ty().skip_binder().into(),
22432243
ErrorCode::E0282,
22442244
false,
2245-
)
2246-
.emit();
2245+
);
2246+
err.stash(span, StashKey::MaybeForgetReturn);
22472247
}
22482248
return;
22492249
}

tests/ui/error-codes/E0401.stderr

+11-11
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,6 @@ LL | fn helper(sel: &Self) -> u8 {
3232
| use of generic parameter from outer function
3333
| use a type here instead
3434

35-
error[E0282]: type annotations needed
36-
--> $DIR/E0401.rs:11:5
37-
|
38-
LL | bfnr(x);
39-
| ^^^^ cannot infer type of the type parameter `U` declared on the function `bfnr`
40-
|
41-
help: consider specifying the generic arguments
42-
|
43-
LL | bfnr::<U, V, W>(x);
44-
| +++++++++++
45-
4635
error[E0283]: type annotations needed
4736
--> $DIR/E0401.rs:11:5
4837
|
@@ -64,6 +53,17 @@ help: consider specifying the generic arguments
6453
LL | bfnr::<U, V, W>(x);
6554
| +++++++++++
6655

56+
error[E0282]: type annotations needed
57+
--> $DIR/E0401.rs:11:5
58+
|
59+
LL | bfnr(x);
60+
| ^^^^ cannot infer type of the type parameter `U` declared on the function `bfnr`
61+
|
62+
help: consider specifying the generic arguments
63+
|
64+
LL | bfnr::<U, V, W>(x);
65+
| +++++++++++
66+
6767
error: aborting due to 5 previous errors
6868

6969
Some errors have detailed explanations: E0282, E0283, E0401.

tests/ui/inference/issue-72690.stderr

+11-11
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,6 @@ help: try using a fully qualified path to specify the expected types
2424
LL | String::from(<str as AsRef<T>>::as_ref("x"));
2525
| ++++++++++++++++++++++++++ ~
2626

27-
error[E0282]: type annotations needed
28-
--> $DIR/issue-72690.rs:12:6
29-
|
30-
LL | |x| String::from("x".as_ref());
31-
| ^
32-
|
33-
help: consider giving this closure parameter an explicit type
34-
|
35-
LL | |x: /* Type */| String::from("x".as_ref());
36-
| ++++++++++++
37-
3827
error[E0283]: type annotations needed
3928
--> $DIR/issue-72690.rs:12:26
4029
|
@@ -51,6 +40,17 @@ help: try using a fully qualified path to specify the expected types
5140
LL | |x| String::from(<str as AsRef<T>>::as_ref("x"));
5241
| ++++++++++++++++++++++++++ ~
5342

43+
error[E0282]: type annotations needed
44+
--> $DIR/issue-72690.rs:12:6
45+
|
46+
LL | |x| String::from("x".as_ref());
47+
| ^
48+
|
49+
help: consider giving this closure parameter an explicit type
50+
|
51+
LL | |x: /* Type */| String::from("x".as_ref());
52+
| ++++++++++++
53+
5454
error[E0283]: type annotations needed for `&T`
5555
--> $DIR/issue-72690.rs:17:9
5656
|
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
struct MyError;
2+
3+
fn foo(x: bool) -> Result<(), MyError> {
4+
if x {
5+
Err(MyError);
6+
//~^ ERROR type annotations needed
7+
}
8+
9+
Ok(())
10+
}
11+
12+
fn bar(x: bool) -> Result<(), MyError> {
13+
if x {
14+
Ok(());
15+
//~^ ERROR type annotations needed
16+
}
17+
18+
Ok(())
19+
}
20+
21+
fn baz(x: bool) -> Result<(), MyError> {
22+
//~^ ERROR mismatched types
23+
if x {
24+
1;
25+
}
26+
27+
Err(MyError);
28+
}
29+
30+
fn error() -> Result<(), MyError> {
31+
Err(MyError)
32+
}
33+
34+
fn bak(x: bool) -> Result<(), MyError> {
35+
if x {
36+
//~^ ERROR mismatched types
37+
error();
38+
} else {
39+
//~^ ERROR mismatched types
40+
error();
41+
}
42+
}
43+
44+
fn bad(x: bool) -> Result<(), MyError> {
45+
Err(MyError); //~ ERROR type annotations needed
46+
Ok(())
47+
}
48+
49+
fn with_closure<F, A, B>(_: F) -> i32
50+
where
51+
F: FnOnce(A, B),
52+
{
53+
0
54+
}
55+
56+
fn a() -> i32 {
57+
with_closure(|x: u32, y| {}); //~ ERROR type annotations needed
58+
0
59+
}
60+
61+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
error[E0282]: type annotations needed
2+
--> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:5:9
3+
|
4+
LL | Err(MyError);
5+
| ^^^ cannot infer type of the type parameter `T` declared on the enum `Result`
6+
|
7+
help: consider specifying the generic arguments
8+
|
9+
LL | Err::<T, MyError>(MyError);
10+
| ++++++++++++++
11+
help: you might have meant to return this to infer its type parameters
12+
|
13+
LL | return Err(MyError);
14+
| ++++++
15+
16+
error[E0282]: type annotations needed
17+
--> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:14:9
18+
|
19+
LL | Ok(());
20+
| ^^ cannot infer type of the type parameter `E` declared on the enum `Result`
21+
|
22+
help: consider specifying the generic arguments
23+
|
24+
LL | Ok::<(), E>(());
25+
| +++++++++
26+
help: you might have meant to return this to infer its type parameters
27+
|
28+
LL | return Ok(());
29+
| ++++++
30+
31+
error[E0308]: mismatched types
32+
--> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:21:20
33+
|
34+
LL | fn baz(x: bool) -> Result<(), MyError> {
35+
| --- ^^^^^^^^^^^^^^^^^^^ expected `Result<(), MyError>`, found `()`
36+
| |
37+
| implicitly returns `()` as its body has no tail or `return` expression
38+
...
39+
LL | Err(MyError);
40+
| - help: remove this semicolon to return this value
41+
|
42+
= note: expected enum `Result<(), MyError>`
43+
found unit type `()`
44+
45+
error[E0308]: mismatched types
46+
--> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:35:10
47+
|
48+
LL | if x {
49+
| __________^
50+
LL | |
51+
LL | | error();
52+
| | - help: remove this semicolon to return this value
53+
LL | | } else {
54+
| |_____^ expected `Result<(), MyError>`, found `()`
55+
|
56+
= note: expected enum `Result<(), MyError>`
57+
found unit type `()`
58+
59+
error[E0308]: mismatched types
60+
--> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:38:12
61+
|
62+
LL | } else {
63+
| ____________^
64+
LL | |
65+
LL | | error();
66+
| | - help: remove this semicolon to return this value
67+
LL | | }
68+
| |_____^ expected `Result<(), MyError>`, found `()`
69+
|
70+
= note: expected enum `Result<(), MyError>`
71+
found unit type `()`
72+
73+
error[E0282]: type annotations needed
74+
--> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:45:5
75+
|
76+
LL | Err(MyError);
77+
| ^^^ cannot infer type of the type parameter `T` declared on the enum `Result`
78+
|
79+
help: consider specifying the generic arguments
80+
|
81+
LL | Err::<T, MyError>(MyError);
82+
| ++++++++++++++
83+
84+
error[E0282]: type annotations needed
85+
--> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:57:27
86+
|
87+
LL | with_closure(|x: u32, y| {});
88+
| ^
89+
|
90+
help: consider giving this closure parameter an explicit type
91+
|
92+
LL | with_closure(|x: u32, y: /* Type */| {});
93+
| ++++++++++++
94+
95+
error: aborting due to 7 previous errors
96+
97+
Some errors have detailed explanations: E0282, E0308.
98+
For more information about an error, try `rustc --explain E0282`.

tests/ui/methods/method-ambig-one-trait-unknown-int-type.stderr

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,3 @@
1-
error[E0282]: type annotations needed for `Vec<T>`
2-
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:9
3-
|
4-
LL | let mut x = Vec::new();
5-
| ^^^^^
6-
|
7-
help: consider giving `x` an explicit type, where the type for type parameter `T` is specified
8-
|
9-
LL | let mut x: Vec<T> = Vec::new();
10-
| ++++++++
11-
121
error[E0283]: type annotations needed
132
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:26:7
143
|
@@ -28,6 +17,17 @@ help: try using a fully qualified path to specify the expected types
2817
LL | <Vec<T> as Foo>::foo(&x);
2918
| ++++++++++++++++++++++ ~
3019

20+
error[E0282]: type annotations needed for `Vec<T>`
21+
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:9
22+
|
23+
LL | let mut x = Vec::new();
24+
| ^^^^^
25+
|
26+
help: consider giving `x` an explicit type, where the type for type parameter `T` is specified
27+
|
28+
LL | let mut x: Vec<T> = Vec::new();
29+
| ++++++++
30+
3131
error[E0308]: mismatched types
3232
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:33:20
3333
|

0 commit comments

Comments
 (0)