Skip to content

Commit e1dd8a9

Browse files
committed
When trait bounds are missing for return values, point at them
1 parent b4bbe78 commit e1dd8a9

File tree

11 files changed

+147
-54
lines changed

11 files changed

+147
-54
lines changed

src/librustc/traits/error_reporting.rs

Lines changed: 73 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,6 +1130,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
11301130
};
11311131

11321132
self.note_obligation_cause(&mut err, obligation);
1133+
self.point_at_returns_when_relevant(&mut err, &obligation);
11331134

11341135
err.emit();
11351136
}
@@ -1737,35 +1738,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
17371738
// Recursively look for `TraitObject` types and if there's only one, use that span to
17381739
// suggest `impl Trait`.
17391740

1740-
struct ReturnsVisitor<'v>(Vec<&'v hir::Expr<'v>>);
1741-
1742-
impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
1743-
type Map = rustc::hir::map::Map<'v>;
1744-
1745-
fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<'_, Self::Map> {
1746-
hir::intravisit::NestedVisitorMap::None
1747-
}
1748-
1749-
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
1750-
match ex.kind {
1751-
hir::ExprKind::Ret(Some(ex)) => self.0.push(ex),
1752-
_ => {}
1753-
}
1754-
hir::intravisit::walk_expr(self, ex);
1755-
}
1756-
1757-
fn visit_body(&mut self, body: &'v hir::Body<'v>) {
1758-
if body.generator_kind().is_none() {
1759-
if let hir::ExprKind::Block(block, None) = body.value.kind {
1760-
if let Some(expr) = block.expr {
1761-
self.0.push(expr);
1762-
}
1763-
}
1764-
}
1765-
hir::intravisit::walk_body(self, body);
1766-
}
1767-
}
1768-
17691741
// Visit to make sure there's a single `return` type to suggest `impl Trait`,
17701742
// otherwise suggest using `Box<dyn Trait>` or an enum.
17711743
let mut visitor = ReturnsVisitor(vec![]);
@@ -1893,6 +1865,38 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
18931865
false
18941866
}
18951867

