From a3db47ab6c976137a26976d5c8060e7eadc05232 Mon Sep 17 00:00:00 2001 From: Kevin Per Date: Tue, 9 Feb 2021 17:18:28 +0000 Subject: [PATCH] Add suggestion for iterators in iterators --- .../diagnostics/conflict_errors.rs | 33 ++++++++++++++++--- library/core/src/iter/traits/iterator.rs | 1 + src/test/ui/issues/issue-81584.fixed | 8 +++++ src/test/ui/issues/issue-81584.rs | 8 +++++ src/test/ui/issues/issue-81584.stderr | 14 ++++++++ .../ui/static/static-reference-to-fn-2.stderr | 2 ++ 6 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/issues/issue-81584.fixed create mode 100644 src/test/ui/issues/issue-81584.rs create mode 100644 src/test/ui/issues/issue-81584.stderr diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index b0b58a8d003..24b9408ffb6 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -10,16 +10,18 @@ use rustc_middle::mir::{ FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm, }; -use rustc_middle::ty::{self, suggest_constraining_type_param, Instance, Ty}; -use rustc_span::{source_map::DesugaringKind, symbol::sym, Span}; +use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TypeFoldable}; +use rustc_span::source_map::DesugaringKind; +use rustc_span::symbol::sym; +use rustc_span::Span; use crate::dataflow::drop_flag_effects; use crate::dataflow::indexes::{MoveOutIndex, MovePathIndex}; use crate::util::borrowck_errors; use crate::borrow_check::{ - borrow_set::BorrowData, prefixes::IsPrefixOf, InitializationRequiringAction, MirBorrowckCtxt, - PrefixSet, WriteKind, + borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf, + InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind, }; use super::{ @@ -1267,6 +1269,29 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if return_span != borrow_span { err.span_label(borrow_span, note); + + let tcx = self.infcx.tcx; + let ty_params = ty::List::empty(); + + let return_ty = self.regioncx.universal_regions().unnormalized_output_ty; + let return_ty = tcx.erase_regions(return_ty); + + // to avoid panics + if !return_ty.has_infer_types() { + if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) { + if tcx.type_implements_trait((iter_trait, return_ty, ty_params, self.param_env)) + { + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) { + err.span_suggestion_hidden( + return_span, + "use `.collect()` to allocate the iterator", + format!("{}{}", snippet, ".collect::>()"), + Applicability::MaybeIncorrect, + ); + } + } + } + } } Some(err) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index f28c4673cc0..e179ce01c41 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -93,6 +93,7 @@ fn _assert_is_object_safe(_: &dyn Iterator) {} message = "`{Self}` is not an iterator" )] #[doc(spotlight)] +#[rustc_diagnostic_item = "Iterator"] #[must_use = "iterators are lazy and do nothing unless consumed"] pub trait Iterator { /// The type of the elements being iterated over. diff --git a/src/test/ui/issues/issue-81584.fixed b/src/test/ui/issues/issue-81584.fixed new file mode 100644 index 00000000000..1cad59f1062 --- /dev/null +++ b/src/test/ui/issues/issue-81584.fixed @@ -0,0 +1,8 @@ +// run-rustfix +fn main() { + let _ = vec![vec![0, 1], vec![2]] + .into_iter() + .map(|y| y.iter().map(|x| x + 1).collect::>()) + //~^ ERROR cannot return value referencing function parameter `y` + .collect::>(); +} diff --git a/src/test/ui/issues/issue-81584.rs b/src/test/ui/issues/issue-81584.rs new file mode 100644 index 00000000000..452288db08b --- /dev/null +++ b/src/test/ui/issues/issue-81584.rs @@ -0,0 +1,8 @@ +// run-rustfix +fn main() { + let _ = vec![vec![0, 1], vec![2]] + .into_iter() + .map(|y| y.iter().map(|x| x + 1)) + //~^ ERROR cannot return value referencing function parameter `y` + .collect::>(); +} diff --git a/src/test/ui/issues/issue-81584.stderr b/src/test/ui/issues/issue-81584.stderr new file mode 100644 index 00000000000..d57f1b778df --- /dev/null +++ b/src/test/ui/issues/issue-81584.stderr @@ -0,0 +1,14 @@ +error[E0515]: cannot return value referencing function parameter `y` + --> $DIR/issue-81584.rs:5:22 + | +LL | .map(|y| y.iter().map(|x| x + 1)) + | -^^^^^^^^^^^^^^^^^^^^^^ + | | + | returns a value referencing data owned by the current function + | `y` is borrowed here + | + = help: use `.collect()` to allocate the iterator + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/static/static-reference-to-fn-2.stderr b/src/test/ui/static/static-reference-to-fn-2.stderr index 028e11a60ce..ff15884bd44 100644 --- a/src/test/ui/static/static-reference-to-fn-2.stderr +++ b/src/test/ui/static/static-reference-to-fn-2.stderr @@ -40,6 +40,8 @@ LL | | statefn: &id(state1 as StateMachineFunc) | | ------------------------------ temporary value created here LL | | } | |_____^ returns a value referencing data owned by the current function + | + = help: use `.collect()` to allocate the iterator error: aborting due to 4 previous errors