Suggest returning a reference for unsized place from a closure

This commit is contained in:
yukang
2026-02-05 09:57:03 +00:00
parent 6f109d8a2d
commit eedf870de9
5 changed files with 204 additions and 0 deletions
@@ -2746,6 +2746,11 @@ pub fn note_obligation_cause(
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) =
@@ -2193,6 +2193,60 @@ pub(super) fn suggest_semicolon_removal(
false
}
pub(super) fn suggest_borrow_for_unsized_closure_return<G: EmissionGuarantee>(
&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<Span> {
let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { sig, .. }, .. }) =
self.tcx.hir_node_by_def_id(obligation.cause.body_id)
@@ -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<str>` 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
}
@@ -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<str>` 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
}
@@ -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::<T>::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<str>` 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<str>` is not an iterator
|
= help: the trait `IntoIterator` is not implemented for `Option<str>`
help: the following other types implement trait `IntoIterator`
--> $SRC_DIR/core/src/option.rs:LL:COL
|
= note: `Option<T>`
::: $SRC_DIR/core/src/option.rs:LL:COL
|
= note: `&Option<T>`
::: $SRC_DIR/core/src/option.rs:LL:COL
|
= note: `&mut Option<T>`
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::<T>::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<T>`
::: $SRC_DIR/core/src/option.rs:LL:COL
|
= note: `&Option<T>`
::: $SRC_DIR/core/src/option.rs:LL:COL
|
= note: `&mut Option<T>`
error: aborting due to 8 previous errors
For more information about this error, try `rustc --explain E0277`.