Skip to content

Commit 201f85f

Browse files
committed
Implement pattern matching for &pin mut|const T
1 parent e131842 commit 201f85f

File tree

53 files changed

+2552
-86
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

+2552
-86
lines changed

compiler/rustc_ast/src/ast.rs

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

797797
impl ByRef {
798798
#[must_use]
799799
pub fn cap_ref_mutability(mut self, mutbl: Mutability) -> Self {
800-
if let ByRef::Yes(old_mutbl) = &mut self {
800+
if let ByRef::Yes(_, old_mutbl) = &mut self {
801801
*old_mutbl = cmp::min(*old_mutbl, mutbl);
802802
}
803803
self
@@ -815,20 +815,33 @@ pub struct BindingMode(pub ByRef, pub Mutability);
815815

816816
impl BindingMode {
817817
pub const NONE: Self = Self(ByRef::No, Mutability::Not);
818-
pub const REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Not);
818+
pub const REF: Self = Self(ByRef::Yes(Pinnedness::Not, Mutability::Not), Mutability::Not);
819+
pub const REF_PIN: Self =
820+
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Not), Mutability::Not);
819821
pub const MUT: Self = Self(ByRef::No, Mutability::Mut);
820-
pub const REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Not);
821-
pub const MUT_REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Mut);
822-
pub const MUT_REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Mut);
822+
pub const REF_MUT: Self = Self(ByRef::Yes(Pinnedness::Not, Mutability::Mut), Mutability::Not);
823+
pub const REF_PIN_MUT: Self =
824+
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Mut), Mutability::Not);
825+
pub const MUT_REF: Self = Self(ByRef::Yes(Pinnedness::Not, Mutability::Not), Mutability::Mut);
826+
pub const MUT_REF_PIN: Self =
827+
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Not), Mutability::Mut);
828+
pub const MUT_REF_MUT: Self =
829+
Self(ByRef::Yes(Pinnedness::Not, Mutability::Mut), Mutability::Mut);
830+
pub const MUT_REF_PIN_MUT: Self =
831+
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Mut), Mutability::Mut);
823832

824833
pub fn prefix_str(self) -> &'static str {
825834
match self {
826835
Self::NONE => "",
827836
Self::REF => "ref ",
837+
Self::REF_PIN => "ref pin const ",
828838
Self::MUT => "mut ",
829839
Self::REF_MUT => "ref mut ",
840+
Self::REF_PIN_MUT => "ref pin mut ",
830841
Self::MUT_REF => "mut ref ",
842+
Self::MUT_REF_PIN => "mut ref pin ",
831843
Self::MUT_REF_MUT => "mut ref mut ",
844+
Self::MUT_REF_PIN_MUT => "mut ref pin mut ",
832845
}
833846
}
834847
}

compiler/rustc_ast/src/visit.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ macro_rules! common_visitor_and_walkers {
368368
crate::tokenstream::TokenStream,
369369
Movability,
370370
Mutability,
371+
Pinnedness,
371372
Result<(), rustc_span::ErrorGuaranteed>,
372373
rustc_data_structures::fx::FxHashMap<Symbol, usize>,
373374
rustc_span::ErrorGuaranteed,

compiler/rustc_ast_ir/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,3 +311,10 @@ pub enum Pinnedness {
311311
Not,
312312
Pinned,
313313
}
314+
315+
impl Pinnedness {
316+
/// Return `true` if self is pinned
317+
pub fn is_pinned(self) -> bool {
318+
matches!(self, Self::Pinned)
319+
}
320+
}

compiler/rustc_ast_pretty/src/pprust/state.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1711,10 +1711,15 @@ impl<'a> State<'a> {
17111711
if mutbl.is_mut() {
17121712
self.word_nbsp("mut");
17131713
}
1714-
if let ByRef::Yes(rmutbl) = by_ref {
1714+
if let ByRef::Yes(pinnedness, rmutbl) = by_ref {
17151715
self.word_nbsp("ref");
1716+
if pinnedness.is_pinned() {
1717+
self.word_nbsp("pin");
1718+
}
17161719
if rmutbl.is_mut() {
17171720
self.word_nbsp("mut");
1721+
} else if pinnedness.is_pinned() {
1722+
self.word_nbsp("const");
17181723
}
17191724
}
17201725
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
@@ -1190,7 +1190,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
11901190
}
11911191

11921192
LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
1193-
binding_mode: BindingMode(ByRef::Yes(_), _),
1193+
binding_mode: BindingMode(ByRef::Yes(..), _),
11941194
..
11951195
})) => {
11961196
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
@@ -2604,6 +2604,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
26042604
_ => bug!("Deref of unexpected type: {:?}", base_ty),
26052605
}
26062606
}
2607+
// Check as the inner reference type if it is a field projection
2608+
// from the `&pin` pattern
2609+
ProjectionElem::Field(FieldIdx::ZERO, _)
2610+
if let Some(adt) =
2611+
place_base.ty(self.body(), self.infcx.tcx).ty.ty_adt_def()
2612+
&& adt.is_pin()
2613+
&& self.infcx.tcx.features().pin_ergonomics() =>
2614+
{
2615+
self.is_mutable(place_base, is_local_mutation_allowed)
2616+
}
26072617
// All other projections are owned by their base path, so mutable if
26082618
// base path is mutable
26092619
ProjectionElem::Field(..)

compiler/rustc_hir/src/hir.rs

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

compiler/rustc_hir_analysis/src/check/region.rs

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

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

compiler/rustc_hir_pretty/src/lib.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1924,10 +1924,15 @@ impl<'a> State<'a> {
19241924
if mutbl.is_mut() {
19251925
self.word_nbsp("mut");
19261926
}
1927-
if let ByRef::Yes(rmutbl) = by_ref {
1927+
if let ByRef::Yes(pinnedness, rmutbl) = by_ref {
19281928
self.word_nbsp("ref");
1929+
if pinnedness.is_pinned() {
1930+
self.word_nbsp("pin");
1931+
}
19291932
if rmutbl.is_mut() {
19301933
self.word_nbsp("mut");
1934+
} else if pinnedness.is_pinned() {
1935+
self.word_nbsp("const");
19311936
}
19321937
}
19331938
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)