7

What happens when pattern-matching against a reference with a pattern that doesn't include a reference?

Here's an example using a struct pattern:

fn main() {
    struct S(u32);
    let S(x) = &S(2);
    // type of x is `&u32`
}

The behavior is surprising to me because the pattern on the left does not seem to match the data on the right, unlike let &S(x) = &S(2) where the &s line up.

It looks like what is happening is that when the RHS is a struct reference and the lhs is a struct pattern with field patterns, the type of the variable in the field pattern is &F where F is the type of the field.

What I am looking for is:

  • a reference that explains what the expected behavior is
  • an explanation of what the behavior is that is general enough to explain what happens with tuples and enums in addition to structs. For example, in let (x,) = &(2,); the type of x is i32 (correction: &i32).

I couldn't find anything about this in the Rust Reference or the Rust Book, but I may have missed it.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
Max Heiber
  • 14,346
  • 12
  • 59
  • 97
  • it's just auto ref in action, people complaining when code compile will always surprise me. – Stargateur Jan 09 '22 at 14:47
  • 2
    @Stargateur Not autoref, it's match ergonomics. The example fails to compile prior to Rust 1.26, and autoref was present in 1.0. – user4815162342 Jan 09 '22 at 14:54
  • 2
    @Stargateur not complaining, just trying to understand the behavior so I can use the features and read code most effectively. The resources linked in https://stackoverflow.com/a/70642417/2482570 helped me. – Max Heiber Jan 09 '22 at 15:04
  • @user4815162342 whatever it's call, autoref make sense to me – Stargateur Jan 09 '22 at 15:09
  • 1
    I didn't know what "autoref" meant, so looked it up and am linking here in case it's helpful for future readers: afaict the terminology refers to the final step of "adjustment" in method calls ("Then, for each candidate T, add &T and &mut T to the list immediately after") https://doc.rust-lang.org/reference/expressions/method-call-expr.html, based on the "autoref" in title of this issue: https://github.com/rust-lang/reference/issues/62 – Max Heiber Jan 09 '22 at 15:12
  • 1
    Yeah autoref just adds some implicit &. So if you have T you can call methods from &T without using the ampersand/explicit reference. – MeetTitan Jan 09 '22 at 15:16
  • 2
    @Stargateur Half of the compiler's job is to reject unsound programs. If you think your program has an issue, and the compiler doesn't flag it, you should be worried (if only because it suggests that your understanding of the compiler is incomplete). – BallpointBen Jan 10 '22 at 04:20

1 Answers1

10

The behavior you encountered was introduced with "match ergonomics" in Rust 1.26 and is described in its own RFC. In short, when matching references against non-reference patterns, the binding mode is switched to use ref binding by default.

In your case, let S(x) = &S(2) desugars to let &S(ref x) = &S(2). The "legacy" status of ref is shortly discussed in the Rust book.

an explanation of what the behavior is that is general enough to explain what happens with tuples and enums in addition to structs. For example, in let (x,) = &(2,); the type of x is i32.

This is incorrect - if you ask Rust for the type of x, it will tell you it is &i32, as one would expect:

let (x,) = &(2i32,);
let () = x;
//       ^^   - this expression has type `&i32`

In other words, the same binding-mode rules that apply to structs and enums also apply to tuples.

user4815162342
  • 141,790
  • 18
  • 296
  • 355
  • why not answer it in the duplicate ? now we have two question that answer the same question. I vote to close the other question since I found this Q&A is better quality – Stargateur Jan 09 '22 at 15:10
  • 1
    @Stargateur I wasn't aware of a duplicate when I was writing the response. If you're referring to [this one](https://stackoverflow.com/q/68063555/1600898), it seems to ask the question from a different angle, so my response wouldn't apply anyway. – user4815162342 Jan 09 '22 at 15:22