diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 53bf38c0a340f..c436c4ff1f1af 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -3307,6 +3307,46 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { seen_requirements, ) }); + + let node = self.tcx.hir().get(self.tcx.hir().local_def_id_to_hir_id(body_id)); + if let hir::Node::Item(item) = node && + let hir::ItemKind::Fn(.., body_id) = item.kind && + let body_node = self.tcx.hir().get(body_id.hir_id) && + let hir::Node::Expr(expr) = body_node && + let hir::ExprKind::Block(block, _) = expr.kind && + let Some(ret) = block.expr && + let hir::ExprKind::MethodCall(path, expr, [fn_expr], map_sp) = ret.kind && + path.ident.name.as_str() == "map" && + let hir::ExprKind::MethodCall(path, vec_expr, _, iter_mut_sp) = expr.kind && + path.ident.name.as_str() == "iter_mut" && + let hir::ExprKind::Path(qpath) = fn_expr.kind && + let hir::QPath::Resolved(_, path) = qpath && + let hir::def::Res::Def(def_kind, def_id) = path.res && + matches!(def_kind, hir::def::DefKind::Fn) + { + let fn_ty = self.tcx.fn_sig(def_id).skip_binder(); + let ret_ty = fn_ty.output().skip_binder(); + if ret_ty.is_unit() || ret_ty.is_never() { + if let hir::ExprKind::Call(expr, _) = vec_expr.kind && + let hir::ExprKind::Path(qpath) = expr.kind && + let hir::QPath::TypeRelative(ty, _) = qpath { + err.note("the method call chain might not have had the expected associated types"); + // todo: ty as string + err.span_label(ty.span, "this expression has type ``"); + err.span_label(map_sp, format!("`Iterator::Item` changed to `{}` here", ret_ty)); + // todo: method call type for iter_mut + err.span_label(iter_mut_sp, "`Iterator::Item` is `` here"); + } else if let hir::ExprKind::Path(qpath) = vec_expr.kind && + let hir::QPath::Resolved(_, path) = qpath && + let hir::def::Res::Local(_id) = path.res { + err.note("the method call chain might not have had the expected associated types"); + // todo: get span of `x` and make sure `x` is vec + err.span_label(map_sp, format!("`Iterator::Item` changed to `{}` here", ret_ty)); + // todo: method call type for iter_mut + err.span_label(iter_mut_sp, "`Iterator::Item` is `` here"); + } + } + } } ObligationCauseCode::DerivedObligation(ref data) => { let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); diff --git a/tests/ui/iterators/issue-106993.rs b/tests/ui/iterators/issue-106993.rs new file mode 100644 index 0000000000000..08851b318b83b --- /dev/null +++ b/tests/ui/iterators/issue-106993.rs @@ -0,0 +1,19 @@ +fn foo(items: &mut Vec) { + items.sort(); +} + +fn bar() -> impl Iterator { + //~^ ERROR expected `foo` to be a fn item that returns `i32`, but it returns `()` [E0271] + let mut x: Vec> = vec![vec![0, 2, 1], vec![5, 4, 3]]; + x.iter_mut().map(foo) +} + +fn bar2() -> impl Iterator { + //~^ ERROR expected `foo` to be a fn item that returns `i32`, but it returns `()` [E0271] + vec![vec![0, 2, 1], vec![5, 4, 3]].iter_mut().map(foo) +} + +fn main() { + bar(); + bar2(); +} diff --git a/tests/ui/iterators/issue-106993.stderr b/tests/ui/iterators/issue-106993.stderr new file mode 100644 index 0000000000000..ff651fa8aace1 --- /dev/null +++ b/tests/ui/iterators/issue-106993.stderr @@ -0,0 +1,32 @@ +error[E0271]: expected `foo` to be a fn item that returns `i32`, but it returns `()` + --> $DIR/issue-106993.rs:5:13 + | +LL | fn bar() -> impl Iterator { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `i32` +... +LL | x.iter_mut().map(foo) + | ---------- -------- `Iterator::Item` changed to `()` here + | | + | `Iterator::Item` is `` here + | + = note: required for `Map>, for<'a> fn(&'a mut Vec) {foo}>` to implement `Iterator` + = note: the method call chain might not have had the expected associated types + +error[E0271]: expected `foo` to be a fn item that returns `i32`, but it returns `()` + --> $DIR/issue-106993.rs:11:14 + | +LL | fn bar2() -> impl Iterator { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `i32` +LL | +LL | vec![vec![0, 2, 1], vec![5, 4, 3]].iter_mut().map(foo) + | ---------------------------------- ---------- -------- `Iterator::Item` changed to `()` here + | | | + | | `Iterator::Item` is `` here + | this expression has type `` + | + = note: required for `Map>, for<'a> fn(&'a mut Vec) {foo}>` to implement `Iterator` + = note: the method call chain might not have had the expected associated types + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/lint/issue-106991.stderr b/tests/ui/lint/issue-106991.stderr index 7b43f0b2ca8f3..ad196a69b9aa1 100644 --- a/tests/ui/lint/issue-106991.stderr +++ b/tests/ui/lint/issue-106991.stderr @@ -3,8 +3,14 @@ error[E0271]: expected `foo` to be a fn item that returns `i32`, but it returns | LL | fn bar() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `i32` +... +LL | x.iter_mut().map(foo) + | ---------- -------- `Iterator::Item` changed to `()` here + | | + | `Iterator::Item` is `` here | = note: required for `Map>, for<'a> fn(&'a mut Vec) {foo}>` to implement `Iterator` + = note: the method call chain might not have had the expected associated types error: aborting due to previous error