Suggest derive(Trait) or T: Trait from transitive obligation in some cases by estebank · Pull Request #127997 · rust-lang/rust (original) (raw)

With code like the following

#[derive(Clone)] struct Ctx { a_map: HashMap<String, B>, }

#[derive(Clone)] struct B { a: A, }

the derived trait will have an implicit restriction on A: Clone for both types.

When referenced as follows:

fn foo(ctx: &mut Ctx) { let a_map = ctx.a_map.clone(); //~ ERROR E0599 }

suggest constraining Z:

error[E0599]: the method `clone` exists for struct `HashMap<String, B<Z>>`, but its trait bounds were not satisfied
  --> $DIR/type-or-type-param-missing-transitive-trait-contraint.rs:16:27
   |
LL | struct B<A> {
   | ----------- doesn't satisfy `B<Z>: Clone`
...
LL |     let a_map = ctx.a_map.clone();
   |                           ^^^^^ method cannot be called on `HashMap<String, B<Z>>` due to unsatisfied trait bounds
   |
   = note: the following trait bounds were not satisfied:
           `B<Z>: Clone`
           which is required by `HashMap<String, B<Z>>: Clone`
help: consider restricting type parameter `Z`
   |
LL | fn foo<Z: std::clone::Clone>(ctx: &mut Ctx<Z>) {
   |         +++++++++++++++++++

When referenced as follows, with a specific type S:

struct S; fn bar(ctx: &mut Ctx) { let a_map = ctx.a_map.clone(); //~ ERROR E0599 }

suggest deriveing the appropriate trait on the local type:

error[E0599]: the method `clone` exists for struct `HashMap<String, B<S>>`, but its trait bounds were not satisfied
  --> $DIR/type-or-type-param-missing-transitive-trait-contraint.rs:21:27
   |
LL | struct B<A> {
   | ----------- doesn't satisfy `B<S>: Clone`
...
LL |     let a_map = ctx.a_map.clone();
   |                           ^^^^^ method cannot be called on `HashMap<String, B<S>>` due to unsatisfied trait bounds
   |
   = note: the following trait bounds were not satisfied:
           `B<S>: Clone`
           which is required by `HashMap<String, B<S>>: Clone`
help: consider annotating `S` with `#[derive(Clone)]`
   |
LL + #[derive(Clone)]
LL | struct S;
   |

Given

use std::fmt::Debug; use std::hash::Hash; pub trait Ctx: Clone + Eq + Debug { type Loc: Loc; }

pub trait Accessible { type Context<'a>: Ctx; fn can_access<'a>(&self, ctx: &Self::Context<'a>) -> bool; }

pub trait Id: Copy + Clone + Debug + Eq + Hash + Ord + PartialOrd {}

pub trait Loc: Accessible { type LocId: Id; }

// error #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum History where T: Ctx { Visit(<::Loc as Loc>::LocId), Action(<::Loc as Loc>::LocId), }

#[derive(Copy, Clone, Default, Eq, PartialEq)] pub struct HSlice<'a, T> where T: Ctx { slice: &'a [History], } impl<'a, T> Hash for HSlice<'a, T> where T: Ctx { fn hash<H: std::hash::Hasher>(&self, state: &mut H) { (*self.slice).hash(state); } }

we emit

error[E0599]: the method `hash` exists for slice `[History<T>]`, but its trait bounds were not satisfied
  --> f1000.rs:34:23
   |
20 | pub enum History<T>
   | ------------------- doesn't satisfy `History<T>: Hash`
...
34 |         (*self.slice).hash(state);
   |                       ^^^^ method cannot be called on `[History<T>]` due to unsatisfied trait bounds
   |
   = note: the following trait bounds were not satisfied:
           `History<T>: Hash`
           which is required by `[History<T>]: Hash`
help: consider further restricting this bound
   |
32 | impl<'a, T> Hash for HSlice<'a, T> where T: Ctx + std::hash::Hash {
   |                                                 +++++++++++++++++

Fix #110446, fix #108712.