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

Match ergonomics 2024 #3627

Open
wants to merge 21 commits into
base: master
Choose a base branch
from

Conversation

Jules-Bertholet
Copy link

@Jules-Bertholet Jules-Bertholet commented May 6, 2024

Rendered

Changes to match ergonomics for the 2024 edition.

@rustbot label T-lang A-patterns A-edition-2024

@Jules-Bertholet Jules-Bertholet changed the title Add match ergonomics 2024 RFC Match ergonomics 2024 May 6, 2024
@rustbot rustbot added A-edition-2024 Area: The 2024 edition A-patterns Pattern matching related proposals & ideas T-lang Relevant to the language team, which will review and decide on the RFC. labels May 6, 2024
Co-authored-by: kennytm <kennytm@gmail.com>
(including "inherited" references).

```rust
let &foo = &mut 42;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

foo is still immutable right?

let &foo = &mut 42;
foo = 53; // error[E0384]: cannot assign twice to immutable variable `foo`

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. (It would be immutable with let &mut foo = &mut 42; also.)

text/3627-match-ergonomics-2024.md Outdated Show resolved Hide resolved
Jules-Bertholet and others added 2 commits May 6, 2024 17:44
Co-authored-by: kennytm <kennytm@gmail.com>
@rpjohnst
Copy link

rpjohnst commented May 6, 2024

The "& patterns matching against &mut" part seems reasonable but also fairly independent of the other changes. It might make more sense as part of a deref patterns RFC, which might (or might not!) also choose to use & more generally.

@Jules-Bertholet
Copy link
Author

The "& patterns matching against &mut" part seems reasonable but also fairly independent of the other changes.

It could be split off, yes. I mention this in the rationale section, but one of the motivating factors for including it is the "no inherited ref mut behind &" rule. With that rule, whether an inherited reference is ref or ref mut (and therefore, whether it can be matched with &mut) depends on non-local factors, so allowing users to always use & unless they need mutation becomes especially important.

@rpjohnst
Copy link

rpjohnst commented May 7, 2024

The "no inherited ref mut behind &" rules seems equally independent and forwards-compatible. (And also equally reasonable! Just probably worth considering holistically alongside deref patterns.)

@Jules-Bertholet
Copy link
Author

The "no inherited ref mut behind &" rules seems equally independent and forwards-compatible.

It is not. On edition 2024, this example would work without the rule, but errors with it: let &[[&mut a]] = &[&mut [42]];

(I'll edit the RFC to make that more clear)

@rpjohnst
Copy link

rpjohnst commented May 7, 2024

I'm not sure why (a version of) "no inherited ref mut behind &" couldn't accept that example. The binding mode could be something like "ref mut behind ref" rather than flattening all the way to ref. Indeed, places behave similarly: given x: &&mut i32, *x still has type &mut i32. You may not be able to move or write through it, but that doesn't make it a &i32.

Really I'm not sure why we would even want to reject it in the first place. There is still a &mut there, after all, and the problem only arises if we try to move it out from behind a &. It would be unfortunate if, for example, let [[&mut a]] = [&mut [42]] worked but let &[[&mut a]] = &[&mut [42]] did not.

This is exactly the sort of thing that would be good to work out as part of deref patterns. Going back to the comparison with places, the reason you can get a &i32 from *x is that auto(de)ref performs a reborrow- the exact expression-side equivalent to deref patterns.

Accepting this example is a different sort of consistency than the "immutability takes precedence" one. Instead, it's "inherited reference type matches skipped reference type." This also brings back the locality that "& patterns matching against &mut" is trying to compensate for.

If we want to defer any decision at all here, I believe we could instead forbid matching &mut against "ref mut behind ref" entirely. That would make it forward compatible to implement either "no inherited ref mut behind &" or "ref mut behind ref is a distinct mode."

@Jules-Bertholet
Copy link
Author

Instead, it's "inherited reference type matches skipped reference type."

If there are several skipped reference types with different mutabilities, you have to choose: eg in let [[/*HERE*/ x]] = &[&mut[42]];, which mutability do you use to determine that of the inherited reference at HERE? So it's impossible to be fully consistent with the principle you give.

text/3627-match-ergonomics-2024.md Outdated Show resolved Hide resolved
let _: &mut u8 = foo;
```

