Skip to content

Commit 296a363

Browse files
committed
Implement pattern matching for &pin mut|const T
1 parent ca9eecd commit 296a363

File tree

53 files changed

+2575
-97
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

+2575
-97
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -786,14 +786,14 @@ pub struct PatField {
786786
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
787787
#[derive(Encodable, Decodable, HashStable_Generic)]
788788
pub enum ByRef {
789-
Yes(Mutability),
789+
Yes(Pinnedness, Mutability),
790790
No,
791791
}
792792

793793
impl ByRef {
794794
#[must_use]
795795
pub fn cap_ref_mutability(mut self, mutbl: Mutability) -> Self {
796-
if let ByRef::Yes(old_mutbl) = &mut self {
796+
if let ByRef::Yes(_, old_mutbl) = &mut self {
797797
*old_mutbl = cmp::min(*old_mutbl, mutbl);
798798
}
799799
self
@@ -811,20 +811,33 @@ pub struct BindingMode(pub ByRef, pub Mutability);
811811

812812
impl BindingMode {
813813
pub const NONE: Self = Self(ByRef::No, Mutability::Not);
814-
pub const REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Not);
814+
pub const REF: Self = Self(ByRef::Yes(Pinnedness::Not, Mutability::Not), Mutability::Not);
815+
pub const REF_PIN: Self =
816+
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Not), Mutability::Not);
815817
pub const MUT: Self = Self(ByRef::No, Mutability::Mut);
816-
pub const REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Not);
817-
pub const MUT_REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Mut);
818-
pub const MUT_REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Mut);
818+
pub const REF_MUT: Self = Self(ByRef::Yes(Pinnedness::Not, Mutability::Mut), Mutability::Not);
819+
pub const REF_PIN_MUT: Self =
820+
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Mut), Mutability::Not);
821+
pub const MUT_REF: Self = Self(ByRef::Yes(Pinnedness::Not, Mutability::Not), Mutability::Mut);
822+
pub const MUT_REF_PIN: Self =
823+
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Not), Mutability::Mut);
824+
pub const MUT_REF_MUT: Self =
825+
Self(ByRef::Yes(Pinnedness::Not, Mutability::Mut), Mutability::Mut);
826+
pub const MUT_REF_PIN_MUT: Self =
827+
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Mut), Mutability::Mut);
819828

