Skip to content

Commit 833fd1e

Browse files
committed
Implement pattern matching for &pin mut|const T
1 parent 5adb489 commit 833fd1e

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
@@ -733,14 +733,14 @@ pub struct PatField {
733733
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
734734
#[derive(Encodable, Decodable, HashStable_Generic)]
735735
pub enum ByRef {
736-
Yes(Mutability),
736+
Yes(Pinnedness, Mutability),
737737
No,
738738
}
739739

740740
impl ByRef {
741741
#[must_use]
742742
pub fn cap_ref_mutability(mut self, mutbl: Mutability) -> Self {
743-
if let ByRef::Yes(old_mutbl) = &mut self {
743+
if let ByRef::Yes(_, old_mutbl) = &mut self {
744744
*old_mutbl = cmp::min(*old_mutbl, mutbl);
745745
}
746746
self
@@ -758,20 +758,33 @@ pub struct BindingMode(pub ByRef, pub Mutability);
758758

759759
impl BindingMode {
760760
pub const NONE: Self = Self(ByRef::No, Mutability::Not);
761-
pub const REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Not);
761+
pub const REF: Self = Self(ByRef::Yes(Pinnedness::Not, Mutability::Not), Mutability::Not);
762+
pub const REF_PIN: Self =
763+
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Not), Mutability::Not);
762764
pub const MUT: Self = Self(ByRef::No, Mutability::Mut);
763-
pub const REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Not);
764-
pub const MUT_REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Mut);
765-
pub const MUT_REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Mut);
765+
pub const REF_MUT: Self = Self(ByRef::Yes(Pinnedness::Not, Mutability::Mut), Mutability::Not);
766+
pub const REF_PIN_MUT: Self =
767+
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Mut), Mutability::Not);
768+
pub const MUT_REF: Self = Self(ByRef::Yes(Pinnedness::Not, Mutability::Not), Mutability::Mut);
769+
pub const MUT_REF_PIN: Self =
770+
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Not), Mutability::Mut);
771+
pub const MUT_REF_MUT: Self =
772+
Self(ByRef::Yes(Pinnedness::Not, Mutability::Mut), Mutability::Mut);
773+
pub const MUT_REF_PIN_MUT: Self =
774+
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Mut), Mutability::Mut);
766775

767776
pub fn prefix_str(self) -> &'static str {
768777
match self {
769778
Self::NONE => "",
770779
Self::REF => "ref ",
780+
Self::REF_PIN => "ref pin const ",
771781
Self::MUT => "mut ",
772782
Self::REF_MUT => "ref mut ",
783+
Self::REF_PIN_MUT => "ref pin mut ",
773784
Self::MUT_REF => "mut ref ",
785+
Self::MUT_REF_PIN => "mut ref pin ",
774786
Self::MUT_REF_MUT => "mut ref mut ",
787+
Self::MUT_REF_PIN_MUT => "mut ref pin mut ",
775788
}
776789
}
777790
}

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
@@ -1705,10 +1705,15 @@ impl<'a> State<'a> {
17051705
if mutbl.is_mut() {
17061706
self.word_nbsp("mut");
17071707
}
1708-
if let ByRef::Yes(rmutbl) = by_ref {
1708+
if let ByRef::Yes(pinnedness, rmutbl) = by_ref {
17091709
self.word_nbsp("ref");
1710+
if pinnedness.is_pinned() {
1711+
self.word_nbsp("pin");
1712+
}
17101713
if rmutbl.is_mut() {
17111714
self.word_nbsp("mut");
1715+
} else if pinnedness.is_pinned() {
1716+
self.word_nbsp("const");
17121717
}
17131718
}
17141719
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
@@ -1234,7 +1234,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
12341234
}
12351235

12361236
LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
1237-
binding_mode: BindingMode(ByRef::Yes(_), _),
1237+
binding_mode: BindingMode(ByRef::Yes(..), _),
12381238
..
12391239
})) => {
12401240
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
@@ -2503,6 +2503,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
25032503
_ => bug!("Deref of unexpected type: {:?}", base_ty),
25042504
}
25052505
}
2506+
// Check as the inner reference type if it is a field projection
2507+
// from the `&pin` pattern
2508+
ProjectionElem::Field(FieldIdx::ZERO, _)
2509+
if let Some(adt) =
2510+
place_base.ty(self.body(), self.infcx.tcx).ty.ty_adt_def()
2511+
&& adt.is_pin()
2512+
&& self.infcx.tcx.features().pin_ergonomics() =>
2513+
{
2514+
self.is_mutable(place_base, is_local_mutation_allowed)
2515+
}
25062516
// All other projections are owned by their base path, so mutable if
25072517
// base path is mutable
25082518
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
@@ -660,7 +660,7 @@ fn resolve_local<'tcx>(
660660
// & expression, and its lifetime would be extended to the end of the block (due
661661
// to a different rule, not the below code).
662662
match pat.kind {
663-
PatKind::Binding(hir::BindingMode(hir::ByRef::Yes(_), _), ..) => true,
663+
PatKind::Binding(hir::BindingMode(hir::ByRef::Yes(..), _), ..) => true,
664664

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

compiler/rustc_hir_pretty/src/lib.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1910,10 +1910,15 @@ impl<'a> State<'a> {
19101910
if mutbl.is_mut() {
19111911
self.word_nbsp("mut");
19121912
}
1913-
if let ByRef::Yes(rmutbl) = by_ref {
1913+
if let ByRef::Yes(pinnedness, rmutbl) = by_ref {
19141914
self.word_nbsp("ref");
1915+
if pinnedness.is_pinned() {
1916+
self.word_nbsp("pin");
1917+
}
19151918
if rmutbl.is_mut() {
19161919
self.word_nbsp("mut");
1920+
} else if pinnedness.is_pinned() {
1921+
self.word_nbsp("const");
19171922
}
19181923
}
19191924
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)