Rust-analyzer and Cargo give different type inferences for the same code

Sorry, English is not my main language. I'll try my best to make my word easy to understand.

I'm new in Rust, and I am working on rustlings exercis try-from-into
The exercise ask me to impl TryFrom<[i16; 3]> for Color

#[derive(Debug, PartialEq)]
struct Color {
    red: u8,
    green: u8,
    blue: u8,
}

#[derive(Debug, PartialEq)]
enum IntoColorError {
    // Incorrect length of slice
    BadLen,
    // Integer conversion error
    IntConversion,
}

Here is my solution:

impl TryFrom<[i16; 3]> for Color {
    type Error = IntoColorError;
    fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> {
        let color = arr
            .into_iter()
            .map(|color| {
                color		// VSCode told me the type of it is i16
                    .try_into()
                    .map_err(|_| IntoColorError::IntConversion)
            })
            .collect::<Result<Vec<u8>, IntoColorError>>()?;
        Ok(Color {
            red: color[0],
            green: color[1],
            blue: color[2],
        })
    }
}

VSCode told me that the type of color in map is i16, but cargo tole me the trait From<&i16> is not implemented for u8 when I compile the code. I tried to convert arr to Vec<i16>, then the code works correctly

impl TryFrom<[i16; 3]> for Color {
    type Error = IntoColorError;
    fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> {
        let color = Vec::from(arr)	// <-- Only change here
            .into_iter()
            .map(|color| {
                color		// <-- VSCode thinks it is i16 too
                    .try_into()
                    .map_err(|_| IntoColorError::IntConversion)
            })
            .collect::<Result<Vec<u8>, IntoColorError>>()?;
        Ok(Color {
            red: color[0],
            green: color[1],
            blue: color[2],
        })
    }
}

I'm so confused about this, is this a bug for rust-analyzer? Or just some feature I'm not familiar with? Thank you for reading my post, I would really appreciate it if you could solve my problem

This is a problem of Editions. In Rust Edition 2018 and before, using a method call .into_iter() on arrays like [u16; 3] does not "reveal" the implementation of IntoIterator, because arrays didn't use to implement that trait. Instead, the call to .into_iter in those editions uses Deref coercion method call resolution and finds the implementation for shared references to arrays (&[u16; 3]), which returns &u16 instead of u16.

To fix, set edition = "2021" in your Cargo.toml file. Or don't use the method call, but you should really be using the most recent Edition anyway.

Here's the Edition Guide entry for IntoIterator for arrays.

3 Likes

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.