-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Irrefutable slice patterns should be inferred as arrays of that length #76342
Comments
Actually there's another option, and that's references to arrays: #![allow(unused_variables)]
struct Zeroes;
impl Into<&'static [usize; 3]> for Zeroes {
fn into(self) -> &'static [usize; 3] { &[0; 3] }
}
impl Into<[usize; 3]> for Zeroes {
fn into(self) -> [usize; 3] { [0; 3] }
}
fn main() {
let [a, b, c] = Zeroes.into(); // Doesn't work: is this an `[usize; 3]` or `&[usize; 3]`?
let [d, e, f]: [_; 3] = Zeroes.into(); // Works
let [g, h, i]: &[_; 3] = Zeroes.into(); // Works
} |
What are the possible follow-up steps here? It sounds like this really is ambiguous - so either we should add a special-case to the compiler to infer |
we have the same behavior for other patterns as well: struct Foo(u32);
trait Mk {
fn mk() -> Self;
}
impl Mk for Foo {
fn mk() -> Self {
Foo(0)
}
}
impl Mk for &'static Foo {
fn mk() -> Self {
&Foo(0)
}
}
fn main() {
let mut y = Mk::mk();
// ERRORS, can be fixed by specifying the type of `y` before this statement
let Foo(_) = y;
// works
// let Foo(_): &Foo = y;
y = &Foo(1);
} in nearly all cases this works as expected however: struct Foo(u32);
struct Bar;
impl Into<&'static Foo> for Bar {
fn into(self) -> &'static Foo { &Foo(1) }
}
impl Into<Foo> for Bar {
fn into(self) -> Foo { Foo(1) }
}
fn ty<T>(_: T) {
println!("{}", std::any::type_name::<T>());
}
fn main() {
let Foo(i) = Bar.into();
ty(i); // u32
let Foo(j) = <Bar as Into<&'static Foo>>::into(Bar);
ty(j); // &u32
let Foo(k): Foo = Bar.into();
ty(k); // u32
let Foo(l): &Foo = Bar.into();
ty(l); // &u32
} I've personally never seen anyone complain about cases where this inference goes wrong. So I think we can do the same thing with arrays, as long as |
Infer type in irrefutable slice patterns with fixed length as array Fixes rust-lang/rust#76342 In irrefutable slice patterns with a fixed length, we can infer the type as an array type. We now choose to prefer some implementations over others, e.g. in: ``` struct Zeroes; const ARR: [usize; 2] = [0; 2]; const ARR2: [usize; 2] = [2; 2]; impl Into<&'static [usize; 2]> for Zeroes { fn into(self) -> &'static [usize; 2] { &ARR } } impl Into<&'static [usize]> for Zeroes { fn into(self) -> &'static [usize] { &ARR2 } } fn main() { let &[a, b] = Zeroes.into(); } ``` We now prefer the impl candidate `impl Into<&'static [usize; 2]> for Zeroes`, it's not entirely clear to me that this is correct, but given that the slice impl would require a type annotation anyway, this doesn't seem unreasonable. r? `@lcnr`
Infer type in irrefutable slice patterns with fixed length as array Fixes rust-lang/rust#76342 In irrefutable slice patterns with a fixed length, we can infer the type as an array type. We now choose to prefer some implementations over others, e.g. in: ``` struct Zeroes; const ARR: [usize; 2] = [0; 2]; const ARR2: [usize; 2] = [2; 2]; impl Into<&'static [usize; 2]> for Zeroes { fn into(self) -> &'static [usize; 2] { &ARR } } impl Into<&'static [usize]> for Zeroes { fn into(self) -> &'static [usize] { &ARR2 } } fn main() { let &[a, b] = Zeroes.into(); } ``` We now prefer the impl candidate `impl Into<&'static [usize; 2]> for Zeroes`, it's not entirely clear to me that this is correct, but given that the slice impl would require a type annotation anyway, this doesn't seem unreasonable. r? `@lcnr`
Infer type in irrefutable slice patterns with fixed length as array Fixes rust-lang/rust#76342 In irrefutable slice patterns with a fixed length, we can infer the type as an array type. We now choose to prefer some implementations over others, e.g. in: ``` struct Zeroes; const ARR: [usize; 2] = [0; 2]; const ARR2: [usize; 2] = [2; 2]; impl Into<&'static [usize; 2]> for Zeroes { fn into(self) -> &'static [usize; 2] { &ARR } } impl Into<&'static [usize]> for Zeroes { fn into(self) -> &'static [usize] { &ARR2 } } fn main() { let &[a, b] = Zeroes.into(); } ``` We now prefer the impl candidate `impl Into<&'static [usize; 2]> for Zeroes`, it's not entirely clear to me that this is correct, but given that the slice impl would require a type annotation anyway, this doesn't seem unreasonable. r? `@lcnr`
Simple demo https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=5b0acd8b21c773c9c4a3ff73bc7a030e:
This is presumably not happening because slice patterns in refutable patterns can be more than just an array of that exact size, but there's no other option for irrefutable patterns.
This would be particularly helpful as we're getting more and more
[T; N]: TryFrom<_>
implementations with const generics. See the example in #76310 for the place I first noticed this not working the way I'd hoped.Zulip topic: https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Type.20inferrence.20.26.20irrefutable.20slice.20patterns/near/209052937
The text was updated successfully, but these errors were encountered: