From 22d4631ee174d8babc320cb8812dccfe5df5803a Mon Sep 17 00:00:00 2001 From: yukang Date: Tue, 13 Feb 2024 21:29:45 +0800 Subject: [PATCH 1/2] Add hint to correct Vec::append into Vec::push when the wrong method is used --- .../src/infer/error_reporting/mod.rs | 1 + .../src/infer/error_reporting/suggest.rs | 55 +++++++++++++++++++ .../ui/inference/issue-87212-suggest-push.rs | 20 +++++++ .../inference/issue-87212-suggest-push.stderr | 50 +++++++++++++++++ 4 files changed, 126 insertions(+) create mode 100644 tests/ui/inference/issue-87212-suggest-push.rs create mode 100644 tests/ui/inference/issue-87212-suggest-push.stderr diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 4d2d19b51e22c..d6fe87e6c48b4 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2005,6 +2005,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag); self.suggest_await_on_expect_found(cause, span, &exp_found, diag); self.suggest_function_pointers(cause, span, &exp_found, diag); + self.suggest_push_for_append(cause, span, &exp_found, diag); } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 248e1c0fcc878..c2cd13e78c443 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -289,6 +289,61 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } + pub(super) fn suggest_push_for_append( + &self, + cause: &ObligationCause<'tcx>, + span: Span, + exp_found: &ty::error::ExpectedFound>, + diag: &mut Diagnostic, + ) { + let ty::error::ExpectedFound { expected: _, found } = exp_found; + let body = if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(cause.body_id) { + self.tcx.hir().body(body_id) + } else { + return; + }; + + struct MethodCallVisitor<'tcx> { + pub method: Option, + pub recv: Option<&'tcx hir::Expr<'tcx>>, + pub err_span: Span, + } + + impl<'v> Visitor<'v> for MethodCallVisitor<'v> { + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + if let hir::ExprKind::MethodCall(method, recv, args, _) = ex.kind { + if args.len() == 1 + && args[0].span.eq(&self.err_span) + && method.ident.name.as_str() == "append" + { + self.method = Some(method.ident.span); + self.recv = Some(recv); + } + } + walk_expr(self, ex); + } + } + + let mut finder = MethodCallVisitor { method: None, err_span: span, recv: None }; + finder.visit_body(body); + + if let Some(typecheck) = self.typeck_results.as_ref() + && let Some(method_call) = finder.method + && let Some(vec_def_id) = self.tcx.get_diagnostic_item(sym::Vec) + && let Some(recv_ty) = finder.recv.and_then(|recv| typecheck.expr_ty_opt(recv)) + && let ty::Adt(def, _) = recv_ty.kind() + && def.did() == vec_def_id + && (recv_ty.contains(*found) || recv_ty.has_infer_types()) + { + diag.span_suggestion_verbose( + method_call, + "you might want to use `push` to add new element to `Vec`", + "push", + Applicability::MaybeIncorrect, + ); + } + } + pub(super) fn suggest_function_pointers( &self, cause: &ObligationCause<'tcx>, diff --git a/tests/ui/inference/issue-87212-suggest-push.rs b/tests/ui/inference/issue-87212-suggest-push.rs new file mode 100644 index 0000000000000..5bed8cd7beaed --- /dev/null +++ b/tests/ui/inference/issue-87212-suggest-push.rs @@ -0,0 +1,20 @@ +struct Thing; +fn t1() { + let mut stuff: Vec = Vec::new(); + // suggest push + stuff.append(Thing); //~ ERROR mismatched types +} + +fn t2() { + let mut stuff = vec![]; + // suggest push + stuff.append(Thing); //~ ERROR mismatched types +} + +fn t3() { + let mut stuff: Vec = Vec::new(); + // don't suggest push + stuff.append(Thing); //~ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/inference/issue-87212-suggest-push.stderr b/tests/ui/inference/issue-87212-suggest-push.stderr new file mode 100644 index 0000000000000..2bb909013ffd7 --- /dev/null +++ b/tests/ui/inference/issue-87212-suggest-push.stderr @@ -0,0 +1,50 @@ +error[E0308]: mismatched types + --> $DIR/issue-87212-suggest-push.rs:5:18 + | +LL | stuff.append(Thing); + | ------ ^^^^^ expected `&mut Vec`, found `Thing` + | | + | arguments to this method are incorrect + | + = note: expected mutable reference `&mut Vec` + found struct `Thing` +note: method defined here + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL +help: you might want to use `push` to add new element to `Vec` + | +LL | stuff.push(Thing); + | ~~~~ + +error[E0308]: mismatched types + --> $DIR/issue-87212-suggest-push.rs:11:18 + | +LL | stuff.append(Thing); + | ------ ^^^^^ expected `&mut Vec<_>`, found `Thing` + | | + | arguments to this method are incorrect + | + = note: expected mutable reference `&mut Vec<_>` + found struct `Thing` +note: method defined here + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL +help: you might want to use `push` to add new element to `Vec` + | +LL | stuff.push(Thing); + | ~~~~ + +error[E0308]: mismatched types + --> $DIR/issue-87212-suggest-push.rs:17:18 + | +LL | stuff.append(Thing); + | ------ ^^^^^ expected `&mut Vec`, found `Thing` + | | + | arguments to this method are incorrect + | + = note: expected mutable reference `&mut Vec` + found struct `Thing` +note: method defined here + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. From 581722a98a799dfd784b29ec709905dafdff5216 Mon Sep 17 00:00:00 2001 From: yukang Date: Tue, 13 Feb 2024 21:45:13 +0800 Subject: [PATCH 2/2] remove useless visity_body --- compiler/rustc_infer/src/infer/error_reporting/suggest.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index c2cd13e78c443..23349547325e3 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -559,10 +559,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } walk_stmt(self, ex); } - - fn visit_body(&mut self, body: &'v hir::Body<'v>) { - hir::intravisit::walk_body(self, body); - } } let mut visitor = IfVisitor { err_span: span, found_if: false, result: false };