简体   繁体   中英

Why do I get a Rust compilation error when combining higher-rank trait bounds with associated types?

I am writing some Rust code that involves generic traits and non- 'static types, and as a result I have come across the need to approximate generic associated types . I understand that GATs can't be emulated elegantly in current Rust, but I thought I had figured out an (inelegant) workaround that would work for my specific situation, using traits with lifetime parameters and higher-rank trait bounds. However, I am getting compiler errors that I don't understand, regarding missing trait implementations for associated types.

The following code shows a minimal example that reproduces the error.

use std::fmt::Debug;

trait Resource<'r> {
    type Value;
}

struct ResourceImpl();

impl<'r> Resource<'r> for ResourceImpl {
    type Value = u32;
}

fn test_generic<R>()
where
    for<'r> R: Resource<'r>,
    for<'r> <R as Resource<'r>>::Value: Debug,
{
}

fn test_specific() {
    test_generic::<ResourceImpl>();
}

When I try to compile this code ( rustc 1.41.0), I get the following error message.

error[E0277]: `<ResourceImpl as Resource<'r>>::Value` doesn't implement `std::fmt::Debug`
  --> src/lib.rs:21:5
   |
13 | fn test_generic<R>()
   |    ------------
...
16 |     for<'r> <R as Resource<'r>>::Value: Debug,
   |                                         ----- required by this bound in `test_generic`
...
21 |     test_generic::<ResourceImpl>();
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `<ResourceImpl as Resource<'r>>::Value` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
   |
   = help: the trait `for<'r> std::fmt::Debug` is not implemented for `<ResourceImpl as Resource<'r>>::Value`

The error message sounds like it is saying u32 doesn't implement Debug , which wouldn't make sense. I must be misunderstanding what the error message means, but I can't figure out what the actual problem is.

There is an open issue about this problem.

In your case a workaround could be to bind Debug to the associated type Resource::Value ?

trait Resource<'r> {
    type Value: Debug;
}.

As attdona pointed out, this appears to be a compiler bug (with an open issue here ). The discussion on that issue points to this Stack Overflow question , which provides a workaround that worked for me. The key point of the workaround is that the trait mentioned inside the higher-rank trait bound must have lifetime parameters matching those inside the for<_> . This can be achieved by creating a wrapper trait (in this case around Debug ) with the required lifetime parameters.

In the case of the minimal example given in the question, the workaround looks like this:

use std::fmt::Debug;

trait Resource<'r> {
    type Value;
}

struct ResourceImpl();

impl<'r> Resource<'r> for ResourceImpl {
    type Value = u32;
}

trait DebugWithLifetime<'r>: Debug {}

impl<'r, T> DebugWithLifetime<'r> for T where T: Debug {}

fn test_generic<R>()
where
    for<'r> R: Resource<'r>,
    for<'r> <R as Resource<'r>>::Value: DebugWithLifetime<'r>,
{
}

fn test_specific() {
    test_generic::<ResourceImpl>();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM