diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 8d0923f57185..d5af1a9a42dd 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1130,6 +1130,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; self.note_obligation_cause(&mut err, obligation); + self.point_at_returns_when_relevant(&mut err, &obligation); err.emit(); } @@ -1737,35 +1738,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // Recursively look for `TraitObject` types and if there's only one, use that span to // suggest `impl Trait`. - struct ReturnsVisitor<'v>(Vec<&'v hir::Expr<'v>>); - - impl<'v> Visitor<'v> for ReturnsVisitor<'v> { - type Map = rustc::hir::map::Map<'v>; - - fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<'_, Self::Map> { - hir::intravisit::NestedVisitorMap::None - } - - fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { - match ex.kind { - hir::ExprKind::Ret(Some(ex)) => self.0.push(ex), - _ => {} - } - hir::intravisit::walk_expr(self, ex); - } - - fn visit_body(&mut self, body: &'v hir::Body<'v>) { - if body.generator_kind().is_none() { - if let hir::ExprKind::Block(block, None) = body.value.kind { - if let Some(expr) = block.expr { - self.0.push(expr); - } - } - } - hir::intravisit::walk_body(self, body); - } - } - // Visit to make sure there's a single `return` type to suggest `impl Trait`, // otherwise suggest using `Box` or an enum. let mut visitor = ReturnsVisitor(vec![]); @@ -1893,6 +1865,38 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { false } + fn point_at_returns_when_relevant( + &self, + err: &mut DiagnosticBuilder<'tcx>, + obligation: &PredicateObligation<'tcx>, + ) { + if let ObligationCauseCode::SizedReturnType = obligation.cause.code.peel_derives() { + } else { + return; + } + + let hir = self.tcx.hir(); + let parent_node = hir.get_parent_node(obligation.cause.body_id); + let node = hir.find(parent_node); + if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) = + node + { + let body = hir.body(*body_id); + // Point at all the `return`s in the function as they have failed trait bounds. + let mut visitor = ReturnsVisitor(vec![]); + visitor.visit_body(&body); + let tables = self.in_progress_tables.map(|t| t.borrow()).unwrap(); + for expr in &visitor.0 { + if let Some(returned_ty) = tables.node_type_opt(expr.hir_id) { + err.span_label( + expr.span, + &format!("this returned value is of type `{}`", returned_ty), + ); + } + } + } + } + /// Given some node representing a fn-like thing in the HIR map, /// returns a span and `ArgKind` information that describes the /// arguments it expects. This can be supplied to @@ -2911,19 +2915,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } ObligationCauseCode::RepeatVec(suggest_const_in_array_repeat_expressions) => { err.note( - "the `Copy` trait is required because the \ - repeated element will be copied", + "the `Copy` trait is required because the repeated element will be copied", ); if suggest_const_in_array_repeat_expressions { err.note( "this array initializer can be evaluated at compile-time, for more \ - information, see issue \ - https://github.com/rust-lang/rust/issues/49147", + information, see issue \ + https://github.com/rust-lang/rust/issues/49147", ); if tcx.sess.opts.unstable_features.is_nightly_build() { err.help( "add `#![feature(const_in_array_repeat_expressions)]` to the \ - crate attributes to enable", + crate attributes to enable", ); } } @@ -2941,16 +2944,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } ObligationCauseCode::SizedReturnType => { - err.note( - "the return type of a function must have a \ - statically known size", - ); + err.note("the return type of a function must have a statically known size"); } ObligationCauseCode::SizedYieldType => { - err.note( - "the yield type of a generator must have a \ - statically known size", - ); + err.note("the yield type of a generator must have a statically known size"); } ObligationCauseCode::AssignmentLhsSized => { 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> { if last { err.note( "the last field of a packed struct may only have a \ - dynamically sized type if it does not need drop to be run", + dynamically sized type if it does not need drop to be run", ); } else { err.note( - "only the last field of a struct may have a dynamically \ - sized type", + "only the last field of a struct may have a dynamically sized type", ); } } @@ -3025,13 +3021,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ObligationCauseCode::CompareImplMethodObligation { .. } => { err.note(&format!( "the requirement `{}` appears on the impl method \ - but not on the corresponding trait method", + but not on the corresponding trait method", predicate )); } ObligationCauseCode::CompareImplTypeObligation { .. } => { err.note(&format!( - "the requirement `{}` appears on the associated impl type\ + "the requirement `{}` appears on the associated impl type \ but not on the corresponding associated trait type", predicate )); @@ -3043,8 +3039,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.help("see issue #48214"); if tcx.sess.opts.unstable_features.is_nightly_build() { err.help( - "add `#![feature(trivial_bounds)]` to the \ - crate attributes to enable", + "add `#![feature(trivial_bounds)]` to the crate attributes to enable", ); } } @@ -3186,3 +3181,32 @@ pub fn suggest_constraining_type_param( } false } + +struct ReturnsVisitor<'v>(Vec<&'v hir::Expr<'v>>); + +impl<'v> Visitor<'v> for ReturnsVisitor<'v> { + type Map = rustc::hir::map::Map<'v>; + + fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<'_, Self::Map> { + hir::intravisit::NestedVisitorMap::None + } + + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + match ex.kind { + hir::ExprKind::Ret(Some(ex)) => self.0.push(ex), + _ => {} + } + hir::intravisit::walk_expr(self, ex); + } + + fn visit_body(&mut self, body: &'v hir::Body<'v>) { + if body.generator_kind().is_none() { + if let hir::ExprKind::Block(block, None) = body.value.kind { + if let Some(expr) = block.expr { + self.0.push(expr); + } + } + } + hir::intravisit::walk_body(self, body); + } +} diff --git a/src/test/ui/async-await/issue-64130-4-async-move.stderr b/src/test/ui/async-await/issue-64130-4-async-move.stderr index 77d0885c38d5..f59dbc263840 100644 --- a/src/test/ui/async-await/issue-64130-4-async-move.stderr +++ b/src/test/ui/async-await/issue-64130-4-async-move.stderr @@ -1,8 +1,17 @@ error: future cannot be sent between threads safely --> $DIR/issue-64130-4-async-move.rs:15:17 | -LL | pub fn foo() -> impl Future + Send { - | ^^^^^^^^^^^^^^^^^^ future returned by `foo` is not `Send` +LL | pub fn foo() -> impl Future + Send { + | ^^^^^^^^^^^^^^^^^^ future returned by `foo` is not `Send` +... +LL | / async move { +LL | | match client.status() { +LL | | 200 => { +LL | | let _x = get().await; +... | +LL | | } +LL | | } + | |_____- this returned value is of type `impl std::future::Future` | = help: the trait `std::marker::Sync` is not implemented for `(dyn std::any::Any + std::marker::Send + 'static)` note: future is not `Send` as this value is used across an await diff --git a/src/test/ui/const-generics/array-impls/alloc-traits-no-impls-length-33.stderr b/src/test/ui/const-generics/array-impls/alloc-traits-no-impls-length-33.stderr index 5c37468130c6..6e5afcdb8bb6 100644 --- a/src/test/ui/const-generics/array-impls/alloc-traits-no-impls-length-33.stderr +++ b/src/test/ui/const-generics/array-impls/alloc-traits-no-impls-length-33.stderr @@ -3,6 +3,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32 | LL | pub fn no_vec_partial_eq_array() -> impl PartialEq<[B; 33]> | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]` +... +LL | Vec::::new() + | --------------- this returned value is of type `std::vec::Vec` | = note: required because of the requirements on the impl of `std::cmp::PartialEq<[B; 33]>` for `std::vec::Vec` = 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 | LL | pub fn no_vec_partial_eq_ref_array<'a, A, B>() -> impl PartialEq<&'a [B; 33]> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]` +... +LL | Vec::::new() + | --------------- this returned value is of type `std::vec::Vec` | = note: required because of the requirements on the impl of `std::cmp::PartialEq<&'a [B; 33]>` for `std::vec::Vec` = 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 | LL | pub fn no_vecdeque_partial_eq_array() -> impl PartialEq<[B; 33]> | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]` +... +LL | VecDeque::::new() + | -------------------- this returned value is of type `std::collections::VecDeque` | = note: required because of the requirements on the impl of `std::cmp::PartialEq<[B; 33]>` for `std::collections::VecDeque` = 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 | LL | pub fn no_vecdeque_partial_eq_ref_array<'a, A, B>() -> impl PartialEq<&'a [B; 33]> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]` +... +LL | VecDeque::::new() + | -------------------- this returned value is of type `std::collections::VecDeque` | = note: required because of the requirements on the impl of `std::cmp::PartialEq<&'a [B; 33]>` for `std::collections::VecDeque` = 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 | LL | pub fn no_vecdeque_partial_eq_ref_mut_array<'a, A, B>() -> impl PartialEq<&'a mut [B; 33]> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]` +... +LL | VecDeque::::new() + | -------------------- this returned value is of type `std::collections::VecDeque` | = note: required because of the requirements on the impl of `std::cmp::PartialEq<&'a mut [B; 33]>` for `std::collections::VecDeque` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr b/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr index bfdff8e3bbe6..e615e10bd5f5 100644 --- a/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr +++ b/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr @@ -11,6 +11,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32 | LL | pub fn no_iterator() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` +LL | +LL | IntoIter::new([0i32; 33]) + | ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>` | = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::array::IntoIter` = 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 | LL | pub fn no_double_ended_iterator() -> impl DoubleEndedIterator { | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` +LL | +LL | IntoIter::new([0i32; 33]) + | ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>` | = note: required because of the requirements on the impl of `std::iter::DoubleEndedIterator` for `std::array::IntoIter` = 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 | LL | pub fn no_exact_size_iterator() -> impl ExactSizeIterator { | ^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` +LL | +LL | IntoIter::new([0i32; 33]) + | ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>` | = note: required because of the requirements on the impl of `std::iter::ExactSizeIterator` for `std::array::IntoIter` = 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 | LL | pub fn no_fused_iterator() -> impl FusedIterator { | ^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` +LL | +LL | IntoIter::new([0i32; 33]) + | ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>` | = note: required because of the requirements on the impl of `std::iter::FusedIterator` for `std::array::IntoIter` = 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 | LL | pub fn no_trusted_len() -> impl TrustedLen { | ^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` +LL | +LL | IntoIter::new([0i32; 33]) + | ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>` | = note: required because of the requirements on the impl of `std::iter::TrustedLen` for `std::array::IntoIter` = 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 | LL | pub fn no_clone() -> impl Clone { | ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` +LL | +LL | IntoIter::new([0i32; 33]) + | ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>` | = note: required because of the requirements on the impl of `std::clone::Clone` for `std::array::IntoIter` = 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 | LL | pub fn no_debug() -> impl Debug { | ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` +LL | +LL | IntoIter::new([0i32; 33]) + | ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>` | = note: required because of the requirements on the impl of `std::fmt::Debug` for `std::array::IntoIter` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/generic-associated-types/impl_bounds.stderr b/src/test/ui/generic-associated-types/impl_bounds.stderr index 017990076931..ca2350ff7577 100644 --- a/src/test/ui/generic-associated-types/impl_bounds.stderr +++ b/src/test/ui/generic-associated-types/impl_bounds.stderr @@ -38,7 +38,7 @@ LL | type C where Self: Copy = String; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | = note: required because of the requirements on the impl of `std::marker::Copy` for `Fooy` - = note: the requirement `Fooy: std::marker::Copy` appears on the associated impl typebut not on the corresponding associated trait type + = note: the requirement `Fooy: std::marker::Copy` appears on the associated impl type but not on the corresponding associated trait type error: aborting due to 3 previous errors diff --git a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr index a09ce2bb2986..d51cd6aeae6e 100644 --- a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr +++ b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr @@ -11,7 +11,9 @@ error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be know --> $DIR/dyn-trait-return-should-be-impl-trait.rs:7:13 | LL | fn fuz() -> (usize, Trait) { (42, Struct) } - | ^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^ ------------ this returned value is of type `(usize, (dyn Trait + 'static))` + | | + | doesn't have a size known at compile-time | = help: within `(usize, (dyn Trait + 'static))`, the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)` = note: to learn more, visit @@ -31,7 +33,9 @@ error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be know --> $DIR/dyn-trait-return-should-be-impl-trait.rs:10:13 | LL | fn bar() -> (usize, dyn Trait) { (42, Struct) } - | ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^ ------------ this returned value is of type `(usize, (dyn Trait + 'static))` + | | + | doesn't have a size known at compile-time | = help: within `(usize, (dyn Trait + 'static))`, the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)` = note: to learn more, visit diff --git a/src/test/ui/issues/issue-58344.stderr b/src/test/ui/issues/issue-58344.stderr index 427d03b679d5..9b07dbd7ab69 100644 --- a/src/test/ui/issues/issue-58344.stderr +++ b/src/test/ui/issues/issue-58344.stderr @@ -3,6 +3,9 @@ error[E0277]: the trait bound `impl Trait<::Output>: Trait | LL | ) -> Either>::Output>, impl Trait<>::Output>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Trait<::Output>` +... +LL | add_generic(value, 1u32) + | ------------------------ this returned value is of type `Either>::Output>, impl Trait<<_ as std::ops::Add<_>>::Output>>` | = note: the return type of a function must have a statically known size @@ -11,6 +14,9 @@ error[E0277]: the trait bound `impl Trait<::Output>: Trait | LL | ) -> Either>::Output>, impl Trait<>::Output>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Trait<::Output>` +... +LL | add_generic(value, 1u32) + | ------------------------ this returned value is of type `Either>::Output>, impl Trait<<_ as std::ops::Add<_>>::Output>>` | = note: the return type of a function must have a statically known size diff --git a/src/test/ui/issues/issue-5883.stderr b/src/test/ui/issues/issue-5883.stderr index c2de1d095505..d886ecc11d17 100644 --- a/src/test/ui/issues/issue-5883.stderr +++ b/src/test/ui/issues/issue-5883.stderr @@ -14,6 +14,9 @@ error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at | LL | -> Struct { | ^^^^^^ doesn't have a size known at compile-time +LL | +LL | Struct { r: r } + | --------------- this returned value is of type `Struct` | = help: within `Struct`, the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)` = note: to learn more, visit diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr index 228582d0001d..49fa11c35aef 100644 --- a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr +++ b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr @@ -3,6 +3,9 @@ error[E0277]: the trait bound `std::result::Result<(), _>: Future` is not satisf | LL | fn foo() -> impl Future> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Future` is not implemented for `std::result::Result<(), _>` +LL | +LL | Ok(()) + | ------ this returned value is of type `std::result::Result<_, _>` | = note: the return type of a function must have a statically known size diff --git a/src/test/ui/never_type/feature-gate-never_type_fallback.stderr b/src/test/ui/never_type/feature-gate-never_type_fallback.stderr index 837e90d6ceb9..88bfed2b5474 100644 --- a/src/test/ui/never_type/feature-gate-never_type_fallback.stderr +++ b/src/test/ui/never_type/feature-gate-never_type_fallback.stderr @@ -3,8 +3,12 @@ error[E0277]: the trait bound `(): T` is not satisfied | LL | fn should_ret_unit() -> impl T { | ^^^^^^ the trait `T` is not implemented for `()` +LL | +LL | panic!() + | -------- this returned value is of type `_` | = note: the return type of a function must have a statically known size + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr index d4c7c7c74529..9e8414f9c15f 100644 --- a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr @@ -18,6 +18,8 @@ LL | type Underconstrained = impl 'static; ... LL | fn underconstrained(_: U) -> Underconstrained { | - help: consider restricting this bound: `U: std::fmt::Debug` +LL | 5u32 + | ---- this returned value is of type `u32` | = help: the trait `std::fmt::Debug` is not implemented for `U` = note: the return type of a function must have a statically known size @@ -30,6 +32,8 @@ LL | type Underconstrained2 = impl 'static; ... LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { | - help: consider restricting this bound: `V: std::fmt::Debug` +LL | 5u32 + | ---- this returned value is of type `u32` | = help: the trait `std::fmt::Debug` is not implemented for `V` = note: the return type of a function must have a statically known size