Adding unnecessary bounds to improve error messages?

⚓ rust    📅 2025-07-15    👤 surdeus    👁️ 3      

surdeus

Hi, I have a situation like this:

/// Very useful trait ...
pub trait Foo {}

impl Foo for i32 {}

/// Return type of combine() -- combination of two Foos
// This is intended to implement Foo and be useless for anything else
pub struct Combined<A, B>(A, B);    // where A: Foo, B: Foo // these are intended usage, but not necessary to define the struct

impl<A, B> Foo for Combined<A, B> where A: Foo, B: Foo {}

/// Combine two Foos into a big one
pub fn combine<A, B>(a: A, b: B) -> Combined<A, B> 
    // These are intended usage, but not necessary to define the function
    // where A: Foo, B: Foo // Uncomment to improve error messages
{
    Combined(a, b)
}


fn test<F: Foo>(_: F) {}

fn main() {
    let x = combine(combine(1, 2), combine(3, 4.5));  // there is a bug on this line
    // more code
    test(x);
}

(playground)

As you can see the compiler reports an error that:

  • points at the use of x, not at the construction of it (where the bug actually is)
  • mentions its type which can be very complex and ugly and does not help much to find the bug

However it you uncomment the where bounds on the combine function, the error message is much better:

  • it points directly to the place of the bug (where we try to combine incompatible components)

So my question is: Is it considered good practice to add such unnecessary bounds? (i.e. they are not needed to implement the function, but its return type/value is useless if they are not satisfied)

Or is there other way to improve error messages?

I have noticed that e.g. Iterator::map() does the same (with F: FnMut bound), so it is ok?

How about bounds on the struct directly?

2 posts - 2 participants

Read full topic

🏷️ rust_feed