1868+
fn point_at_returns_when_relevant(
1869+
&self,
1870+
err: &mut DiagnosticBuilder<'tcx>,
1871+
obligation: &PredicateObligation<'tcx>,
1872+
) {
1873+
if let ObligationCauseCode::SizedReturnType = obligation.cause.code.peel_derives() {
1874+
} else {
1875+
return;
1876+
}
1877+
1878+
let hir = self.tcx.hir();
1879+
let parent_node = hir.get_parent_node(obligation.cause.body_id);
1880+
let node = hir.find(parent_node);
1881+
if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) =
1882+
node
1883+
{
1884+
let body = hir.body(*body_id);
1885+
// Point at all the `return`s in the function as they have failed trait bounds.
1886+
let mut visitor = ReturnsVisitor(vec![]);
1887+
visitor.visit_body(&body);
1888+
let tables = self.in_progress_tables.map(|t| t.borrow()).unwrap();
1889+
for expr in &visitor.0 {
1890+
if let Some(returned_ty) = tables.node_type_opt(expr.hir_id) {
1891+
err.span_label(
1892+
expr.span,
1893+
&format!("this returned value is of type `{}`", returned_ty),
1894+
);
1895+
}
1896+
}
1897+
}
1898+
}
1899+
18961900
/// Given some node representing a fn-like thing in the HIR map,
18971901
/// returns a span and `ArgKind` information that describes the
18981902
/// arguments it expects. This can be supplied to
@@ -2911,19 +2915,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
29112915
}
29122916
ObligationCauseCode::RepeatVec(suggest_const_in_array_repeat_expressions) => {
29132917
err.note(
2914-
"the `Copy` trait is required because the \
2915-
repeated element will be copied",
2918+
"the `Copy` trait is required because the repeated element will be copied",
29162919
);
29172920
if suggest_const_in_array_repeat_expressions {
29182921
err.note(
29192922
"this array initializer can be evaluated at compile-time, for more \
2920-
information, see issue \
2921-
https://github.com/rust-lang/rust/issues/49147",
2923+
information, see issue \
2924+
https://github.com/rust-lang/rust/issues/49147",
29222925
);
29232926
if tcx.sess.opts.unstable_features.is_nightly_build() {
29242927
err.help(
29252928
"add `#![feature(const_in_array_repeat_expressions)]` to the \
2926-
crate attributes to enable",
2929+
crate attributes to enable",
29272930
);
29282931
}
29292932
}
@@ -2941,16 +2944,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
29412944
}
29422945
}
29432946
ObligationCauseCode::SizedReturnType => {
2944-
err.note(
2945-
"the return type of a function must have a \
2946-
statically known size",
2947-
);
2947+
err.note("the return type of a function must have a statically known size");
29482948
}
29492949
ObligationCauseCode::SizedYieldType => {
2950-
err.note(
2951-
"the yield type of a generator must have a \
2952-
statically known size",
2953-
);
2950+
err.note("the yield type of a generator must have a statically known size");
29542951
}
29552952
ObligationCauseCode::AssignmentLhsSized => {
29562953
err.note("the left-hand-side of an assignment must have a statically known size");
@@ -2966,12 +2963,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
29662963
if last {
29672964
err.note(
29682965
"the last field of a packed struct may only have a \
2969-
dynamically sized type if it does not need drop to be run",
2966+
dynamically sized type if it does not need drop to be run",
29702967
);
29712968
} else {
29722969
err.note(
2973-
"only the last field of a struct may have a dynamically \
2974-
sized type",
2970+
"only the last field of a struct may have a dynamically sized type",
29752971
);
29762972
}
29772973
}
@@ -3025,13 +3021,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
30253021
ObligationCauseCode::CompareImplMethodObligation { .. } => {
30263022
err.note(&format!(
30273023
"the requirement `{}` appears on the impl method \
3028-
but not on the corresponding trait method",
3024+
but not on the corresponding trait method",
30293025
predicate
30303026
));
30313027
}
30323028
ObligationCauseCode::CompareImplTypeObligation { .. } => {
30333029
err.note(&format!(
3034-
"the requirement `{}` appears on the associated impl type\
3030+
"the requirement `{}` appears on the associated impl type \
30353031
but not on the corresponding associated trait type",
30363032
predicate
30373033
));
@@ -3043,8 +3039,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
30433039
err.help("see issue #48214");
30443040
if tcx.sess.opts.unstable_features.is_nightly_build() {
30453041
err.help(
3046-
"add `#![feature(trivial_bounds)]` to the \
3047-
crate attributes to enable",
3042+
"add `#![feature(trivial_bounds)]` to the crate attributes to enable",
30483043
);
30493044
}
30503045
}
@@ -3186,3 +3181,32 @@ pub fn suggest_constraining_type_param(
31863181
}
31873182
false
31883183
}
3184+
3185+
struct ReturnsVisitor<'v>(Vec<&'v hir::Expr<'v>>);
3186+
3187+
impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
3188+
type Map = rustc::hir::map::Map<'v>;
3189+
3190+
fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<'_, Self::Map> {
3191+
hir::intravisit::NestedVisitorMap::None
3192+
}
3193+
3194+
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
3195+
match ex.kind {
3196+
hir::ExprKind::Ret(Some(ex)) => self.0.push(ex),
3197+
_ => {}
3198+
}
3199+
hir::intravisit::walk_expr(self, ex);
3200+
}
3201+
3202+
fn visit_body(&mut self, body: &'v hir::Body<'v>) {
3203+
if body.generator_kind().is_none() {
3204+
if let hir::ExprKind::Block(block, None) = body.value.kind {
3205+
if let Some(expr) = block.expr {
3206+
self.0.push(expr);
3207+
}
3208+
}
3209+
}
3210+
hir::intravisit::walk_body(self, body);
3211+
}
3212+
}

