Where bound for type equality with GAT without cycles

⚓ Rust    📅 2026-01-04    👤 surdeus    👁️ 2      

surdeus

Consider this code:

use higher_kinded_types::ForLifetime;

pub trait LendingFn<T> {
    type Output<'a>
    where
        Self: 'a;
    fn call<'a>(&'a self, args: T) -> Self::Output<'a>;
}

trait Foo {
    type Bar;
    fn bar(&self) -> Self::Bar;
}

struct Baz<V>
where
    V: ForLifetime,
    for<'a> V::Of<'a>: Foo,
{
    bar: <V::Of<'static> as Foo>::Bar,
}

impl<V> Baz<V>
where
    V: ForLifetime,
    for<'a> V::Of<'a>: Foo,
{
    fn baz<F>(f: F) -> Self
    where
        F: for<'a> LendingFn<(), Output<'a> = V::Of<'a>>,
        // <V<'a> as Foo>::Bar = <V<'static> as Foo>::Bar
    {
        let foo = f.call(());
        let bar = foo.bar();
        Self { bar }
    }
}

Basically, I need to extract Bar from the output of a lending function, and that Bar in itself isn't the reason for GAT and will always be the same for any implementation. But I can't use <V<'a> as Foo>::Bar as <V::Of<'static> as Foo>::Bar because it must not be true. I would like to enforce in the where bound that those types end up equal so that code can rely on it.

Some of my attempts to write such a bound resulted in error[E0391]: cycle detected when computing the bounds for type parameter V.


My assumption is that Bar for types like that are considered different by the type system:

#[derive(Clone, Copy)]
struct FooI1<'a>(&'a u8);
impl<'a> Foo for FooI1<'a> {
    type Bar = &'a u8;
    fn bar(&self) -> Self::Bar {
        self.0
    }
}

#[derive(Clone, Copy)]
struct FooI2<'a>(&'static u8, std::marker::PhantomData<&'a ()>);
impl<'a> Foo for FooI2<'a> {
    type Bar = &'static u8;
    fn bar(&self) -> Self::Bar {
        self.0
    }
}

1 post - 1 participant

Read full topic

🏷️ Rust_feed