Skip to content

Commit a3f8485

Browse files
committed
Implement pattern matching for &pin mut|const T
1 parent 3d86494 commit a3f8485

File tree

53 files changed

+2555
-85
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+2555
-85
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -718,14 +718,14 @@ pub struct PatField {
718718
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
719719
#[derive(Encodable, Decodable, HashStable_Generic)]
720720
pub enum ByRef {
721-
Yes(Mutability),
721+
Yes(Pinnedness, Mutability),
722722
No,
723723
}
724724

725725
impl ByRef {
726726
#[must_use]
727727
pub fn cap_ref_mutability(mut self, mutbl: Mutability) -> Self {
728-
if let ByRef::Yes(old_mutbl) = &mut self {
728+
if let ByRef::Yes(_, old_mutbl) = &mut self {
729729
*old_mutbl = cmp::min(*old_mutbl, mutbl);
730730
}
731731
self
@@ -743,20 +743,33 @@ pub struct BindingMode(pub ByRef, pub Mutability);
743743

744744
impl BindingMode {
745745
pub const NONE: Self = Self(ByRef::No, Mutability::Not);
746-
pub const REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Not);
746+
pub const REF: Self = Self(ByRef::Yes(Pinnedness::Not, Mutability::Not), Mutability::Not);
747+
pub const REF_PIN: Self =
748+
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Not), Mutability::Not);
747749
pub const MUT: Self = Self(ByRef::No, Mutability::Mut);
748-
pub const REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Not);
749-
pub const MUT_REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Mut);
750-
pub const MUT_REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Mut);
750+
pub const REF_MUT: Self = Self(ByRef::Yes(Pinnedness::Not, Mutability::Mut), Mutability::Not);
751+
pub const REF_PIN_MUT: Self =
752+
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Mut), Mutability::Not);
753+
pub const MUT_REF: Self = Self(ByRef::Yes(Pinnedness::Not, Mutability::Not), Mutability::Mut);
754+
pub const MUT_REF_PIN: Self =
755+
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Not), Mutability::Mut);
756+
pub const MUT_REF_MUT: Self =
757+
Self(ByRef::Yes(Pinnedness::Not, Mutability::Mut), Mutability::Mut);
758+
pub const MUT_REF_PIN_MUT: Self =
759+
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Mut), Mutability::Mut);
751760

752761
pub fn prefix_str(self) -> &'static str {
753762
match self {
754763
Self::NONE => "",
755764
Self::REF => "ref ",
765+
Self::REF_PIN => "ref pin const ",
756766
Self::MUT => "mut ",
757767
Self::REF_MUT => "ref mut ",
768+
Self::REF_PIN_MUT => "ref pin mut ",
758769
Self::MUT_REF => "mut ref ",
770+
Self::MUT_REF_PIN => "mut ref pin ",
759771
Self::MUT_REF_MUT => "mut ref mut ",
772+
Self::MUT_REF_PIN_MUT => "mut ref pin mut ",
760773
}
761774
}
762775
}

compiler/rustc_ast_ir/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,10 @@ pub enum Pinnedness {
101101
Not,
102102
Pinned,
103103
}
104+
105+
impl Pinnedness {
106+
/// Return `true` if self is pinned
107+
pub fn is_pinned(self) -> bool {
108+
matches!(self, Self::Pinned)
109+
}
110+
}

compiler/rustc_ast_pretty/src/pprust/state.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1698,10 +1698,15 @@ impl<'a> State<'a> {
16981698
if mutbl.is_mut() {
16991699
self.word_nbsp("mut");
17001700
}
1701-
if let ByRef::Yes(rmutbl) = by_ref {
1701+
if let ByRef::Yes(pinnedness, rmutbl) = by_ref {
17021702
self.word_nbsp("ref");
1703+
if pinnedness.is_pinned() {
1704+
self.word_nbsp("pin");
1705+
}
17031706
if rmutbl.is_mut() {
17041707
self.word_nbsp("mut");
1708+
} else if pinnedness.is_pinned() {
1709+
self.word_nbsp("const");
17051710
}
17061711
}
17071712
self.print_ident(*ident);

compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1225,7 +1225,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
12251225
}
12261226

12271227
LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
1228-
binding_mode: BindingMode(ByRef::Yes(_), _),
1228+
binding_mode: BindingMode(ByRef::Yes(..), _),
12291229
..
12301230
})) => {
12311231
let pattern_span: Span = local_decl.source_info.span;

compiler/rustc_borrowck/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2529,6 +2529,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
25292529
_ => bug!("Deref of unexpected type: {:?}", base_ty),
25302530
}
25312531
}
2532+
// Check as the inner reference type if it is a field projection
2533+
// from the `&pin` pattern
2534+
ProjectionElem::Field(FieldIdx::ZERO, _)
2535+
if let Some(adt) =
2536+
place_base.ty(self.body(), self.infcx.tcx).ty.ty_adt_def()
2537+
&& adt.is_pin()
2538+
&& self.infcx.tcx.features().pin_ergonomics() =>
2539+
{
2540+
self.is_mutable(place_base, is_local_mutation_allowed)
2541+
}
25322542
// All other projections are owned by their base path, so mutable if
25332543
// base path is mutable
25342544
ProjectionElem::Field(..)