src/test/ui/async-await/issue-64130-4-async-move.stderr

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
error: future cannot be sent between threads safely
22
--> $DIR/issue-64130-4-async-move.rs:15:17
33
|
4-
LL | pub fn foo() -> impl Future + Send {
5-
| ^^^^^^^^^^^^^^^^^^ future returned by `foo` is not `Send`
4+
LL | pub fn foo() -> impl Future + Send {
5+
| ^^^^^^^^^^^^^^^^^^ future returned by `foo` is not `Send`
6+
...
7+
LL | / async move {
8+
LL | | match client.status() {
9+
LL | | 200 => {
10+
LL | | let _x = get().await;
11+
... |
12+
LL | | }
13+
LL | | }
14+
| |_____- this returned value is of type `impl std::future::Future`
615
|
716
= help: the trait `std::marker::Sync` is not implemented for `(dyn std::any::Any + std::marker::Send + 'static)`
817
note: future is not `Send` as this value is used across an await

src/test/ui/const-generics/array-impls/alloc-traits-no-impls-length-33.stderr

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
33
|
44
LL | pub fn no_vec_partial_eq_array<A, B>() -> impl PartialEq<[B; 33]>
55
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]`
6+
...
7+
LL | Vec::<A>::new()
8+
| --------------- this returned value is of type `std::vec::Vec<A>`
69
|
710
= note: required because of the requirements on the impl of `std::cmp::PartialEq<[B; 33]>` for `std::vec::Vec<A>`
811
= note: the return type of a function must have a statically known size
@@ -12,6 +15,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
1215
|
1316
LL | pub fn no_vec_partial_eq_ref_array<'a, A, B>() -> impl PartialEq<&'a [B; 33]>
1417
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]`
18+
...
19+
LL | Vec::<A>::new()
20+
| --------------- this returned value is of type `std::vec::Vec<A>`
1521
|
1622
= note: required because of the requirements on the impl of `std::cmp::PartialEq<&'a [B; 33]>` for `std::vec::Vec<A>`
1723
= note: the return type of a function must have a statically known size
@@ -21,6 +27,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
2127
|
2228
LL | pub fn no_vecdeque_partial_eq_array<A, B>() -> impl PartialEq<[B; 33]>
2329
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]`
30+
...
31+
LL | VecDeque::<A>::new()
32+
| -------------------- this returned value is of type `std::collections::VecDeque<A>`
2433
|
2534
= note: required because of the requirements on the impl of `std::cmp::PartialEq<[B; 33]>` for `std::collections::VecDeque<A>`
2635
= note: the return type of a function must have a statically known size
@@ -30,6 +39,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
3039
|
3140
LL | pub fn no_vecdeque_partial_eq_ref_array<'a, A, B>() -> impl PartialEq<&'a [B; 33]>
3241
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]`
42+
...
43+
LL | VecDeque::<A>::new()
44+
| -------------------- this returned value is of type `std::collections::VecDeque<A>`
3345
|
3446
= note: required because of the requirements on the impl of `std::cmp::PartialEq<&'a [B; 33]>` for `std::collections::VecDeque<A>`
3547
= note: the return type of a function must have a statically known size
@@ -39,6 +51,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
3951
|
4052
LL | pub fn no_vecdeque_partial_eq_ref_mut_array<'a, A, B>() -> impl PartialEq<&'a mut [B; 33]>
4153
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]`
54+
...
55+
LL | VecDeque::<A>::new()
56+
| -------------------- this returned value is of type `std::collections::VecDeque<A>`
4257
|
4358
= note: required because of the requirements on the impl of `std::cmp::PartialEq<&'a mut [B; 33]>` for `std::collections::VecDeque<A>`
4459
= note: the return type of a function must have a statically known size