## Edition 2024: `&` and `&mut` can match against inherited references
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like it! With this, is there even a reason to keep supporting &mut in patterns?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course, without it we can't get desugar match ergonomics that get mutable references into places: let &mut Struct { ref mut field } = ...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, okay. Sounds worthy of a clippy lint for if it's not combined with ref mut then :)

@rpjohnst
Copy link

rpjohnst commented May 7, 2024

If there are several skipped reference types with different mutabilities, you have to choose: ..., which mutability do you use to determine that of the inherited reference?

The innermost one, of course! Why would it be anything else? That's how default binding modes already work, and we're merely exposing that to the user so they can exit the current mode, not trying to reinvent how the mode is entered.

@Jules-Bertholet
Copy link
Author

The innermost one, of course! Why would it be anything else? That's how default binding modes already work

No it's not! Outer shared + inner mutable results in ref, not ref mut. https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c0c3f5fbe3499b54813bbe3af95e31eb

@rpjohnst
Copy link

rpjohnst commented May 7, 2024

What I'm saying is that it is how initially entering a default binding mode already works. That's why the example let &[[x]] = &[&mut [42]] produces x: &mut i32 even though it's underneath a &.

The inconsistency we're both talking about is the difference in behavior between "behind an explicit &" and "in default ref mode," demonstrated by the example above and your latest example let [a] = &&mut [42] => a: &i32.

You're proposing we resolve it in favor of the binding mode (essentially letting explicit & patterns change a sort of "not-yet-default binding mode); I'm proposing we resolve it in favor of the actual skipped reference type (and converting the existing ref->&mut->ref->& mode transition to a more auto(de)ref-like ref->&mut->ref mut->& mechanism), for the reasons I gave above- greater locality, and alignment with explicit patterns, places, and auto(de)ref.

@Jules-Bertholet
Copy link
Author

Jules-Bertholet commented May 7, 2024

Here's another way of looking at it: if &mut patterns "unwrap" a mutable reference, it should be possible to get a mutable reference by removing the pattern.

Simple case:

let &mut x = &mut 42; // x: i32
let x = &mut 42; // x: &mut i32

Roundabout case:

let &[&mut x] = &[&mut 42]; // x: i32
//let &[x] = &[&mut 42]; // ERROR, but…
let &[ref x] = &[&mut 42]; // x: &&mut i32 -> we can get an &mut in the end

However:

let &[[&mut x]] = &[&mut [42]]; // If we allow this, with x: i32
//let &[[x]] = &[&mut [42]]; // and then remove the &mut… -> ERROR move check, if the default binding mode is to be `ref mut`

// nothing we do will get us &mut i32 in any form

@rpjohnst
Copy link

rpjohnst commented May 7, 2024

Indeed, that is a demonstration of the fact that we are limited to a single layer of inherited reference/a single binding mode. If we relaxed that (not that I think this would be useful in practice), you could get a &mut in that last example:

let &[[&mut x]] = &[&mut [42]]; // x: i32
let &[[x]] = &[&mut [42]]; // ERROR move check, unless the pattern equivalent of auto(de)ref coerces &mut i32 -> x: &i32
let &[[ref x]] = &[&mut [42]]; // HYPOTHETICAL: A `ref` binding + an inherited `&mut` -> x: &&mut i32

My proposal is not so much breaking the user's ability to remove a &mut pattern to get a mutable reference, but (somewhat uselessly, on its own) extending that ability to all inherited &muts, and then restricting their use in the same way they are restricted in places. (With the additional possibility of making them nicer to work with via an auto(de)ref-like mechanism, as part of deref patterns.)

If I understand what you're getting at, your proposal would avoid this edge case by preemptively replacing &mut patterns with & in these places where you would be forbidden from using the &mut anyway. I think this is a reasonable design goal but it doesn't need to be accomplished by the binding modes themselves, which as you've noted, makes pattern matching less local.

@Nadrieril
Copy link
Member

that is a demonstration of the fact that we are limited to a single layer of inherited reference/a single binding mode. If we relaxed that...

It is semantically impossible to relax that. E.g.

let var = Some(0);
if let Some(x) = &&var {
   //...
}

Here x cannot be &&u32, because where would we store the &u32 that it points to? There is no &u32 in memory we could make it point to. There is however a u32, so we can have x: &u32 pointing inside var.

@rpjohnst
Copy link

rpjohnst commented May 7, 2024

