When trait bounds are missing for return values, point at them

This commit is contained in:
Esteban Küber 2020-01-13 17:19:52 -08:00
parent b4bbe784a9
commit e1dd8a9095
11 changed files with 147 additions and 54 deletions

View file

@ -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<dyn Trait>` 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);
}
}

View file

@ -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

View file

@ -3,6 +3,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
|
LL | pub fn no_vec_partial_eq_array<A, B>() -> impl PartialEq<[B; 33]>
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]`
...
LL | Vec::<A>::new()
| --------------- this returned value is of type `std::vec::Vec<A>`
|
= note: required because of the requirements on the impl of `std::cmp::PartialEq<[B; 33]>` for `std::vec::Vec<A>`
= 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::<A>::new()
| --------------- this returned value is of type `std::vec::Vec<A>`
|
= note: required because of the requirements on the impl of `std::cmp::PartialEq<&'a [B; 33]>` for `std::vec::Vec<A>`
= 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<A, B>() -> impl PartialEq<[B; 33]>
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]`
...
LL | VecDeque::<A>::new()
| -------------------- this returned value is of type `std::collections::VecDeque<A>`
|
= note: required because of the requirements on the impl of `std::cmp::PartialEq<[B; 33]>` for `std::collections::VecDeque<A>`
= 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::<A>::new()
| -------------------- this returned value is of type `std::collections::VecDeque<A>`
|
= note: required because of the requirements on the impl of `std::cmp::PartialEq<&'a [B; 33]>` for `std::collections::VecDeque<A>`
= 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::<A>::new()
| -------------------- this returned value is of type `std::collections::VecDeque<A>`
|
= note: required because of the requirements on the impl of `std::cmp::PartialEq<&'a mut [B; 33]>` for `std::collections::VecDeque<A>`
= note: the return type of a function must have a statically known size

View file

@ -11,6 +11,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
|
LL | pub fn no_iterator() -> impl Iterator<Item = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ 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<i32, 33usize>`
= 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<i32, 33usize>`
= 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<i32, 33usize>`
= 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<i32, 33usize>`
= 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<i32, 33usize>`
= 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<i32, 33usize>`
= 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<i32, 33usize>`
= note: the return type of a function must have a statically known size

View file

@ -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<T>`
= note: the requirement `Fooy<T>: std::marker::Copy` appears on the associated impl typebut not on the corresponding associated trait type
= note: the requirement `Fooy<T>: std::marker::Copy` appears on the associated impl type but not on the corresponding associated trait type
error: aborting due to 3 previous errors

View file

@ -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 <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
--> $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 <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>

View file

@ -3,6 +3,9 @@ error[E0277]: the trait bound `impl Trait<<u32 as std::ops::Add>::Output>: Trait
|
LL | ) -> Either<impl Trait<<u32 as Add<u32>>::Output>, impl Trait<<u32 as Add<u32>>::Output>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<u32>` is not implemented for `impl Trait<<u32 as std::ops::Add>::Output>`
...
LL | add_generic(value, 1u32)
| ------------------------ this returned value is of type `Either<impl Trait<<_ as std::ops::Add<_>>::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<<u32 as std::ops::Add>::Output>: Trait
|
LL | ) -> Either<impl Trait<<u32 as Add<u32>>::Output>, impl Trait<<u32 as Add<u32>>::Output>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<u32>` is not implemented for `impl Trait<<u32 as std::ops::Add>::Output>`
...
LL | add_generic(value, 1u32)
| ------------------------ this returned value is of type `Either<impl Trait<<_ as std::ops::Add<_>>::Output>, impl Trait<<_ as std::ops::Add<_>>::Output>>`
|
= note: the return type of a function must have a statically known size

View file

@ -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 <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>

View file

@ -3,6 +3,9 @@ error[E0277]: the trait bound `std::result::Result<(), _>: Future` is not satisf
|
LL | fn foo() -> impl Future<Item=(), Error=Box<dyn Error>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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

View file

@ -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

View file

@ -18,6 +18,8 @@ LL | type Underconstrained<T: std::fmt::Debug> = impl 'static;
...
LL | fn underconstrained<U>(_: U) -> Underconstrained<U> {
| - 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<T: std::fmt::Debug> = impl 'static;
...
LL | fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> {
| - 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