compiler/rustc_hir/src/hir.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_ast::{
1212
pub use rustc_ast::{
1313
AssignOp, AssignOpKind, AttrId, AttrStyle, BinOp, BinOpKind, BindingMode, BorrowKind,
1414
BoundConstness, BoundPolarity, ByRef, CaptureBy, DelimArgs, ImplPolarity, IsAuto,
15-
MetaItemInner, MetaItemLit, Movability, Mutability, UnOp,
15+
MetaItemInner, MetaItemLit, Movability, Mutability, Pinnedness, UnOp,
1616
};
1717
use rustc_attr_data_structures::AttributeKind;
1818
use rustc_data_structures::fingerprint::Fingerprint;

compiler/rustc_hir_analysis/src/check/region.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,7 @@ fn resolve_local<'tcx>(
659659
// & expression, and its lifetime would be extended to the end of the block (due
660660
// to a different rule, not the below code).
661661
match pat.kind {
662-
PatKind::Binding(hir::BindingMode(hir::ByRef::Yes(_), _), ..) => true,
662+
PatKind::Binding(hir::BindingMode(hir::ByRef::Yes(..), _), ..) => true,
663663

664664
PatKind::Struct(_, field_pats, _) => field_pats.iter().any(|fp| is_binding_pat(fp.pat)),
665665

compiler/rustc_hir_pretty/src/lib.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1905,10 +1905,15 @@ impl<'a> State<'a> {
19051905
if mutbl.is_mut() {
19061906
self.word_nbsp("mut");
19071907
}
1908-
if let ByRef::Yes(rmutbl) = by_ref {
1908+
if let ByRef::Yes(pinnedness, rmutbl) = by_ref {
19091909
self.word_nbsp("ref");
1910+
if pinnedness.is_pinned() {
1911+
self.word_nbsp("pin");
1912+
}
19101913
if rmutbl.is_mut() {
19111914
self.word_nbsp("mut");
1915+
} else if pinnedness.is_pinned() {
1916+
self.word_nbsp("const");
19121917
}
19131918
}
19141919
self.print_ident(ident);

compiler/rustc_hir_typeck/src/expr_use_visitor.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -985,7 +985,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
985985
// of the pattern, as this just looks confusing, instead use the span
986986
// of the discriminant.
987987
match bm.0 {
988-
hir::ByRef::Yes(m) => {
988+
hir::ByRef::Yes(_, m) => {
989989
let bk = ty::BorrowKind::from_mutbl(m);
990990
self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk);
991991
}
@@ -1003,7 +1003,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
10031003
// Deref patterns on boxes don't borrow, so we ignore them here.
10041004
// HACK: this could be a fake pattern corresponding to a deref inserted by match
10051005
// ergonomics, in which case `pat.hir_id` will be the id of the subpattern.
1006-
if let hir::ByRef::Yes(mutability) =
1006+
if let hir::ByRef::Yes(_, mutability) =
10071007
self.cx.typeck_results().deref_pat_borrow_mode(place.place.ty(), subpattern)
10081008
{
10091009
let bk = ty::BorrowKind::from_mutbl(mutability);
@@ -1255,15 +1255,23 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
12551255
.get(pat.hir_id)
12561256
.expect("missing binding mode");
12571257

1258-
if matches!(bm.0, hir::ByRef::Yes(_)) {
1258+
if let hir::ByRef::Yes(pinnedness, _) = bm.0 {
1259+
let base_ty = if pinnedness.is_pinned() {
1260+
base_ty.pinned_ty().ok_or_else(|| {
1261+
debug!("By-pin-ref binding of non-`Pin` type: {base_ty:?}");
1262+
self.cx.report_bug(pat.span, "by-pin-ref binding of non-`Pin` type")
1263+
})?
1264+
} else {
1265+
base_ty
1266+
};
12591267
// a bind-by-ref means that the base_ty will be the type of the ident itself,
12601268
// but what we want here is the type of the underlying value being borrowed.
12611269
// So peel off one-level, turning the &T into T.
12621270
match self.cx.structurally_resolve_type(pat.span, base_ty).builtin_deref(false)
12631271
{
12641272
Some(ty) => Ok(ty),
12651273
None => {
1266-
debug!("By-ref binding of non-derefable type");
1274+
debug!("By-ref binding of non-derefable type: {base_ty:?}");
12671275
Err(self
12681276
.cx
12691277
.report_bug(pat.span, "by-ref binding of non-derefable type"))
@@ -1696,6 +1704,18 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
16961704
};
16971705
self.pat_deref_place(pat.hir_id, place_with_id, pat, target_ty)?
16981706
}
1707+
adjustment::PatAdjust::PinDeref => {
1708+
debug!("`PinDeref` of non-pinned-reference type: {:?}", adjust.source);
1709+
let target_ty = adjust.source.pinned_ty().ok_or_else(|| {
1710+
self.cx.report_bug(
1711+
self.cx.tcx().hir_span(pat.hir_id),
1712+
"`PinDeref` of non-pinned-reference type",
1713+
)
1714+
})?;
1715+
let kind = ProjectionKind::Field(FieldIdx::ZERO, FIRST_VARIANT);
1716+
place_with_id = self.cat_projection(pat.hir_id, place_with_id, target_ty, kind);
1717+
self.cat_deref(pat.hir_id, place_with_id)?
1718+
}
16991719
};
17001720
}
17011721
drop(typeck_results); // explicitly release borrow of typeck results, just in case.
@@ -1867,7 +1887,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
18671887
// Deref patterns on boxes are lowered using a built-in deref.
18681888
hir::ByRef::No => self.cat_deref(hir_id, base_place),
18691889
// For other types, we create a temporary to match on.
1870-
hir::ByRef::Yes(mutability) => {
1890+
hir::ByRef::Yes(_, mutability) => {
18711891
let re_erased = self.cx.tcx().lifetimes.re_erased;
18721892
let ty = Ty::new_ref(self.cx.tcx(), re_erased, target_ty, mutability);
18731893
// A deref pattern stores the result of `Deref::deref` or `DerefMut::deref_mut` ...

0 commit comments

Comments
 (0)