Skip to content

Generic Type can't inference properly #119469

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Jianqoq opened this issue Dec 31, 2023 · 8 comments
Closed

Generic Type can't inference properly #119469

Jianqoq opened this issue Dec 31, 2023 · 8 comments
Labels
A-inference Area: Type inference C-feature-request Category: A feature request, i.e: not implemented / a PR. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@Jianqoq
Copy link

Jianqoq commented Dec 31, 2023

for example:

pub fn save_compressed<'a,T: CommonBounds + ToBytes<Bytes = [u8; N]>,const N: usize, const M: usize>(file_name: &'a str, tensors: [(&'a str, T); M])

pub fn load_compressed<T: CommonBounds + FromBytes<Bytes = [u8; N]>,const N: usize,const M: usize>(file_name: String, queries: [(&str, &[Slice]); M])

Rust can do type inference for save_compressed correctly without any generic type hinting. But for load_compressed_slice, we have to pass all Generic type.

let a: i32 = 1;

save_compressed("file", [
    ("a", a.clone()),
    ("b", a.clone()),
]);

let _ = load_compressed::<i32>("file".to_string(), [
    ("b", &[Slice::Full(..)]),
])?;
12  |     let _ = load_compressed::<i32>("file".to_string(), [
    |             ^^^^^^^^^^^^^^^^^^^^^   --- supplied 1 generic argument
    |             |
    |             expected 3 generic arguments
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Dec 31, 2023
@Jianqoq
Copy link
Author

Jianqoq commented Dec 31, 2023

The library num-traits-0.2.17 only impl

#[cfg(not(has_int_to_from_bytes))]
impl FromBytes for i32 {
    type Bytes = [u8; 4];
    #[inline]
    fn from_be_bytes(bytes: &Self::Bytes) -> Self {
        Self::from_be(<Self as FromBytes>::from_ne_bytes(bytes))
    }
    #[inline]
    fn from_le_bytes(bytes: &Self::Bytes) -> Self {
        Self::from_le(<Self as FromBytes>::from_ne_bytes(bytes))
    }
    #[inline]
    fn from_ne_bytes(bytes: &Self::Bytes) -> Self {
        unsafe { transmute(*bytes) }
    }
}

So Rust should be able to know the const Generic types

@SkiFire13
Copy link
Contributor

Could you format your code using triple ticks? It helps reading your code a lot easier. Like this:

```
Your code goes here
```

For more details see https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax


That said num-traits implements FromBytes for multiple types, not just i32, so there's nothing constraining your call to T = i32. For example T = u64 and N = 8 or T = f32 and N = 4 are also valid substitutions for your call, so it is actually ambiguous.

@Jianqoq
Copy link
Author

Jianqoq commented Jan 1, 2024

So based on my observation, when I simply use

let a: i32 = 1;
save_compressed("file", [
    ("a", a.clone()),
    ("b", a.clone()),
]);

It looks like Rust knows a is i32 and Rust tried to find N which is the number of bytes, M is also already known which is the len of the input array, so Rust can auto fill all the generic types and can compile the code above.

But for the function load_compressed, since our inputs type doesn't include T, so we need to pass i32 which is load_compressed::<i32>, so now Rust knows T is i32, then Rust can find N itself. However, it turns out it can't. And even M which is the len of the input array, we also need to pass M to load_compressed, which means we have to write let _ = load_compressed::<i32, 4, 1>("file".to_string(), [("b", &[Slice::Full(..)])])?; so that we can pass the compilation.

I think when Rust fails to infer a generics, all generics that follow will fail, and that shouldn't happen.

@SkiFire13
Copy link
Contributor

so we need to pass i32 which is load_compressed::<i32>, so now Rust knows T is i32, then Rust can find N itself

The problem with this attempt is that you can't specify just one single generic argument, you need to specify all of them. This doesn't mean the compiler can't infer the other ones given the first, just that the language requires you to specify all of them. Think for example if you instead wanted to specify what is N rather than the other parameters, it would be ambiguous to just write load_compressed::<4>.

Having to specify all the generic arguments doesn't mean you can't have the compiler infer some of them. You can in fact just use the inferred type _ for them, and that will make the compiler still try to infer them. So in your example you would write let _ = load_compressed::<i32, _, _>("file".to_string(), [("b", &[Slice::Full(..)])])?;

@Jianqoq
Copy link
Author

Jianqoq commented Jan 2, 2024

Ok, that makes sense now, I though that Rust takes the generic argument based on the based on the generic arguments order in the function signature. Thank you!

@Jianqoq
Copy link
Author

Jianqoq commented Jan 4, 2024

After try with load_compressed::<i32, _, _>, I found that it doesn't work.

error[E0747]: type provided when a constant was expected
  --> src/main.rs:29:28
   |
29 |     load_compressed::<i32, _, _>("file".to_string(), ["a"]);
   |                            ^
   |
   = help: const arguments cannot yet be inferred with `_`

@Jianqoq
Copy link
Author

Jianqoq commented Jan 4, 2024

Example Code:

use num::traits::{ FromBytes, ToBytes };
pub fn save_compressed<'a, T: ToBytes<Bytes = [u8; N]>, const N: usize, const M: usize>(
    file_name: &'a str,
    data: [(&'a str, T); M]
) {
    todo!()
}

pub fn load_compressed<T: FromBytes<Bytes = [u8; N]>, const N: usize, const M: usize>(
    file_name: String,
    queries: [&str; M]
) {
    todo!()
}
fn main() -> anyhow::Result<()> {
    let r = 1i32;
    save_compressed("ok", [("a", r)]);
    load_compressed::<i32, _, _>("file".to_string(), ["a"]);
    Ok(())
}

Error message:

error[E0747]: type provided when a constant was expected
  --> src/main.rs:18:28
   |
18 |     load_compressed::<i32, _, _>("file".to_string(), ["a"]);
   |                            ^
   |
   = help: const arguments cannot yet be inferred with `_`

@jieyouxu jieyouxu added the A-inference Area: Type inference label Feb 16, 2024
@fmease fmease added T-lang Relevant to the language team, which will review and decide on the PR/issue. C-feature-request Category: A feature request, i.e: not implemented / a PR. and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Mar 1, 2024
@fmease
Copy link
Member

fmease commented Mar 1, 2024

Closing as works as intended / duplicate of the closed issue #41718 and the RFCs rust-lang/rfcs#1196 and rust-lang/rfcs#2176. If you disagree with my assessment I can of course reopen this issue.

@fmease fmease closed this as not planned Won't fix, can't repro, duplicate, stale Mar 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-inference Area: Type inference C-feature-request Category: A feature request, i.e: not implemented / a PR. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

5 participants