Well, that was only a hypothetical to demonstrate a different way of thinking about the limitation Jules pointed out. But I don't think it's entirely impossible to materialize those extra reference layers- we could introduce temporaries for them around the match, it would just be a bit silly, and they would have shortened lifetimes. (Not to mention confusing to be able to layer binding modes like my example.)

@Jules-Bertholet
Copy link
Author

Jules-Bertholet commented May 16, 2024

I would still prefer to be able to consistently write a &mut pattern that matches an inherited reference, regardless of whether the binding mode has been converted to ref by an outer &, so long as there is a &mut value involved.

AIUI, what you're proposing would be backward compatible. There is going to be a follow-up to this RFC at some point (to choose a syntax for mutable by-reference bindings, and possibly also to provide a solution for matching &mut behind &), so we can re-evaluate this as well when the time comes.

@rpjohnst
Copy link

rpjohnst commented May 17, 2024

The reason I'm making this proposal in the first place is because it enables us to defer "& matching against &mut," narrowing the focus of this RFC significantly.

Co-authored-by: Tyler Mandry <tmandry@gmail.com>
@tmandry
Copy link
Member

tmandry commented May 17, 2024

@rfcbot reviewed

Having mulled it over, I think this RFC strikes the right balance on all the questions we need to decide now. I would also like to see us move forward with an implementation in nightly quickly to give enough time for experimentation with the new rules and with the edition migration.

Never setting default binding mode to ref mut behind &

//! All editions: works only with this rule
let &[[a]] = &[&mut [42]]; // x: &i32
//! Edition ≥ 2024: works only without this rule
let &[[&mut a]] = &[&mut [42]]; // x: i32

I would rather have the first option work than the second, especially when considering the alternatives (to binding x: &i32 and x: i32, respectively) described in the RFC.

mut on a binding with a by-reference binding mode is an error.

While I can see that we might want to allow this in the future, it's not entirely clear to me that this is the case. As the RFC states, "there is not much use for mutable by-reference bindings". They seem rare enough that I would guess a significant percentage of the time, they are not actually what the user wants when written, and when used correctly are unclear to the reader.

@Jules-Bertholet
Copy link
Author

Jules-Bertholet commented May 17, 2024

I would also like to see us move forward with an implementation in nightly quickly

ICYMI: rust-lang/rust#123076

Everything in this RFC, including the migration lint, is either already in nightly under an experimental feature gate, or waiting on PR review.

@Jules-Bertholet
Copy link
Author

I would rather have the first option work than the second, especially when considering the alternatives (to binding x: &i32 and x: i32, respectively) described in the RFC.

Reviewing this section again, I've realized that I grossly overstated my case. For the let &[[a]] = &[&mut [42]]; // x: &i32 example that works only with the proposed rule, let [[a]] = &[&mut [42]]; would work just as well, whether or not we adopt the rule. I apologize for the misrepresentation, and I've replaced the example with a better one that is more fair.

@rpjohnst
Copy link

I would rather have the first option work than the second, especially when considering the alternatives (to binding x: &i32 and x: i32, respectively) described in the RFC.

As Jules noted, it should be backwards compatible with the RFC to accept the let &[[&mut a]] = &[&mut [42]]; // a: i32 example in the future as well. So I don't think we are fundamentally choosing between these x: &i32 and x: i32 examples.

Rather, given that we want to make let &[[a]] = &[&mut [42]]; // a: &i32 work to match let [[a]] = &[&mut [42]]; // a: &i32, our choice is how to match these "downgraded" inherited references when switching back to the move binding mode:

  • The RFC proposes let &[[&a]] = &[&mut [42]]; // a: i32, and then suggests that we allow & to match non-inherited &muts as well: let a: &u8 = &mut 42;.
  • We could alternatively support let &[[&mut a]] = &[&mut [42]]; // a: i32 immediately, and leave "& patterns matching against &mut" (both inherited and non-inherited) as the backwards-compatible future extension.

@joshtriplett
Copy link
Member

@rfcbot resolve switch-to-option-1
@rfcbot reviewed

@nikomatsakis
Copy link
Contributor

@rfcbot resolve leaving-us-in-an-inconsitent-state

@rfcbot rfcbot added final-comment-period Will be merged/postponed/closed in ~10 calendar days unless new substational objections are raised. and removed proposed-final-comment-period Currently awaiting signoff of all team members in order to enter the final comment period. labels May 22, 2024
@rfcbot
Copy link
Collaborator

