Rollup merge of #138528 - dianne:implicit-deref-patterns, r=Nadrieril

deref patterns: implement implicit deref patterns

This implements implicit deref patterns (per https://hackmd.io/4qDDMcvyQ-GDB089IPcHGg#Implicit-deref-patterns) and adds tests and an unstable book chapter.

Best reviewed commit-by-commit. Overall there's a lot of additions, but a lot of that is tests, documentation, and simple(?) refactoring.

Tracking issue: #87121

r? ``@Nadrieril``
This commit is contained in:
Matthias Krüger 2025-04-18 05:16:28 +02:00 committed by GitHub
commit c8a9095f0f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 964 additions and 190 deletions

View file

@ -6,6 +6,8 @@ The tracking issue for this feature is: [#29641]
------------------------
> **Note**: This feature will be superseded by [`deref_patterns`] in the future.
Box patterns let you match on `Box<T>`s:
@ -28,3 +30,5 @@ fn main() {
}
}
```
[`deref_patterns`]: ./deref-patterns.md

View file

@ -0,0 +1,57 @@
# `deref_patterns`
The tracking issue for this feature is: [#87121]
[#87121]: https://github.com/rust-lang/rust/issues/87121
------------------------
> **Note**: This feature is incomplete. In the future, it is meant to supersede
> [`box_patterns`](./box-patterns.md) and [`string_deref_patterns`](./string-deref-patterns.md).
This feature permits pattern matching on [smart pointers in the standard library] through their
`Deref` target types, either implicitly or with explicit `deref!(_)` patterns (the syntax of which
is currently a placeholder).
```rust
#![feature(deref_patterns)]
#![allow(incomplete_features)]
let mut v = vec![Box::new(Some(0))];
// Implicit dereferences are inserted when a pattern can match against the
// result of repeatedly dereferencing but can't match against a smart
// pointer itself. This works alongside match ergonomics for references.
if let [Some(x)] = &mut v {
*x += 1;
}
// Explicit `deref!(_)` patterns may instead be used when finer control is
// needed, e.g. to dereference only a single smart pointer, or to bind the
// the result of dereferencing to a variable.
if let deref!([deref!(opt_x @ Some(1))]) = &mut v {
opt_x.as_mut().map(|x| *x += 1);
}
assert_eq!(v, [Box::new(Some(2))]);
```
Without this feature, it may be necessary to introduce temporaries to represent dereferenced places
when matching on nested structures:
```rust
let mut v = vec![Box::new(Some(0))];
if let [b] = &mut *v {
if let Some(x) = &mut **b {
*x += 1;
}
}
if let [b] = &mut *v {
if let opt_x @ Some(1) = &mut **b {
opt_x.as_mut().map(|x| *x += 1);
}
}
assert_eq!(v, [Box::new(Some(2))]);
```
[smart pointers in the standard library]: https://doc.rust-lang.org/std/ops/trait.DerefPure.html#implementors

View file

@ -6,6 +6,8 @@ The tracking issue for this feature is: [#87121]
------------------------
> **Note**: This feature will be superseded by [`deref_patterns`] in the future.
This feature permits pattern matching `String` to `&str` through [its `Deref` implementation].
```rust
@ -42,4 +44,5 @@ pub fn is_it_the_answer(value: Value) -> bool {
}
```
[`deref_patterns`]: ./deref-patterns.md
[its `Deref` implementation]: https://doc.rust-lang.org/std/string/struct.String.html#impl-Deref-for-String