Skip to content

Commit d153f44

Browse files
committed
Suggest returning a reference for unsized place from a closure
1 parent 3ea2fbc commit d153f44

6 files changed

Lines changed: 186 additions & 0 deletions

File tree

compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2795,6 +2795,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
27952795
obligation.param_env,
27962796
obligation.cause.code(),
27972797
);
2798+
self.suggest_borrow_for_unsized_closure_return(
2799+
obligation.cause.body_id,
2800+
err,
2801+
obligation.predicate,
2802+
);
27982803
self.suggest_unsized_bound_if_applicable(err, obligation);
27992804
if let Some(span) = err.span.primary_span()
28002805
&& let Some(mut diag) =

compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1908,6 +1908,60 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
19081908
false
19091909
}
19101910

1911+
pub(super) fn suggest_borrow_for_unsized_closure_return<G: EmissionGuarantee>(
1912+
&self,
1913+
body_id: LocalDefId,
1914+
err: &mut Diag<'_, G>,
1915+
predicate: ty::Predicate<'tcx>,
1916+
) {
1917+
let Some(pred) = predicate.as_trait_clause() else {
1918+
return;
1919+
};
1920+
if !self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) {
1921+
return;
1922+
}
1923+
1924+
let Some(span) = err.span.primary_span() else {
1925+
return;
1926+
};
1927+
let Some(node_body_id) = self.tcx.hir_node_by_def_id(body_id).body_id() else {
1928+
return;
1929+
};
1930+
let body = self.tcx.hir_body(node_body_id);
1931+
let mut expr_finder = FindExprBySpan::new(span, self.tcx);
1932+
expr_finder.visit_expr(body.value);
1933+
let Some(expr) = expr_finder.result else {
1934+
return;
1935+
};
1936+
1937+
let closure = match expr.kind {
1938+
hir::ExprKind::Call(_, args) => args.iter().find_map(|arg| match arg.kind {
1939+
hir::ExprKind::Closure(closure) => Some(closure),
1940+
_ => None,
1941+
}),
1942+
hir::ExprKind::MethodCall(_, _, args, _) => {
1943+
args.iter().find_map(|arg| match arg.kind {
1944+
hir::ExprKind::Closure(closure) => Some(closure),
1945+
_ => None,
1946+
})
1947+
}
1948+
_ => None,
1949+
};
1950+
let Some(closure) = closure else {
1951+
return;
1952+
};
1953+
if !matches!(closure.fn_decl.output, hir::FnRetTy::DefaultReturn(_)) {
1954+
return;
1955+
}
1956+
1957+
err.span_suggestion_verbose(
1958+
self.tcx.hir_body(closure.body).value.span.shrink_to_lo(),
1959+
"consider borrowing the value",
1960+
"&",
1961+
Applicability::MaybeIncorrect,
1962+
);
1963+
}
1964+
19111965
pub(super) fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span> {
19121966
let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { sig, .. }, .. }) =
19131967
self.tcx.hir_node_by_def_id(obligation.cause.body_id)