rfcbot commented May 22, 2024

🔔 This is now entering its final comment period, as per the review above. 🔔

@traviscross traviscross removed the I-lang-nominated Indicates that an issue has been nominated for prioritizing at the next lang team meeting. label May 22, 2024
@tmandry
Copy link
Member

tmandry commented May 25, 2024

Everything in this RFC, including the migration lint, is either already in nightly under an experimental feature gate, or waiting on PR review.

Fantastic, thanks for your efforts here. Ideally I would like to see this go in as part of the unstable 2024 edition once this RFC lands, i.e. not blocking on a stabilization FCP before that happens. I'm not sure if that's consistent or not with what we've done in the past.

Reviewing this section again, I've realized that I grossly overstated my case. For the let &[[a]] = &[&mut [42]]; // x: &i32 example that works only with the proposed rule, let [[a]] = &[&mut [42]]; would work just as well, whether or not we adopt the rule.

Thanks for the correction! The new examples feel more like a wash to me, to the point where I don't know which one to prefer.

The RFC lists arguments in favor of this rule, but what are the drawbacks? I guess this one? (It sounds like it applies, even though the surrounding conversation seems to be about the & matching &mut rule, but maybe I misunderstand):

I would still prefer to be able to consistently write a &mut pattern that matches an inherited reference, regardless of whether the binding mode has been converted to ref by an outer &, so long as there is a &mut value involved.

Are there others?

@rfcbot concern what tradeoff are we making with the "ref mut behind &" rule

If we have a clear idea of the tradeoff we're making I would think we can resolve this in a triage meeting, so nominating for discussion now.

@rustbot label I-lang-nominated

@rfcbot rfcbot added the proposed-final-comment-period Currently awaiting signoff of all team members in order to enter the final comment period. label May 25, 2024
@rustbot rustbot added the I-lang-nominated Indicates that an issue has been nominated for prioritizing at the next lang team meeting. label May 25, 2024
@rfcbot rfcbot removed the final-comment-period Will be merged/postponed/closed in ~10 calendar days unless new substational objections are raised. label May 25, 2024
@Jules-Bertholet
Copy link
Author

Jules-Bertholet commented May 25, 2024

The RFC lists arguments in favor of this rule, but what are the drawbacks? I guess this one? (It sounds like it applies, even though the surrounding conversation seems to be about the & matching &mut rule, but maybe I misunderstand):

I would still prefer to be able to consistently write a &mut pattern that matches an inherited reference, regardless of whether the binding mode has been converted to ref by an outer &, so long as there is a &mut value involved.

That's basically it.

//! Edition ≥ 2024
let  [[&mut x]] =  [&mut [42]]; // This works
let &[[&mut x]] = &[&mut [42]]; // This is broken by the proposed rule (example given in RFC)
let  [[&mut x]] = &[&mut [42]]; // This is also broken by the rule

Note that with & matching &mut, you can write:

//! Edition ≥ 2024
let  [[&x]] =  [&mut [42]]; // This works, with same meaning as example above
let &[[&x]] = &[&mut [42]]; // This also works
let  [[&x]] = &[&mut [42]]; // This as well (same meaning)

That's why & matching &mut was brought up in the conversation—it alleviates the drawbacks of the proposed rule.

@tmandry
Copy link
Member

tmandry commented May 29, 2024

Rather, given that we want to make let &[[a]] = &[&mut [42]]; // a: &i32 work to match let [[a]] = &[&mut [42]]; // a: &i32, our choice is how to match these "downgraded" inherited references when switching back to the move binding mode:

  • The RFC proposes let &[[&a]] = &[&mut [42]]; // a: i32, and then suggests that we allow & to match non-inherited &muts as well: let a: &u8 = &mut 42;.
  • We could alternatively support let &[[&mut a]] = &[&mut [42]]; // a: i32 immediately, and leave "& patterns matching against &mut" (both inherited and non-inherited) as the backwards-compatible future extension.

