-
Notifications
You must be signed in to change notification settings - Fork 13.6k
lower pattern bindings in the order they're written and base drop order on primary bindings' order #143764
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
base: master
Are you sure you want to change the base?
Conversation
This avoids scheduling drops and immediately unscheduling them. Drops for guard bindings/temporaries are still scheduled and unscheduled as before.
Some changes occurred in match lowering cc @Nadrieril |
to kick the crater run off @bors2 try |
lower pattern bindings in the order they're written and base drop order on primary bindings' order To fix #142163, this PR does two things: - Makes match arms base their drop order on the first sub-branch instead of the last sub-branch. Together with the second change, this makes bindings' drop order correspond to the relative order of when each binding first appears (i.e. the order of the "primary" bindings). - Lowers pattern bindings in the order they're written (still treating the right-hand side of a ``@`` as coming before the binding on the left). In each sub-branch of a match arm, this is the order that would be obtained if the or-alternatives chosen in that sub-branch were inlined into the arm's pattern. This both affects drop order (making bindings in or-patterns not be dropped first) and fixes the issue in [this test](https://github.com/rust-lang/rust/blob/2a023bf80a6fbd6a06d5460a34eb247b986286ed/tests/ui/pattern/bindings-after-at/bind-by-copy-or-pat.rs) from #121716. My approach to the second point is admittedly a bit trickier than may be necessary. To avoid passing around a counter when building `FlatPat`s, I've instead added just enough information to recover the original structure of the pattern's bindings from a `MatchTreeSubBranch`'s path through the `Candidate` tree. Some alternatives: - We could use a counter, then sort bindings by their ordinals when making `MatchTreeSubBranch`es. - I'd like to experiment with always merging sub-candidates and removing `test_remaining_match_pairs_after_or`; that would require lowering bindings and guards in a different way. That makes it a bigger change too, though, so I figure it might be simplest to start here. - For a very big change, we could track which or-alternatives succeed at runtime to base drop order on the binding order in the particular alternatives matched. This is a breaking change. It will need a crater run, language team sign-off, and likely updates to the Reference. This will conflict with #143376 and probably also #143028, so they shouldn't be merged at the same time. r? `@matthewjasper` or `@Nadrieril`
@craterbot check |
👌 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
🚧 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
🎉 Experiment
|
The regressions look unrelated as far as I can tell: 3 crashes in lld and two errors building non-rust dependencies (jq and fltk). The "fixed" crates also look unrelated: previously they'd encountered a file permissions error in a build script, a failure to build a non-rust dependency (jq), and a failure to resolve a dependency (arcstr). I think that means none of the tested crates encountered the change in drop-checking. Hopefully nothing relies on the current drop order for runtime correctness (I'd be surprised/impressed if so!) |
match parents { | ||
None => bug!("can't inline or-pattern bindings: already inlined all bindings"), | ||
Some(mut parents) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: you're starting the function with an unwrap()
, I think it would be a bit clearer to not take an Option
and unwrap remainder
before the call below
fn push_sub_branch_bindings<'c, 'tcx>( | ||
flattened: &mut Vec<Binding<'tcx>>, | ||
parents: Option<&'c [PatternExtraData<'tcx>]>, | ||
leaf_bindings: &[SubpatternBindings<'tcx>], | ||
) -> Option<&'c [PatternExtraData<'tcx>]> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might this be simplified by having it take a it: &mut impl Iterator<Item=&[SubpatternBindings<'tcx>]
and passing it parents.iter().map(|parent| parent.bindings.as_slice()).filter(|bindings| !bindings.is_empty()).chain([leaf_bindings])
? Then you'd just call it.next()
instead of the little loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, true! That's much nicer. I've also put the filter
after the chain
so that we don't have to treat leaf candidates from unsimplified bindingless or-patterns specially. There's tradeoffs, but I think it makes the reasoning simpler overall and the asserts stronger.
No push yet since the stronger asserts uncovered an existing issue that may need fixing before this PR can be merged: we don't do any error tainting for inconsistent or-pattern bindings like x | _
, so patterns like that can get to MIR building. It's not a correctness issue since we emit an error, but I'd really like to be able to assume or-patterns are well-formed here. The ill-formed or-patterns are now hitting the assert in push_sub_branch_bindings
, which means it's working! But it also means ICEs until we have proper error tainting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, we should definitely have good error tainting. I wanna note that I'd like to eventually allow mismatched bindings for use in guard patterns: Ok(x) | Err(e) if let Some(x) = e.recover()
type things; don't know if that changes anything here but thought I'd mention.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's on my to-do list! As I understand it, it will indeed need some substantial changes, which may involve replacing much of what this PR does. My intent here is to land the breaking change to the language with as small of a compiler change as possible, so that I don't have to worry about preserving the current drop order in future changes to match lowering (e.g. to implement guard patterns).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like a second pair of eyes on the first commit because I'm not expert there. Big fan of the last commit, that's a very elegant solution! Let's get some t-lang eyes on this.
Team member @traviscross has proposed to merge this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns. |
@rfcbot reviewed I've not read the PR contents, but I am affirming that the desired behavior is this from the OP:
|
Let's look into ensuring this is documented in the Reference. cc @ehuss |
@rfcbot reviewed |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
The first two commits look good to me (and the third except for the things that you've already commented on). |
To fix #142163, this PR does two things:
@
as coming before the binding on the left). In each sub-branch of a match arm, this is the order that would be obtained if the or-alternatives chosen in that sub-branch were inlined into the arm's pattern. This both affects drop order (making bindings in or-patterns not be dropped first) and fixes the issue in this test from match lowering: Lower bindings in a predictable order #121716.My approach to the second point is admittedly a bit trickier than may be necessary. To avoid passing around a counter when building
FlatPat
s, I've instead added just enough information to recover the original structure of the pattern's bindings from aMatchTreeSubBranch
's path through theCandidate
tree. Some alternatives:MatchTreeSubBranch
es.test_remaining_match_pairs_after_or
; that would require lowering bindings and guards in a different way. That makes it a bigger change too, though, so I figure it might be simplest to start here.This is a breaking change. It will need a crater run, language team sign-off, and likely updates to the Reference.
This will conflict with #143376 and probably also #143028, so they shouldn't be merged at the same time.
r? @matthewjasper or @Nadrieril