Skip to content

Commit

Permalink
Suggest adding return if the type of unused semi return value can c…
Browse files Browse the repository at this point in the history
…oerce to the fn return type
  • Loading branch information
chenyukang committed Sep 3, 2023
1 parent 9f5fc1b commit f0c6f00
Show file tree
Hide file tree
Showing 17 changed files with 333 additions and 119 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_errors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,7 @@ pub enum StashKey {
CallAssocMethod,
TraitMissingMethod,
OpaqueHiddenTypeMismatch,
MaybeForgetReturn,
}

fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if !errors.is_empty() {
self.adjust_fulfillment_errors_for_expr_obligation(&mut errors);
self.err_ctxt().report_fulfillment_errors(&errors);
self.collect_unused_for_coerce_return_ty(&mut errors);
}
}

Expand Down
55 changes: 54 additions & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
use rustc_ast as ast;
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{
pluralize, Applicability, Diagnostic, DiagnosticId, ErrorGuaranteed, MultiSpan,
pluralize, Applicability, Diagnostic, DiagnosticId, ErrorGuaranteed, MultiSpan, StashKey,
};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
Expand All @@ -26,6 +26,7 @@ use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::TypeTrace;
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
use rustc_middle::traits::ObligationCauseCode::ExprBindingObligation;
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::{self, IsSuggestable, Ty};
Expand Down Expand Up @@ -1834,6 +1835,58 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}

pub(super) fn collect_unused_for_coerce_return_ty(
&self,
errors: &[traits::FulfillmentError<'tcx>],
) {
for fillment_error in &*errors {
let obligation = &fillment_error.obligation;
let span = obligation.cause.span;

let Some(mut diag) =
self.tcx.sess.diagnostic().steal_diagnostic(span, StashKey::MaybeForgetReturn)
else {
continue;
};

let root_obligation = &fillment_error.root_obligation;
if let Some(fn_sig) = self.body_fn_sig()
&& let ExprBindingObligation(_, _, hir_id, ..) = root_obligation.cause.code()
&& !fn_sig.output().is_unit() {
let mut block_num = 0;
let mut found_semi = false;
for (_, node) in self.tcx.hir().parent_iter(*hir_id) {
match node {
hir::Node::Stmt(stmt) => if let hir::StmtKind::Semi(ref expr) = stmt.kind {
let expr_ty = self.typeck_results.borrow().expr_ty(expr);
let return_ty = fn_sig.output();
if !matches!(expr.kind, hir::ExprKind::Ret(..)) &&
self.can_coerce(expr_ty, return_ty) {
found_semi = true;
}
},
hir::Node::Block(_block) => if found_semi {
block_num += 1;
}
hir::Node::Item(item) => if let hir::ItemKind::Fn(..) = item.kind {
break;
}
_ => {}
}
}
if block_num > 1 && found_semi {
diag.span_suggestion_verbose(
span.shrink_to_lo(),
"you might have meant to return this to infer its type parameters",
"return ",
Applicability::MaybeIncorrect,
);
}
}
diag.emit();
}
}

/// Given a vector of fulfillment errors, try to adjust the spans of the
/// errors to more accurately point at the cause of the failure.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt a
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
MultiSpan, Style,
MultiSpan, StashKey, Style,
};
use rustc_hir as hir;
use rustc_hir::def::Namespace;
Expand Down Expand Up @@ -2236,14 +2236,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// begin with in those cases.
if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
if let None = self.tainted_by_errors() {
self.emit_inference_failure_err(
let err = self.emit_inference_failure_err(
obligation.cause.body_id,
span,
trait_ref.self_ty().skip_binder().into(),
ErrorCode::E0282,
false,
)
.emit();
);
err.stash(span, StashKey::MaybeForgetReturn);
}
return;
}
Expand Down
22 changes: 11 additions & 11 deletions tests/ui/error-codes/E0401.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,6 @@ LL | fn helper(sel: &Self) -> u8 {
| use of generic parameter from outer function
| use a type here instead

error[E0282]: type annotations needed
--> $DIR/E0401.rs:11:5
|
LL | bfnr(x);
| ^^^^ cannot infer type of the type parameter `U` declared on the function `bfnr`
|
help: consider specifying the generic arguments
|
LL | bfnr::<U, V, W>(x);
| +++++++++++

error[E0283]: type annotations needed
--> $DIR/E0401.rs:11:5
|
Expand All @@ -64,6 +53,17 @@ help: consider specifying the generic arguments
LL | bfnr::<U, V, W>(x);
| +++++++++++

error[E0282]: type annotations needed
--> $DIR/E0401.rs:11:5
|
LL | bfnr(x);
| ^^^^ cannot infer type of the type parameter `U` declared on the function `bfnr`
|
help: consider specifying the generic arguments
|
LL | bfnr::<U, V, W>(x);
| +++++++++++

error: aborting due to 5 previous errors

Some errors have detailed explanations: E0282, E0283, E0401.
Expand Down
22 changes: 11 additions & 11 deletions tests/ui/inference/issue-72690.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,6 @@ help: try using a fully qualified path to specify the expected types
LL | String::from(<str as AsRef<T>>::as_ref("x"));
| ++++++++++++++++++++++++++ ~

error[E0282]: type annotations needed
--> $DIR/issue-72690.rs:12:6
|
LL | |x| String::from("x".as_ref());
| ^
|
help: consider giving this closure parameter an explicit type
|
LL | |x: /* Type */| String::from("x".as_ref());
| ++++++++++++

error[E0283]: type annotations needed
--> $DIR/issue-72690.rs:12:26
|
Expand All @@ -51,6 +40,17 @@ help: try using a fully qualified path to specify the expected types
LL | |x| String::from(<str as AsRef<T>>::as_ref("x"));
| ++++++++++++++++++++++++++ ~

error[E0282]: type annotations needed
--> $DIR/issue-72690.rs:12:6
|
LL | |x| String::from("x".as_ref());
| ^
|
help: consider giving this closure parameter an explicit type
|
LL | |x: /* Type */| String::from("x".as_ref());
| ++++++++++++

error[E0283]: type annotations needed for `&T`
--> $DIR/issue-72690.rs:17:9
|
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
struct MyError;

fn foo(x: bool) -> Result<(), MyError> {
if x {
Err(MyError);
//~^ ERROR type annotations needed
}

Ok(())
}

fn bar(x: bool) -> Result<(), MyError> {
if x {
Ok(());
//~^ ERROR type annotations needed
}

Ok(())
}

fn baz(x: bool) -> Result<(), MyError> {
//~^ ERROR mismatched types
if x {
1;
}

Err(MyError);
}

fn error() -> Result<(), MyError> {
Err(MyError)
}

fn bak(x: bool) -> Result<(), MyError> {
if x {
//~^ ERROR mismatched types
error();
} else {
//~^ ERROR mismatched types
error();
}
}

fn bad(x: bool) -> Result<(), MyError> {
Err(MyError); //~ ERROR type annotations needed
Ok(())
}

fn with_closure<F, A, B>(_: F) -> i32
where
F: FnOnce(A, B),
{
0
}

fn a() -> i32 {
with_closure(|x: u32, y| {}); //~ ERROR type annotations needed
0
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
error[E0282]: type annotations needed
--> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:5:9
|
LL | Err(MyError);
| ^^^ cannot infer type of the type parameter `T` declared on the enum `Result`
|
help: consider specifying the generic arguments
|
LL | Err::<T, MyError>(MyError);
| ++++++++++++++
help: you might have meant to return this to infer its type parameters
|
LL | return Err(MyError);
| ++++++

error[E0282]: type annotations needed
--> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:14:9
|
LL | Ok(());
| ^^ cannot infer type of the type parameter `E` declared on the enum `Result`
|
help: consider specifying the generic arguments
|
LL | Ok::<(), E>(());
| +++++++++
help: you might have meant to return this to infer its type parameters
|
LL | return Ok(());
| ++++++

error[E0308]: mismatched types
--> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:21:20
|
LL | fn baz(x: bool) -> Result<(), MyError> {
| --- ^^^^^^^^^^^^^^^^^^^ expected `Result<(), MyError>`, found `()`
| |
| implicitly returns `()` as its body has no tail or `return` expression
...
LL | Err(MyError);
| - help: remove this semicolon to return this value
|
= note: expected enum `Result<(), MyError>`
found unit type `()`

error[E0308]: mismatched types
--> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:35:10
|
LL | if x {
| __________^
LL | |
LL | | error();
| | - help: remove this semicolon to return this value
LL | | } else {
| |_____^ expected `Result<(), MyError>`, found `()`
|
= note: expected enum `Result<(), MyError>`
found unit type `()`

error[E0308]: mismatched types
--> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:38:12
|
LL | } else {
| ____________^
LL | |
LL | | error();
| | - help: remove this semicolon to return this value
LL | | }
| |_____^ expected `Result<(), MyError>`, found `()`
|
= note: expected enum `Result<(), MyError>`
found unit type `()`

error[E0282]: type annotations needed
--> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:45:5
|
LL | Err(MyError);
| ^^^ cannot infer type of the type parameter `T` declared on the enum `Result`
|
help: consider specifying the generic arguments
|
LL | Err::<T, MyError>(MyError);
| ++++++++++++++

error[E0282]: type annotations needed
--> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:57:27
|
LL | with_closure(|x: u32, y| {});
| ^
|
help: consider giving this closure parameter an explicit type
|
LL | with_closure(|x: u32, y: /* Type */| {});
| ++++++++++++

error: aborting due to 7 previous errors

Some errors have detailed explanations: E0282, E0308.
For more information about an error, try `rustc --explain E0282`.
22 changes: 11 additions & 11 deletions tests/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
Original file line number Diff line number Diff line change
@@ -1,14 +1,3 @@
error[E0282]: type annotations needed for `Vec<T>`
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:9
|
LL | let mut x = Vec::new();
| ^^^^^
|
help: consider giving `x` an explicit type, where the type for type parameter `T` is specified
|
LL | let mut x: Vec<T> = Vec::new();
| ++++++++

error[E0283]: type annotations needed
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:26:7
|
Expand All @@ -28,6 +17,17 @@ help: try using a fully qualified path to specify the expected types
LL | <Vec<T> as Foo>::foo(&x);
| ++++++++++++++++++++++ ~

error[E0282]: type annotations needed for `Vec<T>`
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:9
|
LL | let mut x = Vec::new();
| ^^^^^
|
help: consider giving `x` an explicit type, where the type for type parameter `T` is specified
|
LL | let mut x: Vec<T> = Vec::new();
| ++++++++

error[E0308]: mismatched types
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:33:20
|
Expand Down
Loading

0 comments on commit f0c6f00

Please sign in to comment.