As I understand it, the main drawback of this alternative would be that the compiler would no longer "do the right thing" for you when matching by reference to x in &&mut x (or similar). In addition to the arguments presented in the RFC. (I also see you making references to benefits of this alternative, but I haven't had time to read far back enough to fully understand them yet.)

So we are not converging on the same place: fundamentally we have to choose, or (perhaps) go for an even more conservative "non-choice" option.

@rpjohnst Are you making an argument in favor of going with the alternative option? If so, is there a chance you could write that up in a more self-contained hackmd? Even if we accept the current RFC as-is, it would be good to include as part of the RFC alternatives section.

@Jules-Bertholet
Copy link
Author

@rpjohnst Are you making an argument in favor of going with the alternative option? If so, is there a chance you could write that up in a more self-contained hackmd? Even if we accept the current RFC as-is, it would be good to include as part of the RFC alternatives section.

My understanding of @rpjohnst's position is that he thinks we should accept the union of what the two alternatives accept (is, be maximally permissive).

@rpjohnst
Copy link

rpjohnst commented May 29, 2024

As I understand it, the main drawback of this alternative would be that the compiler would no longer "do the right thing" for you when matching by reference to x in &&mut x (or similar).

I'm not proposing that we keep the old behavior of an unusable ref mut binding mode, as in let &[a] = &&mut [42]; // ERROR because a: &mut i32. Making this work with a: &i32 was the "given that we want..." at the start of what you quoted, @tmandry. I agree with the RFC that the "binding mode is never set to ref mut behind a & value" change is useful and needs to be made over an edition.

I'm also not proposing that we be maximally permissive, @Jules-Bertholet. My primary reason for jumping into this thread has always been to make the argument that we not make the "& patterns match against &mut values" change (yet), because that overlaps with ongoing deref patterns work, and would be a backwards-compatible change if it turns out to be the right choice there.

However, as currently specified, the "no ref mut behind &" change interacts in an unfortunate way with the "inherited references" change: we "do the right thing" under all &s by using a ref binding mode instead of a ref mut binding mode, but at the same time that binding mode changes which patterns (& and/or &mut) can match the inherited reference, for when you're not binding by reference.

This is why the RFC accepts let &[[&a]] = &[&mut [42]]; but rejects let &[[&mut a]] = &[&mut [42]];, despite otherwise accepting things like let [&mut a] = &mut [42];. The RFC points to this as a supporting argument for the "& patterns match against &mut values" change, which would reduce the need to deal with this by supporting & in more places.

I look at this consequence of "no ref mut behind &" in the same way as the "& patterns match against &mut values" change. They both lead to & patterns in places where the (actual or inherited) scrutinee is of &mut type, which I would like to avoid altogether. Of course, doing this without giving up on let &[a] = &&mut [42]; // a: &i32 means changing how "no ref mut under &" works.

So in the spirit of describing this in a self-contained way, I am proposing these changes to parts 2-4 of the RFC's reference section:

  • Remove "& patterns can match against &mut references."
  • & patterns only reset the ref binding mode, and &mut patterns only reset the ref mut binding mode.
  • The binding mode is set to ref when skipping a & and to ref mut when skipping a &mut, regardless of the previous binding mode or whether we are behind a &. At the same time, the type of a binding is now determined from the combination of the current mode and the presence of an outer &.

This last point should behave the same way as the RFC (e.g. let &[a] = &&mut [42]; // a: &i32), except that it now rejects let &[[&a]] = &[&mut [42]]; and accepts let &[[&mut a]] = &[&mut [42]];. I believe this makes the RFC smaller overall, leaving the meaning of these new & patterns up to the deref pattern work, while still solving all the original problems that led to this RFC.

@tmandry
Copy link
Member

tmandry commented May 29, 2024

Many thanks for the clarifications, @rpjohnst and @Jules-Bertholet. I think I have a good grasp of your positions now.

My primary reason for jumping into this thread has always been to make the argument that we not make the "& patterns match against &mut values" change (yet), because that overlaps with ongoing deref patterns work, and would be a backwards-compatible change if it turns out to be the right choice there.

Leaving more design space open for deref patterns is desirable. At the same time, I struggle somewhat to come up with a scenario in which adopting "& matches &mut" now restricts us meaningfully in the future.

While I'd like to avoid going too deep into hypotheticals, is there any way you could sketch out the kind of question this might restrict our choices on in the future, @rpjohnst?

cc @WaffleLapkin, who was also worried about interactions here.

This last point should behave the same way as the RFC (e.g. let &[a] = &&mut [42]; // a: &i32), except that it now rejects let &[[&a]] = &[&mut [42]]; and accepts let &[[&mut a]] = &[&mut [42]];

For my own understanding, is there a "nuclear option" that rejects both of these and allows us to choose one later? Does that mean delaying "& and &mut can match against inherited references" entirely, and is that something we can even do?

@Jules-Bertholet
Copy link
Author

For my own understanding, is there a "nuclear option" that rejects both of these and allows us to choose one later? Does that mean delaying "& and &mut can match against inherited references" entirely,

It's possible to do, we would have to forbid matching against inherited references in the specific situation that the rule affects. It would be confusing and irritating for users, though. Unless there a compelling reason to think we might gain new information in the future to better inform this choice (and I don't see us), delay will not do any good IMO.

@rpjohnst
Copy link

Leaving more design space open for deref patterns is desirable. At the same time, I struggle somewhat to come up with a scenario in which adopting "& matches &mut" now restricts us meaningfully in the future.

While I'd like to avoid going too deep into hypotheticals, is there any way you could sketch out the kind of question this might restrict our choices on in the future, @rpjohnst?

It's looking like deref patterns will introduce some syntax for "deref a scrutinee of any pointer type, and then match on the result." That syntax may or may not be & itself. From the wider perspective of deref patterns, we might want these "universal & patterns" to behave in a subtly different way than whatever we come up with here, where we're only considering & and &mut.

Similarly, if we introduce "& matches &mut" now, but deref patterns choose a different syntax, we will have two different ways to match on "some kind of pointer but I don't care which." Another of the RFC's justifications for this extension of & is that it "makes refactoring less painful" - this is likely to apply to whatever deref patterns comes up with as well. It might be preferable to have only one language feature playing this role.


Regarding the "nuclear option," we would only need to reject matching on inherited references which are both A) inherited from a &mut value and B) behind &, rather than all inherited references. While rejecting & leaves space open for deref patterns, simultaneously rejecting &mut only really leaves space open to figure out the "desirable property:"

