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

Why doesn't let (&x, &y) = &(t, t,) work? #71730

Closed
crlf0710 opened this issue May 1, 2020 · 7 comments
Closed

Why doesn't let (&x, &y) = &(t, t,) work? #71730

crlf0710 opened this issue May 1, 2020 · 7 comments
Labels
A-patterns Relating to patterns and pattern matching C-bug Category: This is a bug.

Comments

@crlf0710
Copy link
Member

crlf0710 commented May 1, 2020

I'm not sure whether this is a bug or not, feel free to close if it's not.
I tried this code:

fn foo1() {
    let c = 1i32;
    let &x = &c;
}

fn foo2() {
    let c = (1i32, 2i32);
    let (&x, &y) = &c;
}

I expected to see this happen: Everything compiles fine, since components of the tuple are all Copy.

Instead, this happened: The second case fails with bad diagnostics.

@crlf0710 crlf0710 added the C-bug Category: This is a bug. label May 1, 2020
@lcnr
Copy link
Contributor

lcnr commented May 1, 2020

Afaik this is intended behavior. You don't have a tuple of references but a reference to a tuple.
I don't think match ergonomics should allow this.

fn foo2() {
    let c = (1i32, 2i32);
    let &(x, y) = &c;
    // This works
}

@crlf0710
Copy link
Member Author

crlf0710 commented May 1, 2020

Thanks.

@crlf0710 crlf0710 closed this as completed May 1, 2020
@crlf0710 crlf0710 reopened this May 6, 2020
@crlf0710
Copy link
Member Author

crlf0710 commented May 6, 2020

Thinking more about this, i still think it's a little weird that this doesn't work.

// this works fine
fn foo3((a, b): &(i32, i32)) {
}

// this doesn't
fn foo4((&a, &b): &(i32, i32)) {                                                                                                                                                                                                                } 

I think this should work for consistency, because there should only be one meaning for & within patterns: matching reference and dereference it.

@crlf0710 crlf0710 added the A-patterns Relating to patterns and pattern matching label May 6, 2020
@tesuji
Copy link
Contributor

tesuji commented May 6, 2020

But this does work:

fn foo4(&(a, b): &(i32, i32)) {}

I think pattern matching is consistent here.

@memoryruins
Copy link
Contributor

memoryruins commented May 6, 2020

foo3 compiles with a and b now having the type &i32. The only dereference pattern that is applicable is on the outside of the tuple, seen in lzutao's and lcnr's examples.

Some additional variations with explicit types if it helps make the current behavior clearer:

fn main() {
    let c: (u8, u8) = (0, 1);
    //
    let (x, y): &(u8, u8) = &c;
    let _: (&u8, &u8) = (x, y);
    //
    let (ref x, ref y): &(u8, u8) = &c;
    let _: (&u8, &u8) = (x, y);
    //
    let &(x, y): &(u8, u8) = &c;
    let _: (u8, u8) = (x, y);
    //
    let (x, y): &(u8, u8) = &c;
    let (&x, &y): (&u8, &u8) = (x, y);
    let _: (u8, u8) = (x, y);
    //
    let &(x, ref y): &(u8, u8) = &c;
    let _: (u8, &u8) = (x, y);
}

fn foo3((a, b): &(i32, i32)) {
    let _: &i32 = a;
    let _: &i32 = b;
}

fn foo3_2((ref a, ref b): &(i32, i32)) {
    let _: &i32 = a;
    let _: &i32 = b;
}

// fn foo4((&a, &b): &(i32, i32)) {}

fn foo4_2(&(a, b): &(i32, i32)) {
    let _: i32 = a;
    let _: i32 = b;
}

The RFC for match ergonomics might help clarify the current binding modes:
https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md

@crlf0710
Copy link
Member Author

crlf0710 commented May 6, 2020

Sorry, i still feel i'm missing something important here, i'm not finding a way to express myself, but just examining the rules and design goals. Let me list my way of thinking and assumptions :(
a. Match ergonomics can and should be able to fully replace all old usages of ref keyword. If it covers most cases but leave some corner cases behind, it's a design flaw.
b.

fn foo3(&(a, ref b): &(i32, i32)) {
}

currently works.
c.

fn foo3((&a, b): &(i32, i32)) {
}

Conceptually should work exactly as the previous program. However it doesn't.
d.
There's nothing really stopping us for mending this flaw, other than amount of work.

@workingjubilee workingjubilee changed the title One tricky corner case in patterns. Why doesn't let (&x, &y) = &(t, t,) work? Mar 12, 2023
@Nadrieril
Copy link
Member

Closing as a duplicate of #64586 (feel free to reopen if I misunderstood)

@Nadrieril Nadrieril closed this as not planned Won't fix, can't repro, duplicate, stale Dec 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-patterns Relating to patterns and pattern matching C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

5 participants