Skip to content

specify relative drop order of pattern bindings #1953

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 43 additions & 3 deletions src/destructors.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,48 @@ let declared_first = PrintOnDrop("Dropped last in outer scope");
let declared_last = PrintOnDrop("Dropped first in outer scope");
```

r[destructors.scope.bindings.match-pattern-order]
If multiple patterns are used in the same arm for a `match` expression, then an
unspecified pattern will be used to determine the drop order.
r[destructors.scope.bindings.pattern-drop-order]
Copy link
Author

Choose a reason for hiding this comment

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

This also only specifies the dynamic semantics of drops, not their static semantics; those seem to be handled by the Nomicon rather than the Reference. See e.g. rust-lang/rust#142057 for an instance where the static semantics would need additional specification. Or for (probably) a non-bug, consider an x @ Struct(y) pattern: x is declared before y, but y is bound before x and (incidentally, as an implementation detail) is considered potentially live until after x is dropped. This is to allow copying into y before moving into x. This can't affect the order in which destructors are run, since if they both had significant drops, neither would be Copy, and the match scrutinee can't be moved into both y and x. As far as I can tell, the only effect x being dropped first has is slightly more permissive drop-checking in edge cases where e.g. x is mutated to contain a reference to y.

Since the Reference only specifies when destructors are run, I've chosen to keep things simple and not handle any of that.

If a pattern binds multiple variables, they are dropped in reverse order of delcaration.
Copy link
Author

Choose a reason for hiding this comment

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

The order of "declaration" is left mostly unspecified, other than by destructors.scope.bindings.or-pattern-declaration-order below. I like specifying the order as the reverse of another order to better match the other rules around drop order, and "reverse declaration order" is used for this purpose in the FLS1. Other possible terms could be "reverse of source order", "reverse order of appearance", or "reverse order of first appearance" to combine the two rules. I don't think any of them read quite as well though.

Footnotes

  1. https://rust-lang.github.io/fls/ownership-and-deconstruction.html#drop-order


```rust
# struct PrintOnDrop(&'static str);
# impl Drop for PrintOnDrop {
# fn drop(&mut self) {
# println!("drop({})", self.0);
# }
# }
let (declared_first, declared_last) = (
PrintOnDrop("Dropped last"),
PrintOnDrop("Dropped first"),
);
```

r[destructors.scope.bindings.or-pattern-declaration-order]
For the purpose of drop order, [or-patterns] declare their bindings in the order given by their first sub-pattern.

```rust
# struct PrintOnDrop(&'static str);
# impl Drop for PrintOnDrop {
# fn drop(&mut self) {
# println!("drop({})", self.0);
# }
# }
// Drops `declared_last`, then `declared_first`.
fn fixed_variable_drop_order<T>(
(Ok([declared_first, declared_last])
| Err([declared_last, declared_first])): Result<[T; 2], [T; 2]>
) {}

fixed_variable_drop_order(Ok([
PrintOnDrop("Dropped last"),
PrintOnDrop("Dropped first"),
]));

fixed_variable_drop_order(Err([
PrintOnDrop("Dropped first"),
PrintOnDrop("Dropped last"),
]));
Comment on lines +220 to +228
Copy link
Author

Choose a reason for hiding this comment

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

I feel like these examples would benefit from comments, but I haven't been able to come up with something concise enough yet.

```

r[destructors.scope.temporary]
### Temporary scopes
Expand Down Expand Up @@ -473,6 +512,7 @@ There is one additional case to be aware of: when a panic reaches a [non-unwindi
[Trait objects]: types/trait-object.md
[tuple]: types/tuple.md

[or-patterns]: patterns.md#or-patterns
[slice pattern]: patterns.md#slice-patterns
[struct pattern]: patterns.md#struct-patterns
[tuple pattern]: patterns.md#tuple-patterns
Expand Down