An &mut pattern is accepted if and only if removing the pattern would allow obtaining an &mut value.

Personally, I don't believe this is important. The language is full of ways to "talk about" something without being able to "get your hands on it," but these are enforced by the borrow checker, rather than by adjusting types ahead of time.

Consider that, given x: &&mut i32, the type of *x is still &mut i32 and not &i32. Imagine that & and &mut had distinct deref operators .d and .dm, like they have distinct patterns - it would still make sense to accept &x.d.dm rather than &x.d.d or x.d, and to reject &mut x.d.dm in the borrow checker rather than the type checker.

When you rely on auto(de)ref to get a &i32 out of *x, it works by desugaring to &**x. In fact, even when you try to get a &mut i32 out of *x, the error you get is a failure to reborrow **x.

To me it seems more in line with the rest of the language to accepting &mut patterns (the pattern corresponding to my made-up .dm expressions) even in places that don't permit mutation, or mutable reborrowing, or otherwise materializing a &mut.

@tmandry
Copy link
Member

tmandry commented May 29, 2024

The deciding factor is ultimately whether the lang team has considered all of the information it thinks is relevant, or will have time to do so, without either delaying the edition or risking this RFC as part of it.

For my own understanding, is there a "nuclear option" that rejects both of these and allows us to choose one later? Does that mean delaying "& and &mut can match against inherited references" entirely,

It's possible to do, we would have to forbid matching against inherited references in the specific situation that the rule affects. It would be confusing and irritating for users, though.

What about the second part of my question — delaying "& and &mut can match against inherited references" until we have a firm decision one way or the other?

We all agree this feature is desirable, and I would like to ship it as part of the story we tell for the edition. But we also have to prioritize decisions that must be made for the edition (and we are whittling those down quickly, knock on wood).

Is this feature inherently edition sensitive on its own?

@Jules-Bertholet
Copy link
Author

Jules-Bertholet commented May 29, 2024

Is this feature inherently edition sensitive on its own?

Yes, at least if we adopt the "eat-one-layer" model as proposed (and alternative models have their own issues.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-edition-2024 Area: The 2024 edition A-patterns Pattern matching related proposals & ideas disposition-merge This RFC is in PFCP or FCP with a disposition to merge it. I-lang-nominated Indicates that an issue has been nominated for prioritizing at the next lang team meeting. proposed-final-comment-period Currently awaiting signoff of all team members in order to enter the final comment period. T-lang Relevant to the language team, which will review and decide on the RFC.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet