Skip to content
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

Cannot infer const parameter that has a default value #83687

Closed
Soveu opened this issue Mar 30, 2021 · 4 comments
Closed

Cannot infer const parameter that has a default value #83687

Soveu opened this issue Mar 30, 2021 · 4 comments
Labels
C-bug Category: This is a bug.

Comments

@Soveu
Copy link
Contributor

Soveu commented Mar 30, 2021

I tried this code:

#![feature(const_generics_defaults)]

struct Array<const N: usize = 1>([u32; N]);

impl<const N: usize> Array<N> {
    fn from_slice(_s: &[u32]) -> &Self {
        todo!();
    }
}

fn main() {
    let slice = [1u32, 2, 3, 4];
    let arr = Array::from_slice(&slice);
}

I expected to see this happen:
Code compiles and arr is Array<1>, because of the default.

Instead, this happened:

warning: the feature `const_generics_defaults` is incomplete and may not be safe to use and/or cause compiler crashes
 --> infer.rs:1:12
  |
1 | #![feature(const_generics_defaults)]
  |            ^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(incomplete_features)]` on by default
  = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information

error[E0282]: type annotations needed for `&Array<{_: usize}>`
  --> infer.rs:13:15
   |
13 |     let arr = Array::from_slice(&slice);
   |         ---   ^^^^^ cannot infer the value of const parameter `N` declared on the struct `Array`
   |         |
   |         consider giving `arr` the explicit type `&Array<{_: usize}>`, where the type parameter `N` is specified
   |
help: consider specifying the const argument
   |
13 |     let arr = Array::<N>::from_slice(&slice);
   |               ^^^^^^^^^^

error: aborting due to previous error; 1 warning emitted

For more information about this error, try `rustc --explain E0282`.

Meta

rustc --version --verbose:

rustc 1.53.0-nightly (07e0e2ec2 2021-03-24)
binary: rustc
commit-hash: 07e0e2ec268c140e607e1ac7f49f145612d0f597
commit-date: 2021-03-24
host: x86_64-unknown-linux-gnu
release: 1.53.0-nightly
LLVM version: 12.0.0

No backtrace

@Soveu Soveu added the C-bug Category: This is a bug. label Mar 30, 2021
@fmease
Copy link
Member

fmease commented Mar 31, 2021

Default type/const parameters are not taken into consideration during type inference. This is an already known flaw. See a Reddit comment of mine.

I think this is a duplicate of #27336

@Soveu
Copy link
Contributor Author

Soveu commented Apr 16, 2021

Lets take for example this code

struct VirtAddr<T = ()>(*const T);

impl<T> VirtAddr<T> {
    const fn new(ptr: *const T) -> Self {
        Self(ptr)
    }
}

fn main() {
    let a: VirtAddr = VirtAddr::new(std::ptr::null());
    let b: VirtAddr<()> = a;
}

Clearly, VirtAddr::new gets de-sugared into VirtAddr::<()>::new, so why can't here Array::from_slice de-sugar into Array::<1usize>::from_slice?

EDIT: Actually, just leaving
let a = VirtAddr::new(std::ptr::null()) without
let b: VirtAddr<()> = a
does not work either 🤔

@Soveu
Copy link
Contributor Author

Soveu commented Apr 16, 2021

I guess I will close this issue as this is consistent with other behavior

@Soveu Soveu closed this as completed Apr 16, 2021
@fmease
Copy link
Member

fmease commented Apr 18, 2021

Clearly, VirtAddr::new gets de-sugared into VirtAddr::<()>::new

That is actually not true. Since the associated function new is defined for VirtAddr<T> for all types T: Sized, the subexpression VirtAddr::new in the third from last line is treated as <VirtAddr<?T>>::new by the type checker where ?T denotes an inference variable. In the type annotation on the other hand, VirtAddr expands to VirtAddr<()> due to the default argument.

As a result, we have VirtAddr<()> on the left side and VirtAddr<?T> on the right side (ignoring the call to new here).
During unification, the type checker gets to know that ?T == () and thus everything works out.

Only if you were to write <VirtAddr>::new, it would get resolved to <VirtAddr<()>>::new.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

2 participants