Unable to retrieve expected result type

Hello,

Here is my code example:


pub struct ResultStruct<T, U> {
    pub f: T,
    pub i: U,
}

pub fn func<T>(p: T) -> ResultStruct<T, impl ResultTrait>
where
    T: ResultTrait,
{
    p.func_trait()
}

pub trait ResultTrait {
    fn func_trait(self) -> ResultStruct<Self, impl ResultTrait>
    where
        Self: Sized;
}

impl ResultTrait for f32 {
    fn func_trait(self) -> ResultStruct<Self, i32>
    where
        Self: Sized,
    {
        ResultStruct { f: self, i: 0 }
    }
}

impl ResultTrait for i32 {
    fn func_trait(self) -> ResultStruct<Self, i32>
    where
        Self: Sized,
    {
        todo!()
    }
}

impl ResultTrait for f64 {
    fn func_trait(self) -> ResultStruct<Self, i64>
    where
        Self: Sized,
    {
        ResultStruct { f: self, i: 0 }
    }
}

impl ResultTrait for i64 {
    fn func_trait(self) -> ResultStruct<Self, i64>
    where
        Self: Sized,
    {
        todo!()
    }
}

When using func(f32::MAX).f I get f32, but func(f32::MAX).i doesn't give me i32 without casting explicitly as expected.
I need rust-analyzer to guess the result i is of type i32 when f is of type f32.
The same should apply to f64 and corresponding i64.

Why does rust-analyzer know the type of the result f without problem, but not for i ?

Thank you in advance for your answers.

This is almost surely due to RPIT in traits being a new feature, in combination with using a refined implementation (also a new concept).[1] So probably r-a is looking at the trait and only sees the opaque impl ResultTrait, versus finding the specific implementation and seeing the refined type.

For this use case, I suggest using an associated type instead of impl ResultTrait.

Probably r-a knows how to handle that, but I didn't check.


  1. Frankly I thought refinements had to error if not declared, not just warn, and didn't realize they (at least partially) landed with RPITIT. ↩ī¸Ž

Grrrrrr!!!
Great workaround, but it doesn't work for let x: i32 = func(10).i; which is what I was expecting.
Do you think I need to open an issue for this rust-analyzer problem ?

fn func_trait<T: ResultTrait>(t: T) -> ResultStruct<T, T::Err> {
    t.func_trait()
}

fn main() {
    let x: i32 = func_trait(10).i;
}

I'd say it deserves to have an issue if it doesn't already, yes.

1 Like

RPITITs should desugar to associated types (refining_impl_trait lint) and I assume would desugar to @quinedot's explicit associated type example. I wonder why r-a type inference is incorrect despite this desugaring.

1 Like

It probably just doesn't know how to, because an RPIT whose underlying type can be known to callers is a new thing as of 1.75. And the "as-if" associated type is unnameable.

Incidentally, almost everything called a "desugaring" in Rust either isn't actually desugaring, or is desugared at the MIR level or so, not at the Rust source code level. I.e. take any claim of desugaring with a grain of salt :wink:.

1 Like