diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 9ba92cfa2bdf9..24c9c7dabe5fe 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -2746,6 +2746,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation.param_env, obligation.cause.code(), ); + self.suggest_borrow_for_unsized_closure_return( + obligation.cause.body_id, + err, + obligation.predicate, + ); self.suggest_unsized_bound_if_applicable(err, obligation); if let Some(span) = err.span.primary_span() && let Some(mut diag) = diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 5a5d8af4ce144..e58eb9de04286 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -2193,6 +2193,60 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { false } + pub(super) fn suggest_borrow_for_unsized_closure_return( + &self, + body_id: LocalDefId, + err: &mut Diag<'_, G>, + predicate: ty::Predicate<'tcx>, + ) { + let Some(pred) = predicate.as_trait_clause() else { + return; + }; + if !self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) { + return; + } + + let Some(span) = err.span.primary_span() else { + return; + }; + let Some(node_body_id) = self.tcx.hir_node_by_def_id(body_id).body_id() else { + return; + }; + let body = self.tcx.hir_body(node_body_id); + let mut expr_finder = FindExprBySpan::new(span, self.tcx); + expr_finder.visit_expr(body.value); + let Some(expr) = expr_finder.result else { + return; + }; + + let closure = match expr.kind { + hir::ExprKind::Call(_, args) => args.iter().find_map(|arg| match arg.kind { + hir::ExprKind::Closure(closure) => Some(closure), + _ => None, + }), + hir::ExprKind::MethodCall(_, _, args, _) => { + args.iter().find_map(|arg| match arg.kind { + hir::ExprKind::Closure(closure) => Some(closure), + _ => None, + }) + } + _ => None, + }; + let Some(closure) = closure else { + return; + }; + if !matches!(closure.fn_decl.output, hir::FnRetTy::DefaultReturn(_)) { + return; + } + + err.span_suggestion_verbose( + self.tcx.hir_body(closure.body).value.span.shrink_to_lo(), + "consider borrowing the value", + "&", + Applicability::MaybeIncorrect, + ); + } + pub(super) fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option { let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { sig, .. }, .. }) = self.tcx.hir_node_by_def_id(obligation.cause.body_id) diff --git a/tests/ui/closures/unsized-return-suggest-ref-issue-152064.fixed b/tests/ui/closures/unsized-return-suggest-ref-issue-152064.fixed new file mode 100644 index 0000000000000..343ec57d41e46 --- /dev/null +++ b/tests/ui/closures/unsized-return-suggest-ref-issue-152064.fixed @@ -0,0 +1,20 @@ +#![allow(unused_variables, for_loops_over_fallibles)] +//@ run-rustfix + +fn main() { + // Basic case from the issue: str slice + let o = Some("Hello, world!"); + for s in o.map(|s| &s[3..8]) {} + //~^ ERROR the size for values of type `str` cannot be known at compilation time + //~| ERROR the size for values of type `str` cannot be known at compilation time + //~| ERROR the size for values of type `str` cannot be known at compilation time + //~| ERROR `Option` is not an iterator + + // Byte slice case + let arr = Some(b"Hello, world!"); + for s in arr.map(|s| &s[3..8]) {} + //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time + //~| ERROR the size for values of type `[u8]` cannot be known at compilation time + //~| ERROR the size for values of type `[u8]` cannot be known at compilation time + //~| ERROR `Option<[u8]>` is not an iterator +} diff --git a/tests/ui/closures/unsized-return-suggest-ref-issue-152064.rs b/tests/ui/closures/unsized-return-suggest-ref-issue-152064.rs new file mode 100644 index 0000000000000..7eb4640169548 --- /dev/null +++ b/tests/ui/closures/unsized-return-suggest-ref-issue-152064.rs @@ -0,0 +1,20 @@ +#![allow(unused_variables, for_loops_over_fallibles)] +//@ run-rustfix + +fn main() { + // Basic case from the issue: str slice + let o = Some("Hello, world!"); + for s in o.map(|s| s[3..8]) {} + //~^ ERROR the size for values of type `str` cannot be known at compilation time + //~| ERROR the size for values of type `str` cannot be known at compilation time + //~| ERROR the size for values of type `str` cannot be known at compilation time + //~| ERROR `Option` is not an iterator + + // Byte slice case + let arr = Some(b"Hello, world!"); + for s in arr.map(|s| s[3..8]) {} + //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time + //~| ERROR the size for values of type `[u8]` cannot be known at compilation time + //~| ERROR the size for values of type `[u8]` cannot be known at compilation time + //~| ERROR `Option<[u8]>` is not an iterator +} diff --git a/tests/ui/closures/unsized-return-suggest-ref-issue-152064.stderr b/tests/ui/closures/unsized-return-suggest-ref-issue-152064.stderr new file mode 100644 index 0000000000000..33018fb8a82d4 --- /dev/null +++ b/tests/ui/closures/unsized-return-suggest-ref-issue-152064.stderr @@ -0,0 +1,105 @@ +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/unsized-return-suggest-ref-issue-152064.rs:7:16 + | +LL | for s in o.map(|s| s[3..8]) {} + | ^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` +note: required by an implicit `Sized` bound in `Option::::map` + --> $SRC_DIR/core/src/option.rs:LL:COL + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/unsized-return-suggest-ref-issue-152064.rs:7:24 + | +LL | for s in o.map(|s| s[3..8]) {} + | ^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: the return type of a function must have a statically known size + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/unsized-return-suggest-ref-issue-152064.rs:7:14 + | +LL | for s in o.map(|s| s[3..8]) {} + | ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` +note: required by an implicit `Sized` bound in `Option` + --> $SRC_DIR/core/src/option.rs:LL:COL +help: consider borrowing the value + | +LL | for s in o.map(|s| &s[3..8]) {} + | + + +error[E0277]: `Option` is not an iterator + --> $DIR/unsized-return-suggest-ref-issue-152064.rs:7:14 + | +LL | for s in o.map(|s| s[3..8]) {} + | ^^^^^^^^^^^^^^^^^^ `Option` is not an iterator + | + = help: the trait `IntoIterator` is not implemented for `Option` +help: the following other types implement trait `IntoIterator` + --> $SRC_DIR/core/src/option.rs:LL:COL + | + = note: `Option` + ::: $SRC_DIR/core/src/option.rs:LL:COL + | + = note: `&Option` + ::: $SRC_DIR/core/src/option.rs:LL:COL + | + = note: `&mut Option` + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/unsized-return-suggest-ref-issue-152064.rs:15:18 + | +LL | for s in arr.map(|s| s[3..8]) {} + | ^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by an implicit `Sized` bound in `Option::::map` + --> $SRC_DIR/core/src/option.rs:LL:COL + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/unsized-return-suggest-ref-issue-152064.rs:15:26 + | +LL | for s in arr.map(|s| s[3..8]) {} + | ^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: the return type of a function must have a statically known size + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/unsized-return-suggest-ref-issue-152064.rs:15:14 + | +LL | for s in arr.map(|s| s[3..8]) {} + | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by an implicit `Sized` bound in `Option` + --> $SRC_DIR/core/src/option.rs:LL:COL +help: consider borrowing the value + | +LL | for s in arr.map(|s| &s[3..8]) {} + | + + +error[E0277]: `Option<[u8]>` is not an iterator + --> $DIR/unsized-return-suggest-ref-issue-152064.rs:15:14 + | +LL | for s in arr.map(|s| s[3..8]) {} + | ^^^^^^^^^^^^^^^^^^^^ `Option<[u8]>` is not an iterator + | + = help: the trait `IntoIterator` is not implemented for `Option<[u8]>` +help: the following other types implement trait `IntoIterator` + --> $SRC_DIR/core/src/option.rs:LL:COL + | + = note: `Option` + ::: $SRC_DIR/core/src/option.rs:LL:COL + | + = note: `&Option` + ::: $SRC_DIR/core/src/option.rs:LL:COL + | + = note: `&mut Option` + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0277`.