src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
1111
|
1212
LL | pub fn no_iterator() -> impl Iterator<Item = i32> {
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
14+
LL |
15+
LL | IntoIter::new([0i32; 33])
16+
| ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>`
1417
|
1518
= note: required because of the requirements on the impl of `std::iter::Iterator` for `std::array::IntoIter<i32, 33usize>`
1619
= note: the return type of a function must have a statically known size
@@ -28,6 +31,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
2831
|
2932
LL | pub fn no_double_ended_iterator() -> impl DoubleEndedIterator {
3033
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
34+
LL |
35+
LL | IntoIter::new([0i32; 33])
36+
| ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>`
3137
|
3238
= note: required because of the requirements on the impl of `std::iter::DoubleEndedIterator` for `std::array::IntoIter<i32, 33usize>`
3339
= note: the return type of a function must have a statically known size
@@ -45,6 +51,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
4551
|
4652
LL | pub fn no_exact_size_iterator() -> impl ExactSizeIterator {
4753
| ^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
54+
LL |
55+
LL | IntoIter::new([0i32; 33])
56+
| ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>`
4857
|
4958
= note: required because of the requirements on the impl of `std::iter::ExactSizeIterator` for `std::array::IntoIter<i32, 33usize>`
5059
= note: the return type of a function must have a statically known size
@@ -62,6 +71,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
6271
|
6372
LL | pub fn no_fused_iterator() -> impl FusedIterator {
6473
| ^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
74+
LL |
75+
LL | IntoIter::new([0i32; 33])
76+
| ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>`
6577
|
6678
= note: required because of the requirements on the impl of `std::iter::FusedIterator` for `std::array::IntoIter<i32, 33usize>`
6779
= note: the return type of a function must have a statically known size
@@ -79,6 +91,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
7991
|
8092
LL | pub fn no_trusted_len() -> impl TrustedLen {
8193
| ^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
94+
LL |
95+
LL | IntoIter::new([0i32; 33])
96+
| ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>`
8297
|
8398
= note: required because of the requirements on the impl of `std::iter::TrustedLen` for `std::array::IntoIter<i32, 33usize>`
8499
= note: the return type of a function must have a statically known size
@@ -96,6 +111,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
96111
|
97112
LL | pub fn no_clone() -> impl Clone {
98113
| ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
114+
LL |
115+
LL | IntoIter::new([0i32; 33])
116+
| ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>`
99117
|
100118
= note: required because of the requirements on the impl of `std::clone::Clone` for `std::array::IntoIter<i32, 33usize>`
101119
= note: the return type of a function must have a statically known size
@@ -113,6 +131,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
113131
|
114132
LL | pub fn no_debug() -> impl Debug {
115133
| ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
134+
LL |
135+
LL | IntoIter::new([0i32; 33])
136+
| ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>`
116137
|
117138
= note: required because of the requirements on the impl of `std::fmt::Debug` for `std::array::IntoIter<i32, 33usize>`
118139
= note: the return type of a function must have a statically known size

src/test/ui/generic-associated-types/impl_bounds.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ LL | type C where Self: Copy = String;
3838
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
3939
|
4040
= note: required because of the requirements on the impl of `std::marker::Copy` for `Fooy<T>`
41-
= note: the requirement `Fooy<T>: std::marker::Copy` appears on the associated impl typebut not on the corresponding associated trait type
41+
= note: the requirement `Fooy<T>: std::marker::Copy` appears on the associated impl type but not on the corresponding associated trait type
4242

4343
error: aborting due to 3 previous errors
4444

src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be know
1111
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:7:13
1212
|
1313
LL | fn fuz() -> (usize, Trait) { (42, Struct) }
14-
| ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
14+
| ^^^^^^^^^^^^^^ ------------ this returned value is of type `(usize, (dyn Trait + 'static))`
15+
| |
16+
| doesn't have a size known at compile-time
1517
|
1618
= help: within `(usize, (dyn Trait + 'static))`, the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)`
1719
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
@@ -31,7 +33,9 @@ error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be know
3133
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:10:13
3234
|
3335
LL | fn bar() -> (usize, dyn Trait) { (42, Struct) }
34-
| ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
36+
| ^^^^^^^^^^^^^^^^^^ ------------ this returned value is of type `(usize, (dyn Trait + 'static))`
37+
| |
38+
| doesn't have a size known at compile-time
3539
|
3640
= help: within `(usize, (dyn Trait + 'static))`, the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)`
3741
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>

0 commit comments

Comments
 (0)