Skip to content

inconsistent drop order for pattern bindings in the presence of or-patterns #142163

Open
@dianne

Description

@dianne

When or-patterns are present in a pattern, the drop order for its bindings depends on the particular language construct used. To see it in action, see this test (#142193), but in short:

  • let pat; treats the bindings in pat as being in the order they first appear in the pattern, and drops them in reverse order. This is the behavior I would expect.
// Drops are right-to-left: `z`, `y`, `x`.
let (x, Ok(y) | Err(y), z);
// The first or-pattern alternative determines the bindings' drop order: `y`, `x`.
let ((true, x, y) | (false, y, x));
  • let pat = expr;, if let, and let-else see bindings in or-patterns as being after other bindings, thus they're dropped first. i.e.
// Drops are right-to-left, treating `y` as rightmost: `y`, `z`, `x`.
let (x, Ok(y) | Err(y), z) = expr;
// The first or-pattern alternative determines the bindings' drop order: `y`, `x`.
let ((true, x, y) | (false, y, x)) = expr;
  • match arms see bindings in or-patterns as being after other bindings, and use the final or-pattern alternative's binding order, rather than the first. i.e.
// Drops are right-to-left, treating `y` as rightmost: `y`, `z`, `x`.
match expr { (x, Ok(y) | Err(y), z) => {} }
// The last or-pattern alternative determines the bindings' drop order: `x`, `y`.
match expr { (true, x, y) | (false, y, x) => {} }
  • Function parameters are dropped in the usual right-to-left order, but the bindings within a parameter's pattern see bindings in or-patterns as being rightmost. i.e.
// Among separate params, the drop order is right-to-left: `z`, `y`, `x`.
(|x, (Ok(y) | Err(y)), z| {})(expr1, expr2, expr3);
// Within a param's pattern, or-patterns are treated as rightmost: `y`, `z`, `x`.
(|(x, Ok(y) | Err(y), z)| {})(expr);
// The first or-pattern alternative determines the bindings' drop order: `y`, `x`.
(|((true, x, y) | (false, y, x))| {})(expr);

Implementation-wise, this is due to differences in how pattern bindings are lowered to MIR.

  • For let pat;, we traverse the pattern in a natural order and schedule drops for bindings here.
  • For anything that involves pattern-matching, we use the ordering of bindings seen by match lowering, which tests or-patterns last. match using the final or-pattern alternative's binding order is a detail of how match guards are currently implemented here.
  • Function parameters' patterns are lowered left-to-right, using the usual pattern-matching lowering for each individual parameter with a non-trivial pattern here.

If this should change, I imagine it will need a T-lang decision on what the correct behavior should be, so cc @rust-lang/lang

@rustbot label: +T-compiler +T-lang +A-MIR +A-patterns +A-destructors

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-MIRArea: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.htmlA-destructorsArea: Destructors (`Drop`, …)A-patternsRelating to patterns and pattern matchingC-bugCategory: This is a bug.I-lang-nominatedNominated for discussion during a lang team meeting.P-lang-drag-1Lang team prioritization drag level 1. https://rust-lang.zulipchat.com/#narrow/channel/410516-t-langT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions