Another GAT issue: for<'a> <_ as S>::T<'a>: U<'a> is not satisfied

I am facing a problem that can be demonstrated as follows. In the code below, the generic associated type (Machine::Datum<'a>) for MyMachine is MyDatum<'a>. For all 'a, MyDatum<'a> implements MaybeString<'a>`:

impl<'a> MaybeString<'a> for MyDatum<'a> { /* … */ }

Yet for<'a> <M as Machine>::Datum<'a>: MaybeString<'a> is not fulfilled when M is MyMachine.

Here is the code example:

#![feature(generic_associated_types)]

struct MyDatum<'a> {
    s: &'a str,
}

trait MaybeString<'a> {
    fn get_str(&self) -> Option<&'a str>;
}

impl<'a> MaybeString<'a> for MyDatum<'a> {
    fn get_str(&self) -> Option<&'a str> {
        Some(self.s)
    }
}

trait Machine {
    type Datum<'a>;
}

struct MyMachine {}

impl Machine for MyMachine {
    type Datum<'a> = MyDatum<'a>;
}

fn run<M>(m: M)
where
    M: Machine,
    for<'a> <M as Machine>::Datum<'a>: MaybeString<'a>,
{
}

fn main() {
    run(MyMachine {});
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `for<'a> <_ as Machine>::Datum<'a>: MaybeString<'a>` is not satisfied
  --> src/main.rs:35:5
   |
35 |     run(MyMachine {});
   |     ^^^ the trait `for<'a> MaybeString<'a>` is not implemented for `<_ as Machine>::Datum<'a>`
   |
note: required by a bound in `run`
  --> src/main.rs:30:40
   |
27 | fn run<M>(m: M)
   |    --- required by a bound in this
...
30 |     for<'a> <M as Machine>::Datum<'a>: MaybeString<'a>,
   |                                        ^^^^^^^^^^^^^^^ required by this bound in `run`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` due to previous error

Am I expecting too much from the compiler to recognize this? What can I do? Add a bound for each lifetime that I actually need/use?


Not sure of that's even possible with(out?) introducing bogus lifetime arguments to the function.

Update: Doesn't work, because a lifetime given as argument must live as long as the function runs, see details below:

Details
#![feature(generic_associated_types)]

struct MyDatum<'a> {
    s: &'a str,
}

trait MaybeString<'a> {
    fn from_str(s: &'a str) -> Self;
    fn get_str(&self) -> Option<&'a str>;
}

impl<'a> MaybeString<'a> for MyDatum<'a> {
    fn from_str(s: &'a str) -> Self {
        MyDatum { s }
    }
    fn get_str(&self) -> Option<&'a str> {
        Some(self.s)
    }
}

trait Machine {
    type Datum<'a>;
}

struct MyMachine {}

impl Machine for MyMachine {
    type Datum<'a> = MyDatum<'a>;
}

fn run<'a1, M>(_m: M)
where
    M: Machine,
    //<M as Machine>::Datum<'static>: MaybeString<'static>,
    <M as Machine>::Datum<'a1>: MaybeString<'a1>,
{
    //let s = "Static";
    //let _ = <M as Machine>::Datum::<'_>::from_str(s);
    let s1_string = "Non-static".to_string();
    let s1 = &s1_string;
    let _ = <M as Machine>::Datum::<'_>::from_str(s1);
}

fn main() {
    run(MyMachine {});
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0597]: `s1_string` does not live long enough
  --> src/main.rs:40:14
   |
31 | fn run<'a1, M>(_m: M)
   |        --- lifetime `'a1` defined here
...
40 |     let s1 = &s1_string;
   |              ^^^^^^^^^^ borrowed value does not live long enough
41 |     let _ = <M as Machine>::Datum::<'_>::from_str(s1);
   |             ----------------------------------------- argument requires that `s1_string` is borrowed for `'a1`
42 | }
   | - `s1_string` dropped here while still borrowed

For more information about this error, try `rustc --explain E0597`.
error: could not compile `playground` due to previous error

It looks like I need a HRTB here. But the compiler doesn't recognize that MyMachine fulfills it. :frowning:

I like translating these lifetime-only GAT examples back into stable Rust. Let's see what we get.

struct MyDatum<'a> {
    s: &'a str,
}

trait MaybeString<'a> {
    fn get_str(&self) -> Option<&'a str>;
}

impl<'a> MaybeString<'a> for MyDatum<'a> {
    fn get_str(&self) -> Option<&'a str> {
        Some(self.s)
    }
}

trait HasDatum<'a> {
    type Datum;
}
type Datum<'a, T> = <T as HasDatum<'a>>::Datum;

trait Machine: for<'a> HasDatum<'a> {}

struct MyMachine {}

impl<'a> HasDatum<'a> for MyMachine {
    type Datum = MyDatum<'a>;
}

impl Machine for MyMachine {}

fn run<M>(m: M)
where
    M: Machine,
    for<'a> Datum<'a, M>: MaybeString<'a>,
{
}

fn main() {
    run(MyMachine {});
}
error[E0277]: the trait bound `for<'a> <_ as HasDatum<'a>>::Datum: MaybeString<'a>` is not satisf
   --> src/main.rs:38:5
    |
 38 |     run(MyMachine {});
    |     ^^^ the trait `for<'a> MaybeString<'a>` is not implemented for `<_ as HasDatum<'a>>::Datum`
    |
 note: required by a bound in `run`
   --> src/main.rs:33:27
    |
 30 | fn run<M>(m: M)
    |    --- required by a bound in this
 ...
 33 |     for<'a> Datum<'a, M>: MaybeString<'a>,
    |                           ^^^^^^^^^^^^^^^ required by this bound in `run`

wonderful, it's the same error :sweat_smile:


Let me try some things, how about implementing a helper trait for this higher-ranked bound? [short failed attempt to even reasonably do this elided…]


That's curious, the error message consistently uses _ instead of MyMachine. Does it change if we more explicitly specify the type in the call?

fn main() {
    run::<MyMachine>(MyMachine {});
}

:sweat_smile: aaaand... now it compiles. (With the GAT version, too.) Don't ask me why, feels like a bug to me that this additional information makes a difference here.

1 Like

Hrm… watch out for _'s then…

Yeah, I think so too. Unless someone else comes up with another explanation, I'll open an issue.

P.S.: I think this issue is already reported, still investigating… Yep, here it is: #88460. I added a comment with your workaround.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.