Skip to content

Commit 203f504

Browse files
committed
Implement pattern matching for &pin mut|const T
1 parent dcecb99 commit 203f504

Some content is hidden

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

49 files changed

+2169
-97
lines changed

compiler/rustc_ast/src/ast.rs

+19-6
Original file line numberDiff line numberDiff line change
@@ -719,14 +719,14 @@ pub struct PatField {
719719
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
720720
#[derive(Encodable, Decodable, HashStable_Generic)]
721721
pub enum ByRef {
722-
Yes(Mutability),
722+
Yes(Pinnedness, Mutability),
723723
No,
724724
}
725725

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

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

753762
pub fn prefix_str(self) -> &'static str {
754763
match self {
755764
Self::NONE => "",
756765
Self::REF => "ref ",
766+
Self::REF_PIN => "ref pin const ",
757767
Self::MUT => "mut ",
758768
Self::REF_MUT => "ref mut ",
769+
Self::REF_PIN_MUT => "ref pin mut ",
759770
Self::MUT_REF => "mut ref ",
771+
Self::MUT_REF_PIN => "mut ref pin ",
760772
Self::MUT_REF_MUT => "mut ref mut ",
773+
Self::MUT_REF_PIN_MUT => "mut ref pin mut ",
761774
}
762775
}
763776
}

compiler/rustc_ast_ir/src/lib.rs

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

+6-1
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

+1-1
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

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

compiler/rustc_hir/src/hir.rs

+1-1
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

+1-1
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

+6-1
Original file line numberDiff line numberDiff line change
@@ -1906,10 +1906,15 @@ impl<'a> State<'a> {
19061906
if mutbl.is_mut() {
19071907
self.word_nbsp("mut");
19081908
}
1909-
if let ByRef::Yes(rmutbl) = by_ref {
1909+
if let ByRef::Yes(pinnedness, rmutbl) = by_ref {
19101910
self.word_nbsp("ref");
1911+
if pinnedness.is_pinned() {
1912+
self.word_nbsp("pin");
1913+
}
19111914
if rmutbl.is_mut() {
19121915
self.word_nbsp("mut");
1916+
} else if pinnedness.is_pinned() {
1917+
self.word_nbsp("const");
19131918
}
19141919
}
19151920
self.print_ident(ident);

compiler/rustc_hir_typeck/src/expr_use_visitor.rs

+39-17
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,22 +1255,34 @@ 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(_)) {
1259-
// a bind-by-ref means that the base_ty will be the type of the ident itself,
1260-
// but what we want here is the type of the underlying value being borrowed.
1261-
// So peel off one-level, turning the &T into T.
1262-
match self.cx.structurally_resolve_type(pat.span, base_ty).builtin_deref(false)
1263-
{
1264-
Some(ty) => Ok(ty),
1265-
None => {
1266-
debug!("By-ref binding of non-derefable type");
1267-
Err(self
1268-
.cx
1269-
.report_bug(pat.span, "by-ref binding of non-derefable type"))
1258+
match bm.0 {
1259+
hir::ByRef::Yes(pinnedness, _) => {
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");
1263+
self.cx.report_bug(pat.span, "by-pin-ref binding of non-`Pin` type")
1264+
})?
1265+
} else {
1266+
base_ty
1267+
};
1268+
// a bind-by-ref means that the base_ty will be the type of the ident itself,
1269+
// but what we want here is the type of the underlying value being borrowed.
1270+
// So peel off one-level, turning the &T into T.
1271+
match self
1272+
.cx
1273+
.structurally_resolve_type(pat.span, base_ty)
1274+
.builtin_deref(false)
1275+
{
1276+
Some(ty) => Ok(ty),
1277+
None => {
1278+
debug!("By-ref binding of non-derefable type");
1279+
Err(self
1280+
.cx
1281+
.report_bug(pat.span, "by-ref binding of non-derefable type"))
1282+
}
12701283
}
12711284
}
1272-
} else {
1273-
Ok(base_ty)
1285+
_ => Ok(base_ty),
12741286
}
12751287
}
12761288
_ => Ok(base_ty),
@@ -1696,6 +1708,16 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
16961708
};
16971709
self.pat_deref_place(pat.hir_id, place_with_id, pat, target_ty)?
16981710
}
1711+
adjustment::PatAdjust::PinDeref => {
1712+
let target_ty = match adjusts.peek() {
1713+
Some(&&next_adjust) => next_adjust.source,
1714+
// At the end of the deref chain, we get `pat`'s scrutinee.
1715+
None => self.pat_ty_unadjusted(pat)?,
1716+
};
1717+
let kind = ProjectionKind::Field(FieldIdx::ZERO, FIRST_VARIANT);
1718+
place_with_id = self.cat_projection(pat.hir_id, place_with_id, target_ty, kind);
1719+
self.cat_deref(pat.hir_id, place_with_id)?
1720+
}
16991721
};
17001722
}
17011723
drop(typeck_results); // explicitly release borrow of typeck results, just in case.
@@ -1867,7 +1889,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
18671889
// Deref patterns on boxes are lowered using a built-in deref.
18681890
hir::ByRef::No => self.cat_deref(hir_id, base_place),
18691891
// For other types, we create a temporary to match on.
1870-
hir::ByRef::Yes(mutability) => {
1892+
hir::ByRef::Yes(_, mutability) => {
18711893
let re_erased = self.cx.tcx().lifetimes.re_erased;
18721894
let ty = Ty::new_ref(self.cx.tcx(), re_erased, target_ty, mutability);
18731895
// A deref pattern stores the result of `Deref::deref` or `DerefMut::deref_mut` ...

0 commit comments

Comments
 (0)