From f34db2f36311b0256d7fdfbf42fcb45702786e75 Mon Sep 17 00:00:00 2001 From: yukang Date: Thu, 5 Feb 2026 09:57:03 +0000 Subject: [PATCH] Suggest returning a reference for unsized place from a closure --- .../traits/fulfillment_errors.rs | 5 ++ .../src/error_reporting/traits/suggestions.rs | 54 ++++++++++++ ...ized-return-suggest-ref-issue-152064.fixed | 18 ++++ ...unsized-return-suggest-ref-issue-152064.rs | 18 ++++ ...zed-return-suggest-ref-issue-152064.stderr | 87 +++++++++++++++++++ 5 files changed, 182 insertions(+) create mode 100644 tests/ui/closures/unsized-return-suggest-ref-issue-152064.fixed create mode 100644 tests/ui/closures/unsized-return-suggest-ref-issue-152064.rs create mode 100644 tests/ui/closures/unsized-return-suggest-ref-issue-152064.stderr 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 eeccf1eb0ecfa..f9a966004ba8e 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 @@ -2795,6 +2795,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 4a6d5eb48f8f1..b0e07c5d90c69 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -1908,6 +1908,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..2e1d10fb2804c --- /dev/null +++ b/tests/ui/closures/unsized-return-suggest-ref-issue-152064.fixed @@ -0,0 +1,18 @@ +#![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 `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 `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..6a0573248ff8b --- /dev/null +++ b/tests/ui/closures/unsized-return-suggest-ref-issue-152064.rs @@ -0,0 +1,18 @@ +#![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 `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 `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..c5e5e71cd8823 --- /dev/null +++ b/tests/ui/closures/unsized-return-suggest-ref-issue-152064.stderr @@ -0,0 +1,87 @@ +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: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:14: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:14: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:14: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 6 previous errors + +For more information about this error, try `rustc --explain E0277`.