Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a974e4b

Browse files
authoredApr 18, 2025··
Unrolled build for rust-lang#138528
Rollup merge of rust-lang#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: rust-lang#87121 r? ``@Nadrieril``
2 parents 6a0bd27 + 3b91b7a commit a974e4b

33 files changed

+944
-170
lines changed
 

‎compiler/rustc_hir_analysis/src/autoderef.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use rustc_infer::infer::InferCtxt;
22
use rustc_infer::traits::PredicateObligations;
33
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
44
use rustc_session::Limit;
5-
use rustc_span::Span;
65
use rustc_span::def_id::{LOCAL_CRATE, LocalDefId};
6+
use rustc_span::{ErrorGuaranteed, Span};
77
use rustc_trait_selection::traits::ObligationCtxt;
88
use tracing::{debug, instrument};
99

@@ -259,7 +259,11 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
259259
}
260260
}
261261

262-
pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
262+
pub fn report_autoderef_recursion_limit_error<'tcx>(
263+
tcx: TyCtxt<'tcx>,
264+
span: Span,
265+
ty: Ty<'tcx>,
266+
) -> ErrorGuaranteed {
263267
// We've reached the recursion limit, error gracefully.
264268
let suggested_limit = match tcx.recursion_limit() {
265269
Limit(0) => Limit(2),
@@ -270,5 +274,5 @@ pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Spa
270274
ty,
271275
suggested_limit,
272276
crate_name: tcx.crate_name(LOCAL_CRATE),
273-
});
277+
})
274278
}

‎compiler/rustc_hir_typeck/src/expr_use_visitor.rs

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
10001000
// determines whether to borrow *at the level of the deref pattern* rather than
10011001
// borrowing the bound place (since that inner place is inside the temporary that
10021002
// stores the result of calling `deref()`/`deref_mut()` so can't be captured).
1003+
// HACK: this could be a fake pattern corresponding to a deref inserted by match
1004+
// ergonomics, in which case `pat.hir_id` will be the id of the subpattern.
10031005
let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpattern);
10041006
let mutability =
10051007
if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
@@ -1227,9 +1229,9 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
12271229
// actually this is somewhat "disjoint" from the code below
12281230
// that aims to account for `ref x`.
12291231
if let Some(vec) = self.cx.typeck_results().pat_adjustments().get(pat.hir_id) {
1230-
if let Some(first_ty) = vec.first() {
1231-
debug!("pat_ty(pat={:?}) found adjusted ty `{:?}`", pat, first_ty);
1232-
return Ok(*first_ty);
1232+
if let Some(first_adjust) = vec.first() {
1233+
debug!("pat_ty(pat={:?}) found adjustment `{:?}`", pat, first_adjust);
1234+
return Ok(first_adjust.source);
12331235
}
12341236
} else if let PatKind::Ref(subpat, _) = pat.kind
12351237
&& self.cx.typeck_results().skipped_ref_pats().contains(pat.hir_id)
@@ -1680,12 +1682,31 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
16801682
// Then we see that to get the same result, we must start with
16811683
// `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)`
16821684
// and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`.
1683-
for _ in
1684-
0..self.cx.typeck_results().pat_adjustments().get(pat.hir_id).map_or(0, |v| v.len())
1685-
{
1685+
let typeck_results = self.cx.typeck_results();
1686+
let adjustments: &[adjustment::PatAdjustment<'tcx>] =
1687+
typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v);
1688+
let mut adjusts = adjustments.iter().peekable();
1689+
while let Some(adjust) = adjusts.next() {
16861690
debug!("applying adjustment to place_with_id={:?}", place_with_id);
1687-
place_with_id = self.cat_deref(pat.hir_id, place_with_id)?;
1691+
place_with_id = match adjust.kind {
1692+
adjustment::PatAdjust::BuiltinDeref => self.cat_deref(pat.hir_id, place_with_id)?,
1693+
adjustment::PatAdjust::OverloadedDeref => {
1694+
// This adjustment corresponds to an overloaded deref; it borrows the scrutinee to
1695+
// call `Deref::deref` or `DerefMut::deref_mut`. Invoke the callback before setting
1696+
// `place_with_id` to the temporary storing the result of the deref.
1697+
// HACK(dianne): giving the callback a fake deref pattern makes sure it behaves the
1698+
// same as it would if this were an explicit deref pattern.
1699+
op(&place_with_id, &hir::Pat { kind: PatKind::Deref(pat), ..*pat })?;
1700+
let target_ty = match adjusts.peek() {
1701+
Some(&&next_adjust) => next_adjust.source,
1702+
// At the end of the deref chain, we get `pat`'s scrutinee.
1703+
None => self.pat_ty_unadjusted(pat)?,
1704+
};
1705+
self.pat_deref_temp(pat.hir_id, pat, target_ty)?
1706+
}
1707+
};
16881708
}
1709+
drop(typeck_results); // explicitly release borrow of typeck results, just in case.
16891710
let place_with_id = place_with_id; // lose mutability
16901711
debug!("applied adjustment derefs to get place_with_id={:?}", place_with_id);
16911712

@@ -1788,14 +1809,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
17881809
self.cat_pattern(subplace, subpat, op)?;
17891810
}
17901811
PatKind::Deref(subpat) => {
1791-
let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpat);
1792-
let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
1793-
let re_erased = self.cx.tcx().lifetimes.re_erased;
17941812
let ty = self.pat_ty_adjusted(subpat)?;
1795-
let ty = Ty::new_ref(self.cx.tcx(), re_erased, ty, mutability);
1796-
// A deref pattern generates a temporary.
1797-
let base = self.cat_rvalue(pat.hir_id, ty);
1798-
let place = self.cat_deref(pat.hir_id, base)?;
1813+
let place = self.pat_deref_temp(pat.hir_id, subpat, ty)?;
17991814
self.cat_pattern(place, subpat, op)?;
18001815
}
18011816

@@ -1848,6 +1863,23 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
18481863
Ok(())
18491864
}
18501865

1866+
/// Represents the place of the temp that stores the scrutinee of a deref pattern's interior.
1867+
fn pat_deref_temp(
1868+
&self,
1869+
hir_id: HirId,
1870+
inner: &hir::Pat<'_>,
1871+
target_ty: Ty<'tcx>,
1872+
) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
1873+
let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(inner);
1874+
let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
1875+
let re_erased = self.cx.tcx().lifetimes.re_erased;
1876+
let ty = Ty::new_ref(self.cx.tcx(), re_erased, target_ty, mutability);
1877+
// A deref pattern stores the result of `Deref::deref` or `DerefMut::deref_mut` ...
1878+
let base = self.cat_rvalue(hir_id, ty);
1879+
// ... and the inner pattern matches on the place behind that reference.
1880+
self.cat_deref(hir_id, base)
1881+
}
1882+
18511883
fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool {
18521884
if let ty::Adt(def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() {
18531885
// Note that if a non-exhaustive SingleVariant is defined in another crate, we need

‎compiler/rustc_hir_typeck/src/pat.rs

Lines changed: 314 additions & 119 deletions
Large diffs are not rendered by default.

‎compiler/rustc_middle/src/ty/adjustment.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,3 +214,25 @@ pub enum CustomCoerceUnsized {
214214
/// Records the index of the field being coerced.
215215
Struct(FieldIdx),
216216
}
217+
218+
/// Represents an implicit coercion applied to the scrutinee of a match before testing a pattern
219+
/// against it. Currently, this is used only for implicit dereferences.
220+
#[derive(Clone, Copy, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
221+
pub struct PatAdjustment<'tcx> {
222+
pub kind: PatAdjust,
223+
/// The type of the scrutinee before the adjustment is applied, or the "adjusted type" of the
224+
/// pattern.
225+
pub source: Ty<'tcx>,
226+
}
227+
228+
/// Represents implicit coercions of patterns' types, rather than values' types.
229+
#[derive(Clone, Copy, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
230+
#[derive(TypeFoldable, TypeVisitable)]
231+
pub enum PatAdjust {
232+
/// An implicit dereference before matching, such as when matching the pattern `0` against a
233+
/// scrutinee of type `&u8` or `&mut u8`.
234+
BuiltinDeref,
235+
/// An implicit call to `Deref(Mut)::deref(_mut)` before matching, such as when matching the
236+
/// pattern `[..]` against a scrutinee of type `Vec<T>`.
237+
OverloadedDeref,
238+
}

‎compiler/rustc_middle/src/ty/structural_impls.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ impl<'tcx> fmt::Debug for ty::adjustment::Adjustment<'tcx> {
6060
}
6161
}
6262

63+
impl<'tcx> fmt::Debug for ty::adjustment::PatAdjustment<'tcx> {
64+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65+
write!(f, "{} -> {:?}", self.source, self.kind)
66+
}
67+
}
68+
6369
impl fmt::Debug for ty::BoundRegionKind {
6470
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6571
match *self {

‎compiler/rustc_middle/src/ty/typeck_results.rs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,20 +77,29 @@ pub struct TypeckResults<'tcx> {
7777
/// to a form valid in all Editions, either as a lint diagnostic or hard error.
7878
rust_2024_migration_desugared_pats: ItemLocalMap<Rust2024IncompatiblePatInfo>,
7979

80-
/// Stores the types which were implicitly dereferenced in pattern binding modes
81-
/// for later usage in THIR lowering. For example,
80+
/// Stores the types which were implicitly dereferenced in pattern binding modes or deref
81+
/// patterns for later usage in THIR lowering. For example,
8282
///
8383
/// ```
8484
/// match &&Some(5i32) {
8585
/// Some(n) => {},
8686
/// _ => {},
8787
/// }
8888
/// ```
89-
/// leads to a `vec![&&Option<i32>, &Option<i32>]`. Empty vectors are not stored.
89+
/// leads to a `vec![&&Option<i32>, &Option<i32>]` and
90+
///
91+
/// ```
92+
/// #![feature(deref_patterns)]
93+
/// match &Box::new(Some(5i32)) {
94+
/// Some(n) => {},
95+
/// _ => {},
96+
/// }
97+
/// ```
98+
/// leads to a `vec![&Box<Option<i32>>, Box<Option<i32>>]`. Empty vectors are not stored.
9099
///
91100
/// See:
92101
/// <https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions>
93-
pat_adjustments: ItemLocalMap<Vec<Ty<'tcx>>>,
102+
pat_adjustments: ItemLocalMap<Vec<ty::adjustment::PatAdjustment<'tcx>>>,
94103

95104
/// Set of reference patterns that match against a match-ergonomics inserted reference
96105
/// (as opposed to against a reference in the scrutinee type).
@@ -403,11 +412,15 @@ impl<'tcx> TypeckResults<'tcx> {
403412
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_binding_modes }
404413
}
405414

406-
pub fn pat_adjustments(&self) -> LocalTableInContext<'_, Vec<Ty<'tcx>>> {
415+
pub fn pat_adjustments(
416+
&self,
417+
) -> LocalTableInContext<'_, Vec<ty::adjustment::PatAdjustment<'tcx>>> {
407418
LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_adjustments }
408419
}
409420

410-
pub fn pat_adjustments_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>>> {
421+
pub fn pat_adjustments_mut(
422+
&mut self,
423+
) -> LocalTableInContextMut<'_, Vec<ty::adjustment::PatAdjustment<'tcx>>> {
411424
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
412425
}
413426

‎compiler/rustc_mir_build/src/thir/pattern/migration.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ use rustc_data_structures::fx::FxIndexMap;
44
use rustc_errors::MultiSpan;
55
use rustc_hir::{BindingMode, ByRef, HirId, Mutability};
66
use rustc_lint as lint;
7-
use rustc_middle::span_bug;
8-
use rustc_middle::ty::{self, Rust2024IncompatiblePatInfo, Ty, TyCtxt};
7+
use rustc_middle::ty::{self, Rust2024IncompatiblePatInfo, TyCtxt};
98
use rustc_span::{Ident, Span};
109

1110
use crate::errors::{Rust2024IncompatiblePat, Rust2024IncompatiblePatSugg};
@@ -87,19 +86,18 @@ impl<'a> PatMigration<'a> {
8786
}
8887

8988
/// Tracks when we're lowering a pattern that implicitly dereferences the scrutinee.
90-
/// This should only be called when the pattern type adjustments list `adjustments` is
91-
/// non-empty. Returns the prior default binding mode; this should be followed by a call to
92-
/// [`PatMigration::leave_ref`] to restore it when we leave the pattern.
89+
/// This should only be called when the pattern type adjustments list `adjustments` contains an
90+
/// implicit deref of a reference type. Returns the prior default binding mode; this should be
91+
/// followed by a call to [`PatMigration::leave_ref`] to restore it when we leave the pattern.
9392
pub(super) fn visit_implicit_derefs<'tcx>(
9493
&mut self,
9594
pat_span: Span,
96-
adjustments: &[Ty<'tcx>],
95+
adjustments: &[ty::adjustment::PatAdjustment<'tcx>],
9796
) -> Option<(Span, Mutability)> {
98-
let implicit_deref_mutbls = adjustments.iter().map(|ref_ty| {
99-
let &ty::Ref(_, _, mutbl) = ref_ty.kind() else {
100-
span_bug!(pat_span, "pattern implicitly dereferences a non-ref type");
101-
};
102-
mutbl
97+
// Implicitly dereferencing references changes the default binding mode, but implicit derefs
98+
// of smart pointers do not. Thus, we only consider implicit derefs of reference types.
99+
let implicit_deref_mutbls = adjustments.iter().filter_map(|adjust| {
100+
if let &ty::Ref(_, _, mutbl) = adjust.source.kind() { Some(mutbl) } else { None }
103101
});
104102

105103
if !self.info.suggest_eliding_modes {

‎compiler/rustc_mir_build/src/thir/pattern/mod.rs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use rustc_middle::mir::interpret::LitToConstInput;
1818
use rustc_middle::thir::{
1919
Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
2020
};
21+
use rustc_middle::ty::adjustment::{PatAdjust, PatAdjustment};
2122
use rustc_middle::ty::layout::IntegerExt;
2223
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypingMode};
2324
use rustc_middle::{bug, span_bug};
@@ -63,13 +64,15 @@ pub(super) fn pat_from_hir<'a, 'tcx>(
6364

6465
impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
6566
fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
66-
let adjustments: &[Ty<'tcx>] =
67+
let adjustments: &[PatAdjustment<'tcx>] =
6768
self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v);
6869

6970
// Track the default binding mode for the Rust 2024 migration suggestion.
71+
// Implicitly dereferencing references changes the default binding mode, but implicit deref
72+
// patterns do not. Only track binding mode changes if a ref type is in the adjustments.
7073
let mut opt_old_mode_span = None;
7174
if let Some(s) = &mut self.rust_2024_migration
72-
&& !adjustments.is_empty()
75+
&& adjustments.iter().any(|adjust| adjust.kind == PatAdjust::BuiltinDeref)
7376
{
7477
opt_old_mode_span = s.visit_implicit_derefs(pat.span, adjustments);
7578
}
@@ -102,17 +105,23 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
102105
_ => self.lower_pattern_unadjusted(pat),
103106
};
104107

105-
let adjusted_pat = adjustments.iter().rev().fold(unadjusted_pat, |thir_pat, ref_ty| {
106-
debug!("{:?}: wrapping pattern with type {:?}", thir_pat, ref_ty);
107-
Box::new(Pat {
108-
span: thir_pat.span,
109-
ty: *ref_ty,
110-
kind: PatKind::Deref { subpattern: thir_pat },
111-
})
108+
let adjusted_pat = adjustments.iter().rev().fold(unadjusted_pat, |thir_pat, adjust| {
109+
debug!("{:?}: wrapping pattern with adjustment {:?}", thir_pat, adjust);
110+
let span = thir_pat.span;
111+
let kind = match adjust.kind {
112+
PatAdjust::BuiltinDeref => PatKind::Deref { subpattern: thir_pat },
113+
PatAdjust::OverloadedDeref => {
114+
let mutable = self.typeck_results.pat_has_ref_mut_binding(pat);
115+
let mutability =
116+
if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
117+
PatKind::DerefPattern { subpattern: thir_pat, mutability }
118+
}
119+
};
120+
Box::new(Pat { span, ty: adjust.source, kind })
112121
});
113122

114123
if let Some(s) = &mut self.rust_2024_migration
115-
&& !adjustments.is_empty()
124+
&& adjustments.iter().any(|adjust| adjust.kind == PatAdjust::BuiltinDeref)
116125
{
117126
s.leave_ref(opt_old_mode_span);
118127
}

‎src/doc/unstable-book/src/language-features/box-patterns.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ The tracking issue for this feature is: [#29641]
66

77
------------------------
88

9+
> **Note**: This feature will be superseded by [`deref_patterns`] in the future.
10+
911
Box patterns let you match on `Box<T>`s:
1012

1113

@@ -28,3 +30,5 @@ fn main() {
2830
}
2931
}
3032
```
33+
34+
[`deref_patterns`]: ./deref-patterns.md
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# `deref_patterns`
2+
3+
The tracking issue for this feature is: [#87121]
4+
5+
[#87121]: https://github.com/rust-lang/rust/issues/87121
6+
7+
------------------------
8+
9+
> **Note**: This feature is incomplete. In the future, it is meant to supersede
10+
> [`box_patterns`](./box-patterns.md) and [`string_deref_patterns`](./string-deref-patterns.md).
11+
12+
This feature permits pattern matching on [smart pointers in the standard library] through their
13+
`Deref` target types, either implicitly or with explicit `deref!(_)` patterns (the syntax of which
14+
is currently a placeholder).
15+
16+
```rust
17+
#![feature(deref_patterns)]
18+
#![allow(incomplete_features)]
19+
20+
let mut v = vec![Box::new(Some(0))];
21+
22+
// Implicit dereferences are inserted when a pattern can match against the
23+
// result of repeatedly dereferencing but can't match against a smart
24+
// pointer itself. This works alongside match ergonomics for references.
25+
if let [Some(x)] = &mut v {
26+
*x += 1;
27+
}
28+
29+
// Explicit `deref!(_)` patterns may instead be used when finer control is
30+
// needed, e.g. to dereference only a single smart pointer, or to bind the
31+
// the result of dereferencing to a variable.
32+
if let deref!([deref!(opt_x @ Some(1))]) = &mut v {
33+
opt_x.as_mut().map(|x| *x += 1);
34+
}
35+
36+
assert_eq!(v, [Box::new(Some(2))]);
37+
```
38+
39+
Without this feature, it may be necessary to introduce temporaries to represent dereferenced places
40+
when matching on nested structures:
41+
42+
```rust
43+
let mut v = vec![Box::new(Some(0))];
44+
if let [b] = &mut *v {
45+
if let Some(x) = &mut **b {
46+
*x += 1;
47+
}
48+
}
49+
if let [b] = &mut *v {
50+
if let opt_x @ Some(1) = &mut **b {
51+
opt_x.as_mut().map(|x| *x += 1);
52+
}
53+
}
54+
assert_eq!(v, [Box::new(Some(2))]);
55+
```
56+
57+
[smart pointers in the standard library]: https://doc.rust-lang.org/std/ops/trait.DerefPure.html#implementors

‎src/doc/unstable-book/src/language-features/string-deref-patterns.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ The tracking issue for this feature is: [#87121]
66

77
------------------------
88

9+
> **Note**: This feature will be superseded by [`deref_patterns`] in the future.
10+
911
This feature permits pattern matching `String` to `&str` through [its `Deref` implementation].
1012

1113
```rust
@@ -42,4 +44,5 @@ pub fn is_it_the_answer(value: Value) -> bool {
4244
}
4345
```
4446

47+
[`deref_patterns`]: ./deref-patterns.md
4548
[its `Deref` implementation]: https://doc.rust-lang.org/std/string/struct.String.html#impl-Deref-for-String

‎src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ fn find_first_mismatch(cx: &LateContext<'_>, pat: &Pat<'_>) -> Option<(Span, Mut
179179
};
180180
if let Some(adjustments) = cx.typeck_results().pat_adjustments().get(adjust_pat.hir_id) {
181181
if let [first, ..] = **adjustments {
182-
if let ty::Ref(.., mutability) = *first.kind() {
182+
if let ty::Ref(.., mutability) = *first.source.kind() {
183183
let level = if p.hir_id == pat.hir_id {
184184
Level::Top
185185
} else {

‎tests/ui/pattern/deref-patterns/bindings.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
//@ revisions: explicit implicit
12
//@ run-pass
23
#![feature(deref_patterns)]
34
#![allow(incomplete_features)]
45

6+
#[cfg(explicit)]
57
fn simple_vec(vec: Vec<u32>) -> u32 {
68
match vec {
79
deref!([]) => 100,
@@ -13,6 +15,19 @@ fn simple_vec(vec: Vec<u32>) -> u32 {
1315
}
1416
}
1517

18+
#[cfg(implicit)]
19+
fn simple_vec(vec: Vec<u32>) -> u32 {
20+
match vec {
21+
[] => 100,
22+
[x] if x == 4 => x + 4,
23+
[x] => x,
24+
[1, x] => x + 200,
25+
deref!(ref slice) => slice.iter().sum(),
26+
_ => 2000,
27+
}
28+
}
29+
30+
#[cfg(explicit)]
1631
fn nested_vec(vecvec: Vec<Vec<u32>>) -> u32 {
1732
match vecvec {
1833
deref!([]) => 0,
@@ -24,6 +39,19 @@ fn nested_vec(vecvec: Vec<Vec<u32>>) -> u32 {
2439
}
2540
}
2641

42+
#[cfg(implicit)]
43+
fn nested_vec(vecvec: Vec<Vec<u32>>) -> u32 {
44+
match vecvec {
45+
[] => 0,
46+
[[x]] => x,
47+
[[0, x] | [1, x]] => x,
48+
[ref x] => x.iter().sum(),
49+
[[], [1, x, y]] => y - x,
50+
_ => 2000,
51+
}
52+
}
53+
54+
#[cfg(explicit)]
2755
fn ref_mut(val: u32) -> u32 {
2856
let mut b = Box::new(0u32);
2957
match &mut b {
@@ -37,6 +65,21 @@ fn ref_mut(val: u32) -> u32 {
3765
*x
3866
}
3967

68+
#[cfg(implicit)]
69+
fn ref_mut(val: u32) -> u32 {
70+
let mut b = Box::new((0u32,));
71+
match &mut b {
72+
(_x,) if false => unreachable!(),
73+
(x,) => {
74+
*x = val;
75+
}
76+
_ => unreachable!(),
77+
}
78+
let (x,) = &b else { unreachable!() };
79+
*x
80+
}
81+
82+
#[cfg(explicit)]
4083
#[rustfmt::skip]
4184
fn or_and_guard(tuple: (u32, u32)) -> u32 {
4285
let mut sum = 0;
@@ -48,6 +91,18 @@ fn or_and_guard(tuple: (u32, u32)) -> u32 {
4891
sum
4992
}
5093

94+
#[cfg(implicit)]
95+
#[rustfmt::skip]
96+
fn or_and_guard(tuple: (u32, u32)) -> u32 {
97+
let mut sum = 0;
98+
let b = Box::new(tuple);
99+
match b {
100+
(x, _) | (_, x) if { sum += x; false } => {},
101+
_ => {},
102+
}
103+
sum
104+
}
105+
51106
fn main() {
52107
assert_eq!(simple_vec(vec![1]), 1);
53108
assert_eq!(simple_vec(vec![1, 2]), 202);

‎tests/ui/pattern/deref-patterns/branch.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
//@ revisions: explicit implicit
12
//@ run-pass
23
// Test the execution of deref patterns.
34
#![feature(deref_patterns)]
45
#![allow(incomplete_features)]
56

7+
#[cfg(explicit)]
68
fn branch(vec: Vec<u32>) -> u32 {
79
match vec {
810
deref!([]) => 0,
@@ -12,6 +14,17 @@ fn branch(vec: Vec<u32>) -> u32 {
1214
}
1315
}
1416

17+
#[cfg(implicit)]
18+
fn branch(vec: Vec<u32>) -> u32 {
19+
match vec {
20+
[] => 0,
21+
[1, _, 3] => 1,
22+
[2, ..] => 2,
23+
_ => 1000,
24+
}
25+
}
26+
27+
#[cfg(explicit)]
1528
fn nested(vec: Vec<Vec<u32>>) -> u32 {
1629
match vec {
1730
deref!([deref!([]), ..]) => 1,
@@ -20,6 +33,15 @@ fn nested(vec: Vec<Vec<u32>>) -> u32 {
2033
}
2134
}
2235

36+
#[cfg(implicit)]
37+
fn nested(vec: Vec<Vec<u32>>) -> u32 {
38+
match vec {
39+
[[], ..] => 1,
40+
[[0, ..], [1, ..]] => 2,
41+
_ => 1000,
42+
}
43+
}
44+
2345
fn main() {
2446
assert!(matches!(Vec::<u32>::new(), deref!([])));
2547
assert!(matches!(vec![1], deref!([1])));

‎tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,22 @@ fn cant_move_out_rc(rc: Rc<Struct>) -> Struct {
2121
}
2222
}
2323

24+
struct Container(Struct);
25+
26+
fn cant_move_out_box_implicit(b: Box<Container>) -> Struct {
27+
match b {
28+
//~^ ERROR: cannot move out of a shared reference
29+
Container(x) => x,
30+
_ => unreachable!(),
31+
}
32+
}
33+
34+
fn cant_move_out_rc_implicit(rc: Rc<Container>) -> Struct {
35+
match rc {
36+
//~^ ERROR: cannot move out of a shared reference
37+
Container(x) => x,
38+
_ => unreachable!(),
39+
}
40+
}
41+
2442
fn main() {}

‎tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.stderr

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,40 @@ help: consider borrowing the pattern binding
3232
LL | deref!(ref x) => x,
3333
| +++
3434

35-
error: aborting due to 2 previous errors
35+
error[E0507]: cannot move out of a shared reference
36+
--> $DIR/cant_move_out_of_pattern.rs:27:11
37+
|
38+
LL | match b {
39+
| ^
40+
LL |
41+
LL | Container(x) => x,
42+
| -
43+
| |
44+
| data moved here
45+
| move occurs because `x` has type `Struct`, which does not implement the `Copy` trait
46+
|
47+
help: consider borrowing the pattern binding
48+
|
49+
LL | Container(ref x) => x,
50+
| +++
51+
52+
error[E0507]: cannot move out of a shared reference
53+
--> $DIR/cant_move_out_of_pattern.rs:35:11
54+
|
55+
LL | match rc {
56+
| ^^
57+
LL |
58+
LL | Container(x) => x,
59+
| -
60+
| |
61+
| data moved here
62+
| move occurs because `x` has type `Struct`, which does not implement the `Copy` trait
63+
|
64+
help: consider borrowing the pattern binding
65+
|
66+
LL | Container(ref x) => x,
67+
| +++
68+
69+
error: aborting due to 4 previous errors
3670

3771
For more information about this error, try `rustc --explain E0507`.

‎tests/ui/pattern/deref-patterns/closure_capture.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,38 @@ fn main() {
1111
assert_eq!(b.len(), 3);
1212
f();
1313

14+
let v = vec![1, 2, 3];
15+
let f = || {
16+
// this should count as a borrow of `v` as a whole
17+
let [.., x] = v else { unreachable!() };
18+
assert_eq!(x, 3);
19+
};
20+
assert_eq!(v, [1, 2, 3]);
21+
f();
22+
1423
let mut b = Box::new("aaa".to_string());
1524
let mut f = || {
1625
let deref!(ref mut s) = b else { unreachable!() };
1726
s.push_str("aa");
1827
};
1928
f();
2029
assert_eq!(b.len(), 5);
30+
31+
let mut v = vec![1, 2, 3];
32+
let mut f = || {
33+
// this should count as a mutable borrow of `v` as a whole
34+
let [.., ref mut x] = v else { unreachable!() };
35+
*x = 4;
36+
};
37+
f();
38+
assert_eq!(v, [1, 2, 4]);
39+
40+
let mut v = vec![1, 2, 3];
41+
let mut f = || {
42+
// here, `[.., x]` is adjusted by both an overloaded deref and a builtin deref
43+
let [.., x] = &mut v else { unreachable!() };
44+
*x = 4;
45+
};
46+
f();
47+
assert_eq!(v, [1, 2, 4]);
2148
}

‎tests/ui/pattern/deref-patterns/fake_borrows.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,11 @@ fn main() {
1111
deref!(false) => {}
1212
_ => {},
1313
}
14+
match b {
15+
true => {}
16+
_ if { *b = true; false } => {}
17+
//~^ ERROR cannot assign `*b` in match guard
18+
false => {}
19+
_ => {},
20+
}
1421
}

‎tests/ui/pattern/deref-patterns/fake_borrows.stderr

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ LL | deref!(true) => {}
77
LL | _ if { *b = true; false } => {}
88
| ^^^^^^^^^ cannot assign
99

10-
error: aborting due to 1 previous error
10+
error[E0510]: cannot assign `*b` in match guard
11+
--> $DIR/fake_borrows.rs:16:16
12+
|
13+
LL | match b {
14+
| - value is immutable in match guard
15+
LL | true => {}
16+
LL | _ if { *b = true; false } => {}
17+
| ^^^^^^^^^ cannot assign
18+
19+
error: aborting due to 2 previous errors
1120

1221
For more information about this error, try `rustc --explain E0510`.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//! Test that we get an error about structural equality rather than a type error when attempting to
2+
//! use const patterns of library pointer types. Currently there aren't any smart pointers that can
3+
//! be used in constant patterns, but we still need to make sure we don't implicitly dereference the
4+
//! scrutinee and end up with a type error; this would prevent us from reporting that only constants
5+
//! supporting structural equality can be used as patterns.
6+
#![feature(deref_patterns)]
7+
#![allow(incomplete_features)]
8+
9+
const EMPTY: Vec<()> = Vec::new();
10+
11+
fn main() {
12+
// FIXME(inline_const_pat): if `inline_const_pat` is reinstated, there should be a case here for
13+
// inline const block patterns as well; they're checked differently than named constants.
14+
match vec![()] {
15+
EMPTY => {}
16+
//~^ ERROR: constant of non-structural type `Vec<()>` in a pattern
17+
_ => {}
18+
}
19+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: constant of non-structural type `Vec<()>` in a pattern
2+
--> $DIR/implicit-const-deref.rs:15:9
3+
|
4+
LL | const EMPTY: Vec<()> = Vec::new();
5+
| -------------------- constant defined here
6+
...
7+
LL | EMPTY => {}
8+
| ^^^^^ constant of non-structural type
9+
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
10+
|
11+
= note: `Vec<()>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
12+
|
13+
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
14+
15+
error: aborting due to 1 previous error
16+
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//@ run-pass
2+
//! Test that implicit deref patterns interact as expected with `Cow` constructor patterns.
3+
#![feature(deref_patterns)]
4+
#![allow(incomplete_features)]
5+
6+
use std::borrow::Cow;
7+
8+
fn main() {
9+
let cow: Cow<'static, [u8]> = Cow::Borrowed(&[1, 2, 3]);
10+
11+
match cow {
12+
[..] => {}
13+
_ => unreachable!(),
14+
}
15+
16+
match cow {
17+
Cow::Borrowed(_) => {}
18+
Cow::Owned(_) => unreachable!(),
19+
}
20+
21+
match Box::new(&cow) {
22+
Cow::Borrowed { 0: _ } => {}
23+
Cow::Owned { 0: _ } => unreachable!(),
24+
_ => unreachable!(),
25+
}
26+
27+
let cow_of_cow: Cow<'_, Cow<'static, [u8]>> = Cow::Owned(cow);
28+
29+
match cow_of_cow {
30+
[..] => {}
31+
_ => unreachable!(),
32+
}
33+
34+
// This matches on the outer `Cow` (the owned one).
35+
match cow_of_cow {
36+
Cow::Borrowed(_) => unreachable!(),
37+
Cow::Owned(_) => {}
38+
}
39+
40+
match Box::new(&cow_of_cow) {
41+
Cow::Borrowed { 0: _ } => unreachable!(),
42+
Cow::Owned { 0: _ } => {}
43+
_ => unreachable!(),
44+
}
45+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// gate-test-deref_patterns
2+
3+
fn main() {
4+
match Box::new(0) {
5+
deref!(0) => {}
6+
//~^ ERROR: use of unstable library feature `deref_patterns`: placeholder syntax for deref patterns
7+
_ => {}
8+
}
9+
10+
match Box::new(0) {
11+
0 => {}
12+
//~^ ERROR: mismatched types
13+
_ => {}
14+
}
15+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
error[E0658]: use of unstable library feature `deref_patterns`: placeholder syntax for deref patterns
2+
--> $DIR/needs-gate.rs:5:9
3+
|
4+
LL | deref!(0) => {}
5+
| ^^^^^
6+
|
7+
= note: see issue #87121 <https://github.com/rust-lang/rust/issues/87121> for more information
8+
= help: add `#![feature(deref_patterns)]` to the crate attributes to enable
9+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10+
11+
error[E0308]: mismatched types
12+
--> $DIR/needs-gate.rs:11:9
13+
|
14+
LL | match Box::new(0) {
15+
| ----------- this expression has type `Box<{integer}>`
16+
LL | 0 => {}
17+
| ^ expected `Box<{integer}>`, found integer
18+
|
19+
= note: expected struct `Box<{integer}>`
20+
found type `{integer}`
21+
help: consider dereferencing to access the inner value using the Deref trait
22+
|
23+
LL | match *Box::new(0) {
24+
| +
25+
26+
error: aborting due to 2 previous errors
27+
28+
Some errors have detailed explanations: E0308, E0658.
29+
For more information about an error, try `rustc --explain E0308`.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//! Test that implicit deref patterns respect the recursion limit
2+
#![feature(deref_patterns)]
3+
#![allow(incomplete_features)]
4+
#![recursion_limit = "8"]
5+
6+
use std::ops::Deref;
7+
8+
struct Cyclic;
9+
impl Deref for Cyclic {
10+
type Target = Cyclic;
11+
fn deref(&self) -> &Cyclic {
12+
&Cyclic
13+
}
14+
}
15+
16+
fn main() {
17+
match &Box::new(Cyclic) {
18+
() => {}
19+
//~^ ERROR: reached the recursion limit while auto-dereferencing `Cyclic`
20+
//~| ERROR: the trait bound `Cyclic: DerefPure` is not satisfied
21+
_ => {}
22+
}
23+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error[E0055]: reached the recursion limit while auto-dereferencing `Cyclic`
2+
--> $DIR/recursion-limit.rs:18:9
3+
|
4+
LL | () => {}
5+
| ^^ deref recursion limit reached
6+
|
7+
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`recursion_limit`)
8+
9+
error[E0277]: the trait bound `Cyclic: DerefPure` is not satisfied
10+
--> $DIR/recursion-limit.rs:18:9
11+
|
12+
LL | () => {}
13+
| ^^ the trait `DerefPure` is not implemented for `Cyclic`
14+
15+
error: aborting due to 2 previous errors
16+
17+
Some errors have detailed explanations: E0055, E0277.
18+
For more information about an error, try `rustc --explain E0055`.

‎tests/ui/pattern/deref-patterns/ref-mut.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,19 @@ fn main() {
88
deref!(x) => {}
99
_ => {}
1010
}
11+
match &mut vec![1] {
12+
[x] => {}
13+
_ => {}
14+
}
1115

1216
match &mut Rc::new(1) {
1317
deref!(x) => {}
1418
//~^ ERROR the trait bound `Rc<{integer}>: DerefMut` is not satisfied
1519
_ => {}
1620
}
21+
match &mut Rc::new((1,)) {
22+
(x,) => {}
23+
//~^ ERROR the trait bound `Rc<({integer},)>: DerefMut` is not satisfied
24+
_ => {}
25+
}
1726
}

‎tests/ui/pattern/deref-patterns/ref-mut.stderr

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,19 @@ LL | #![feature(deref_patterns)]
88
= note: `#[warn(incomplete_features)]` on by default
99

1010
error[E0277]: the trait bound `Rc<{integer}>: DerefMut` is not satisfied
11-
--> $DIR/ref-mut.rs:13:9
11+
--> $DIR/ref-mut.rs:17:9
1212
|
1313
LL | deref!(x) => {}
1414
| ^^^^^^^^^ the trait `DerefMut` is not implemented for `Rc<{integer}>`
1515
|
1616
= note: this error originates in the macro `deref` (in Nightly builds, run with -Z macro-backtrace for more info)
1717

18-
error: aborting due to 1 previous error; 1 warning emitted
18+
error[E0277]: the trait bound `Rc<({integer},)>: DerefMut` is not satisfied
19+
--> $DIR/ref-mut.rs:22:9
20+
|
21+
LL | (x,) => {}
22+
| ^^^^ the trait `DerefMut` is not implemented for `Rc<({integer},)>`
23+
24+
error: aborting due to 2 previous errors; 1 warning emitted
1925

2026
For more information about this error, try `rustc --explain E0277`.

‎tests/ui/pattern/deref-patterns/typeck.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,32 @@ fn main() {
1010
let vec: Vec<u32> = Vec::new();
1111
match vec {
1212
deref!([..]) => {}
13+
[..] => {}
1314
_ => {}
1415
}
1516
match Box::new(true) {
1617
deref!(true) => {}
18+
true => {}
1719
_ => {}
1820
}
1921
match &Box::new(true) {
2022
deref!(true) => {}
23+
true => {}
2124
_ => {}
2225
}
2326
match &Rc::new(0) {
2427
deref!(1..) => {}
28+
1.. => {}
2529
_ => {}
2630
}
2731
let _: &Struct = match &Rc::new(Struct) {
2832
deref!(x) => x,
33+
Struct => &Struct,
2934
_ => unreachable!(),
3035
};
3136
let _: &[Struct] = match &Rc::new(vec![Struct]) {
3237
deref!(deref!(x)) => x,
38+
[Struct] => &[Struct],
3339
_ => unreachable!(),
3440
};
3541
}

‎tests/ui/pattern/deref-patterns/typeck_fail.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,22 @@ fn main() {
77
match "foo".to_string() {
88
deref!("foo") => {}
99
//~^ ERROR: mismatched types
10+
"foo" => {}
11+
//~^ ERROR: mismatched types
1012
_ => {}
1113
}
1214
match &"foo".to_string() {
1315
deref!("foo") => {}
1416
//~^ ERROR: mismatched types
17+
"foo" => {}
18+
//~^ ERROR: mismatched types
19+
_ => {}
20+
}
21+
22+
// Make sure we don't try implicitly dereferncing any ADT.
23+
match Some(0) {
24+
Ok(0) => {}
25+
//~^ ERROR: mismatched types
1526
_ => {}
1627
}
1728
}

‎tests/ui/pattern/deref-patterns/typeck_fail.stderr

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,45 @@ LL | deref!("foo") => {}
77
| ^^^^^ expected `str`, found `&str`
88

99
error[E0308]: mismatched types
10-
--> $DIR/typeck_fail.rs:13:16
10+
--> $DIR/typeck_fail.rs:10:9
11+
|
12+
LL | match "foo".to_string() {
13+
| ----------------- this expression has type `String`
14+
...
15+
LL | "foo" => {}
16+
| ^^^^^ expected `String`, found `&str`
17+
18+
error[E0308]: mismatched types
19+
--> $DIR/typeck_fail.rs:15:16
1120
|
1221
LL | match &"foo".to_string() {
1322
| ------------------ this expression has type `&String`
1423
LL | deref!("foo") => {}
1524
| ^^^^^ expected `str`, found `&str`
1625

17-
error: aborting due to 2 previous errors
26+
error[E0308]: mismatched types
27+
--> $DIR/typeck_fail.rs:17:9
28+
|
29+
LL | match &"foo".to_string() {
30+
| ------------------ this expression has type `&String`
31+
...
32+
LL | "foo" => {}
33+
| ^^^^^ expected `&String`, found `&str`
34+
|
35+
= note: expected reference `&String`
36+
found reference `&'static str`
37+
38+
error[E0308]: mismatched types
39+
--> $DIR/typeck_fail.rs:24:9
40+
|
41+
LL | match Some(0) {
42+
| ------- this expression has type `Option<{integer}>`
43+
LL | Ok(0) => {}
44+
| ^^^^^ expected `Option<{integer}>`, found `Result<_, _>`
45+
|
46+
= note: expected enum `Option<{integer}>`
47+
found enum `Result<_, _>`
48+
49+
error: aborting due to 5 previous errors
1850

1951
For more information about this error, try `rustc --explain E0308`.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#![feature(deref_patterns)]
2+
#![allow(incomplete_features)]
3+
4+
struct MyPointer;
5+
6+
impl std::ops::Deref for MyPointer {
7+
type Target = ();
8+
fn deref(&self) -> &() {
9+
&()
10+
}
11+
}
12+
13+
fn main() {
14+
// Test that we get a trait error if a user attempts implicit deref pats on their own impls.
15+
// FIXME(deref_patterns): there should be a special diagnostic for missing `DerefPure`.
16+
match MyPointer {
17+
() => {}
18+
//~^ the trait bound `MyPointer: DerefPure` is not satisfied
19+
_ => {}
20+
}
21+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0277]: the trait bound `MyPointer: DerefPure` is not satisfied
2+
--> $DIR/unsatisfied-bounds.rs:17:9
3+
|
4+
LL | () => {}
5+
| ^^ the trait `DerefPure` is not implemented for `MyPointer`
6+
7+
error: aborting due to 1 previous error
8+
9+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)
This repository has been archived.