820829
pub fn prefix_str(self) -> &'static str {
821830
match self {
822831
Self::NONE => "",
823832
Self::REF => "ref ",
833+
Self::REF_PIN => "ref pin const ",
824834
Self::MUT => "mut ",
825835
Self::REF_MUT => "ref mut ",
836+
Self::REF_PIN_MUT => "ref pin mut ",
826837
Self::MUT_REF => "mut ref ",
838+
Self::MUT_REF_PIN => "mut ref pin ",
827839
Self::MUT_REF_MUT => "mut ref mut ",
840+
Self::MUT_REF_PIN_MUT => "mut ref pin mut ",
828841
}
829842
}
830843
}

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
@@ -1713,10 +1713,15 @@ impl<'a> State<'a> {
17131713
if mutbl.is_mut() {
17141714
self.word_nbsp("mut");
17151715
}
1716-
if let ByRef::Yes(rmutbl) = by_ref {
1716+
if let ByRef::Yes(pinnedness, rmutbl) = by_ref {
17171717
self.word_nbsp("ref");
1718+
if pinnedness.is_pinned() {
1719+
self.word_nbsp("pin");
1720+
}
17181721
if rmutbl.is_mut() {
17191722
self.word_nbsp("mut");
1723+
} else if pinnedness.is_pinned() {
1724+
self.word_nbsp("const");
17201725
}
17211726
}
17221727
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
@@ -1218,7 +1218,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
12181218
}
12191219

12201220
LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
1221-
binding_mode: BindingMode(ByRef::Yes(_), _),
1221+
binding_mode: BindingMode(ByRef::Yes(..), _),
12221222
..
12231223
})) => {
12241224
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
@@ -2498,6 +2498,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
24982498
_ => bug!("Deref of unexpected type: {:?}", base_ty),
24992499
}
25002500
}
2501+
// Check as the inner reference type if it is a field projection
2502+
// from the `&pin` pattern
2503+
ProjectionElem::Field(FieldIdx::ZERO, _)
2504+
if let Some(adt) =
2505+
place_base.ty(self.body(), self.infcx.tcx).ty.ty_adt_def()
2506+
&& adt.is_pin()
2507+
&& self.infcx.tcx.features().pin_ergonomics() =>
2508+
{
2509+
self.is_mutable(place_base, is_local_mutation_allowed)
2510+
}
25012511
// All other projections are owned by their base path, so mutable if
25022512
// base path is mutable
25032513
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
@@ -559,7 +559,7 @@ fn resolve_local<'tcx>(
559559
// & expression, and its lifetime would be extended to the end of the block (due
560560
// to a different rule, not the below code).
561561
match pat.kind {
562-
PatKind::Binding(hir::BindingMode(hir::ByRef::Yes(_), _), ..) => true,
562+
PatKind::Binding(hir::BindingMode(hir::ByRef::Yes(..), _), ..) => true,
563563

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

compiler/rustc_hir_pretty/src/lib.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1919,10 +1919,15 @@ impl<'a> State<'a> {
19191919
if mutbl.is_mut() {
19201920
self.word_nbsp("mut");
19211921
}
1922-
if let ByRef::Yes(rmutbl) = by_ref {
1922+
if let ByRef::Yes(pinnedness, rmutbl) = by_ref {
19231923
self.word_nbsp("ref");
1924+
if pinnedness.is_pinned() {
1925+
self.word_nbsp("pin");
1926+
}
19241927
if rmutbl.is_mut() {
19251928
self.word_nbsp("mut");
1929+
} else if pinnedness.is_pinned() {
1930+
self.word_nbsp("const");
19261931
}
19271932
}
19281933
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
@@ -986,7 +986,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
986986
// of the pattern, as this just looks confusing, instead use the span
987987
// of the discriminant.
988988
match bm.0 {
989-
hir::ByRef::Yes(m) => {
989+
hir::ByRef::Yes(_, m) => {
990990
let bk = ty::BorrowKind::from_mutbl(m);
991991
self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk);
992992
}
@@ -1004,7 +1004,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
10041004
// Deref patterns on boxes don't borrow, so we ignore them here.
10051005
// HACK: this could be a fake pattern corresponding to a deref inserted by match
10061006
// ergonomics, in which case `pat.hir_id` will be the id of the subpattern.
1007-
if let hir::ByRef::Yes(mutability) =
1007+
if let hir::ByRef::Yes(_, mutability) =
10081008
self.cx.typeck_results().deref_pat_borrow_mode(place.place.ty(), subpattern)
10091009
{
10101010
let bk = ty::BorrowKind::from_mutbl(mutability);
@@ -1256,15 +1256,23 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
12561256
.get(pat.hir_id)
12571257
.expect("missing binding mode");
12581258

1259-
if matches!(bm.0, hir::ByRef::Yes(_)) {
1259+
if let hir::ByRef::Yes(pinnedness, _) = bm.0 {
1260+
let base_ty = if pinnedness.is_pinned() {
1261+
base_ty.pinned_ty().ok_or_else(|| {
1262+
debug!("By-pin-ref binding of non-`Pin` type: {base_ty:?}");
1263+
self.cx.report_bug(pat.span, "by-pin-ref binding of non-`Pin` type")
1264+
})?
1265+
} else {
1266+
base_ty
1267+
};
12601268
// a bind-by-ref means that the base_ty will be the type of the ident itself,
12611269
// but what we want here is the type of the underlying value being borrowed.
12621270
// So peel off one-level, turning the &T into T.
12631271
match self.cx.structurally_resolve_type(pat.span, base_ty).builtin_deref(false)
12641272
{
12651273
Some(ty) => Ok(ty),
12661274
None => {
1267-
debug!("By-ref binding of non-derefable type");
1275+
debug!("By-ref binding of non-derefable type: {base_ty:?}");
12681276
Err(self
12691277
.cx
12701278
.report_bug(pat.span, "by-ref binding of non-derefable type"))
@@ -1706,6 +1714,18 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
17061714
};
17071715
self.pat_deref_place(pat.hir_id, place_with_id, pat, target_ty)?
17081716
}
1717+
adjustment::PatAdjust::PinDeref => {
1718+
debug!("`PinDeref` of non-pinned-reference type: {:?}", adjust.source);
1719+
let target_ty = adjust.source.pinned_ty().ok_or_else(|| {
1720+
self.cx.report_bug(
1721+
self.cx.tcx().hir_span(pat.hir_id),
1722+
"`PinDeref` of non-pinned-reference type",
1723+
)
1724+
})?;
1725+
let kind = ProjectionKind::Field(FieldIdx::ZERO, FIRST_VARIANT);
1726+
place_with_id = self.cat_projection(pat.hir_id, place_with_id, target_ty, kind);
1727+
self.cat_deref(pat.hir_id, place_with_id)?
1728+
}
17091729
};
17101730
}
17111731
drop(typeck_results); // explicitly release borrow of typeck results, just in case.
@@ -1877,7 +1897,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
18771897
// Deref patterns on boxes are lowered using a built-in deref.
18781898
hir::ByRef::No => self.cat_deref(hir_id, base_place),
18791899
// For other types, we create a temporary to match on.
1880-
hir::ByRef::Yes(mutability) => {
1900+
hir::ByRef::Yes(_, mutability) => {
18811901
let re_erased = self.cx.tcx().lifetimes.re_erased;
18821902
let ty = Ty::new_ref(self.cx.tcx(), re_erased, target_ty, mutability);
18831903
// A deref pattern stores the result of `Deref::deref` or `DerefMut::deref_mut` ...

0 commit comments

Comments
 (0)