From 6a17ee6d4125c0c35147b16ebcf54e34f0cdc87a Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 29 Jul 2021 23:23:17 -0700 Subject: [PATCH] Recommend fix `count()` -> `len()` on slices Fixes #87302 --- compiler/rustc_span/src/symbol.rs | 1 + .../rustc_typeck/src/check/method/suggest.rs | 26 ++++++++++++-- src/test/ui/suggestions/count2len.rs | 8 +++++ src/test/ui/suggestions/count2len.stderr | 36 +++++++++++++++++++ 4 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/suggestions/count2len.rs create mode 100644 src/test/ui/suggestions/count2len.stderr diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 0d556b5eda609..adce8da91a3a8 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -496,6 +496,7 @@ symbols! { core_panic_macro, cosf32, cosf64, + count, cr, crate_id, crate_in_paths, diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index ca174ed5e8497..ad38885dbd8bd 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -67,6 +67,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn is_slice_ty(&self, ty: Ty<'tcx>, span: Span) -> bool { + self.autoderef(span, ty).any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..))) + } + pub fn report_method_error( &self, mut span: Span, @@ -691,7 +695,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut restrict_type_params = false; let mut unsatisfied_bounds = false; - if !unsatisfied_predicates.is_empty() { + if item_name.name == sym::count && self.is_slice_ty(actual, span) { + let msg = "consider using `len` instead"; + if let SelfSource::MethodCall(_expr) = source { + err.span_suggestion_short( + span, + msg, + String::from("len"), + Applicability::MachineApplicable, + ); + } else { + err.span_label(span, msg); + } + if let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) { + let iterator_trait = self.tcx.def_path_str(iterator_trait); + err.note(&format!("`count` is defined on `{iterator_trait}`, which `{actual}` does not implement")); + } + } else if !unsatisfied_predicates.is_empty() { let def_span = |def_id| { self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id)) }; @@ -990,9 +1010,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let mut fallback_span = true; - let msg = "remove this method call"; if item_name.name == sym::as_str && actual.peel_refs().is_str() { + let msg = "remove this method call"; + let mut fallback_span = true; if let SelfSource::MethodCall(expr) = source { let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)); diff --git a/src/test/ui/suggestions/count2len.rs b/src/test/ui/suggestions/count2len.rs new file mode 100644 index 0000000000000..f11a789efbc5b --- /dev/null +++ b/src/test/ui/suggestions/count2len.rs @@ -0,0 +1,8 @@ +fn main() { + let slice = [1,2,3,4]; + let vec = vec![1,2,3,4]; + + slice.count(); //~ERROR: E0599 + vec.count(); //~ERROR: E0599 + vec.as_slice().count(); //~ERROR: E0599 +} diff --git a/src/test/ui/suggestions/count2len.stderr b/src/test/ui/suggestions/count2len.stderr new file mode 100644 index 0000000000000..6394a84dd47e1 --- /dev/null +++ b/src/test/ui/suggestions/count2len.stderr @@ -0,0 +1,36 @@ +error[E0599]: no method named `count` found for array `[{integer}; 4]` in the current scope + --> $DIR/count2len.rs:5:11 + | +LL | slice.count(); + | ^^^^^ + | | + | method cannot be called on `[{integer}; 4]` due to unsatisfied trait bounds + | help: consider using `len` instead + | + = note: `count` is defined on `Iterator`, which `[{integer}; 4]` does not implement + +error[E0599]: no method named `count` found for struct `Vec<{integer}>` in the current scope + --> $DIR/count2len.rs:6:9 + | +LL | vec.count(); + | ^^^^^ + | | + | method cannot be called on `Vec<{integer}>` due to unsatisfied trait bounds + | help: consider using `len` instead + | + = note: `count` is defined on `Iterator`, which `Vec<{integer}>` does not implement + +error[E0599]: no method named `count` found for reference `&[{integer}]` in the current scope + --> $DIR/count2len.rs:7:20 + | +LL | vec.as_slice().count(); + | ^^^^^ + | | + | method cannot be called on `&[{integer}]` due to unsatisfied trait bounds + | help: consider using `len` instead + | + = note: `count` is defined on `Iterator`, which `&[{integer}]` does not implement + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0599`.