src/tools/clippy/tests/ui/crashes/ice-6251.stderr

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ LL | fn bug<T>() -> impl Iterator<Item = [(); { |x: [u8]| x }]> {
1919
|
2020
= help: the trait `std::marker::Sized` is not implemented for `[u8]`
2121
= note: the return type of a function must have a statically known size
22+
help: consider borrowing the value
23+
|
24+
LL | fn bug<T>() -> impl Iterator<Item = [(); { |x: [u8]| &x }]> {
25+
| +
2226

2327
error[E0308]: mismatched types
2428
--> tests/ui/crashes/ice-6251.rs:4:44
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#![allow(unused_variables, for_loops_over_fallibles)]
2+
//@ run-rustfix
3+
4+
fn main() {
5+
// Basic case from the issue: str slice
6+
let o = Some("Hello, world!");
7+
for s in o.map(|s| &s[3..8]) {}
8+
//~^ ERROR the size for values of type `str` cannot be known at compilation time
9+
//~| ERROR the size for values of type `str` cannot be known at compilation time
10+
//~| ERROR `Option<str>` is not an iterator
11+
12+
// Byte slice case
13+
let arr = Some(b"Hello, world!");
14+
for s in arr.map(|s| &s[3..8]) {}
15+
//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
16+
//~| ERROR the size for values of type `[u8]` cannot be known at compilation time
17+
//~| ERROR `Option<[u8]>` is not an iterator
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#![allow(unused_variables, for_loops_over_fallibles)]
2+
//@ run-rustfix
3+
4+
fn main() {
5+
// Basic case from the issue: str slice
6+
let o = Some("Hello, world!");
7+
for s in o.map(|s| s[3..8]) {}
8+
//~^ ERROR the size for values of type `str` cannot be known at compilation time
9+
//~| ERROR the size for values of type `str` cannot be known at compilation time
10+
//~| ERROR `Option<str>` is not an iterator
11+
12+
// Byte slice case
13+
let arr = Some(b"Hello, world!");
14+
for s in arr.map(|s| s[3..8]) {}
15+
//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
16+
//~| ERROR the size for values of type `[u8]` cannot be known at compilation time
17+
//~| ERROR `Option<[u8]>` is not an iterator
18+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
error[E0277]: the size for values of type `str` cannot be known at compilation time
2+
--> $DIR/unsized-return-suggest-ref-issue-152064.rs:7:16
3+
|
4+
LL | for s in o.map(|s| s[3..8]) {}
5+
| ^^^ doesn't have a size known at compile-time
6+
|
7+
= help: the trait `Sized` is not implemented for `str`
8+
note: required by an implicit `Sized` bound in `Option::<T>::map`
9+
--> $SRC_DIR/core/src/option.rs:LL:COL
10+
11+
error[E0277]: the size for values of type `str` cannot be known at compilation time
12+
--> $DIR/unsized-return-suggest-ref-issue-152064.rs:7:14
13+
|
14+
LL | for s in o.map(|s| s[3..8]) {}
15+
| ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
16+
|
17+
= help: the trait `Sized` is not implemented for `str`
18+
note: required by an implicit `Sized` bound in `Option`
19+
--> $SRC_DIR/core/src/option.rs:LL:COL
20+
help: consider borrowing the value
21+
|
22+
LL | for s in o.map(|s| &s[3..8]) {}
23+
| +
24+
25+
error[E0277]: `Option<str>` is not an iterator
26+
--> $DIR/unsized-return-suggest-ref-issue-152064.rs:7:14
27+
|
28+
LL | for s in o.map(|s| s[3..8]) {}
29+
| ^^^^^^^^^^^^^^^^^^ `Option<str>` is not an iterator
30+
|
31+
= help: the trait `IntoIterator` is not implemented for `Option<str>`
32+
help: the following other types implement trait `IntoIterator`
33+
--> $SRC_DIR/core/src/option.rs:LL:COL
34+
|
35+
= note: `Option<T>`
36+
::: $SRC_DIR/core/src/option.rs:LL:COL
37+
|
38+
= note: `&Option<T>`
39+
::: $SRC_DIR/core/src/option.rs:LL:COL
40+
|
41+
= note: `&mut Option<T>`
42+
43+
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
44+
--> $DIR/unsized-return-suggest-ref-issue-152064.rs:14:18
45+
|
46+
LL | for s in arr.map(|s| s[3..8]) {}
47+
| ^^^ doesn't have a size known at compile-time
48+
|
49+
= help: the trait `Sized` is not implemented for `[u8]`
50+
note: required by an implicit `Sized` bound in `Option::<T>::map`
51+
--> $SRC_DIR/core/src/option.rs:LL:COL
52+
53+
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
54+
--> $DIR/unsized-return-suggest-ref-issue-152064.rs:14:14
55+
|
56+
LL | for s in arr.map(|s| s[3..8]) {}
57+
| ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
58+
|
59+
= help: the trait `Sized` is not implemented for `[u8]`
60+
note: required by an implicit `Sized` bound in `Option`
61+
--> $SRC_DIR/core/src/option.rs:LL:COL
62+
help: consider borrowing the value
63+
|
64+
LL | for s in arr.map(|s| &s[3..8]) {}
65+
| +
66+
67+
error[E0277]: `Option<[u8]>` is not an iterator
68+
--> $DIR/unsized-return-suggest-ref-issue-152064.rs:14:14
69+
|
70+
LL | for s in arr.map(|s| s[3..8]) {}
71+
| ^^^^^^^^^^^^^^^^^^^^ `Option<[u8]>` is not an iterator
72+
|
73+
= help: the trait `IntoIterator` is not implemented for `Option<[u8]>`
74+
help: the following other types implement trait `IntoIterator`
75+
--> $SRC_DIR/core/src/option.rs:LL:COL
76+
|
77+
= note: `Option<T>`
78+
::: $SRC_DIR/core/src/option.rs:LL:COL
79+
|
80+
= note: `&Option<T>`
81+
::: $SRC_DIR/core/src/option.rs:LL:COL
82+
|
83+
= note: `&mut Option<T>`
84+
85+
error: aborting due to 6 previous errors
86+
87+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)