Implement pattern matching for &pin mut|const T

This commit is contained in:
Frank King 2025-04-13 22:57:37 +08:00
parent 292be5c7c0
commit 26f35ae269
53 changed files with 2552 additions and 86 deletions

View file

@ -789,14 +789,14 @@ pub struct PatField {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[derive(Encodable, Decodable, HashStable_Generic, Walkable)]
pub enum ByRef {
Yes(Mutability),
Yes(Pinnedness, Mutability),
No,
}
impl ByRef {
#[must_use]
pub fn cap_ref_mutability(mut self, mutbl: Mutability) -> Self {
if let ByRef::Yes(old_mutbl) = &mut self {
if let ByRef::Yes(_, old_mutbl) = &mut self {
*old_mutbl = cmp::min(*old_mutbl, mutbl);
}
self
@ -814,20 +814,33 @@ pub struct BindingMode(pub ByRef, pub Mutability);
impl BindingMode {
pub const NONE: Self = Self(ByRef::No, Mutability::Not);
pub const REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Not);
pub const REF: Self = Self(ByRef::Yes(Pinnedness::Not, Mutability::Not), Mutability::Not);
pub const REF_PIN: Self =
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Not), Mutability::Not);
pub const MUT: Self = Self(ByRef::No, Mutability::Mut);
pub const REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Not);
pub const MUT_REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Mut);
pub const MUT_REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Mut);
pub const REF_MUT: Self = Self(ByRef::Yes(Pinnedness::Not, Mutability::Mut), Mutability::Not);
pub const REF_PIN_MUT: Self =
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Mut), Mutability::Not);
pub const MUT_REF: Self = Self(ByRef::Yes(Pinnedness::Not, Mutability::Not), Mutability::Mut);
pub const MUT_REF_PIN: Self =
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Not), Mutability::Mut);
pub const MUT_REF_MUT: Self =
Self(ByRef::Yes(Pinnedness::Not, Mutability::Mut), Mutability::Mut);
pub const MUT_REF_PIN_MUT: Self =
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Mut), Mutability::Mut);
pub fn prefix_str(self) -> &'static str {
match self {
Self::NONE => "",
Self::REF => "ref ",
Self::REF_PIN => "ref pin const ",
Self::MUT => "mut ",
Self::REF_MUT => "ref mut ",
Self::REF_PIN_MUT => "ref pin mut ",
Self::MUT_REF => "mut ref ",
Self::MUT_REF_PIN => "mut ref pin ",
Self::MUT_REF_MUT => "mut ref mut ",
Self::MUT_REF_PIN_MUT => "mut ref pin mut ",
}
}
}

View file

@ -368,6 +368,7 @@ macro_rules! common_visitor_and_walkers {
crate::tokenstream::TokenStream,
Movability,
Mutability,
Pinnedness,
Result<(), rustc_span::ErrorGuaranteed>,
rustc_data_structures::fx::FxHashMap<Symbol, usize>,
rustc_span::ErrorGuaranteed,

View file

@ -311,3 +311,10 @@ pub enum Pinnedness {
Not,
Pinned,
}
impl Pinnedness {
/// Return `true` if self is pinned
pub fn is_pinned(self) -> bool {
matches!(self, Self::Pinned)
}
}

View file

@ -1712,10 +1712,15 @@ impl<'a> State<'a> {
if mutbl.is_mut() {
self.word_nbsp("mut");
}
if let ByRef::Yes(rmutbl) = by_ref {
if let ByRef::Yes(pinnedness, rmutbl) = by_ref {
self.word_nbsp("ref");
if pinnedness.is_pinned() {
self.word_nbsp("pin");
}
if rmutbl.is_mut() {
self.word_nbsp("mut");
} else if pinnedness.is_pinned() {
self.word_nbsp("const");
}
}
self.print_ident(*ident);

View file

@ -1188,7 +1188,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
binding_mode: BindingMode(ByRef::Yes(_), _),
binding_mode: BindingMode(ByRef::Yes(..), _),
..
})) => {
let pattern_span: Span = local_decl.source_info.span;

View file

@ -2584,6 +2584,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
_ => bug!("Deref of unexpected type: {:?}", base_ty),
}
}
// Check as the inner reference type if it is a field projection
// from the `&pin` pattern
ProjectionElem::Field(FieldIdx::ZERO, _)
if let Some(adt) =
place_base.ty(self.body(), self.infcx.tcx).ty.ty_adt_def()
&& adt.is_pin()
&& self.infcx.tcx.features().pin_ergonomics() =>
{
self.is_mutable(place_base, is_local_mutation_allowed)
}
// All other projections are owned by their base path, so mutable if
// base path is mutable
ProjectionElem::Field(..)

View file

@ -13,7 +13,7 @@ use rustc_ast::{
pub use rustc_ast::{
AssignOp, AssignOpKind, AttrId, AttrStyle, BinOp, BinOpKind, BindingMode, BorrowKind,
BoundConstness, BoundPolarity, ByRef, CaptureBy, DelimArgs, ImplPolarity, IsAuto,
MetaItemInner, MetaItemLit, Movability, Mutability, UnOp,
MetaItemInner, MetaItemLit, Movability, Mutability, Pinnedness, UnOp,
};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::sorted_map::SortedMap;

View file

@ -575,7 +575,7 @@ fn resolve_local<'tcx>(
// & expression, and its lifetime would be extended to the end of the block (due
// to a different rule, not the below code).
match pat.kind {
PatKind::Binding(hir::BindingMode(hir::ByRef::Yes(_), _), ..) => true,
PatKind::Binding(hir::BindingMode(hir::ByRef::Yes(..), _), ..) => true,
PatKind::Struct(_, field_pats, _) => field_pats.iter().any(|fp| is_binding_pat(fp.pat)),

View file

@ -1928,10 +1928,15 @@ impl<'a> State<'a> {
if mutbl.is_mut() {
self.word_nbsp("mut");
}
if let ByRef::Yes(rmutbl) = by_ref {
if let ByRef::Yes(pinnedness, rmutbl) = by_ref {
self.word_nbsp("ref");
if pinnedness.is_pinned() {
self.word_nbsp("pin");
}
if rmutbl.is_mut() {
self.word_nbsp("mut");
} else if pinnedness.is_pinned() {
self.word_nbsp("const");
}
}
self.print_ident(ident);

View file

@ -986,7 +986,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
// of the pattern, as this just looks confusing, instead use the span
// of the discriminant.
match bm.0 {
hir::ByRef::Yes(m) => {
hir::ByRef::Yes(_, m) => {
let bk = ty::BorrowKind::from_mutbl(m);
self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk);
}
@ -1004,7 +1004,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
// Deref patterns on boxes don't borrow, so we ignore them here.
// HACK: this could be a fake pattern corresponding to a deref inserted by match
// ergonomics, in which case `pat.hir_id` will be the id of the subpattern.
if let hir::ByRef::Yes(mutability) =
if let hir::ByRef::Yes(_, mutability) =
self.cx.typeck_results().deref_pat_borrow_mode(place.place.ty(), subpattern)
{
let bk = ty::BorrowKind::from_mutbl(mutability);
@ -1256,7 +1256,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
.get(pat.hir_id)
.expect("missing binding mode");
if matches!(bm.0, hir::ByRef::Yes(_)) {
if let hir::ByRef::Yes(pinnedness, _) = bm.0 {
let base_ty = if pinnedness.is_pinned() {
base_ty.pinned_ty().ok_or_else(|| {
debug!("By-pin-ref binding of non-`Pin` type: {base_ty:?}");
self.cx.report_bug(pat.span, "by-pin-ref binding of non-`Pin` type")
})?
} else {
base_ty
};
// a bind-by-ref means that the base_ty will be the type of the ident itself,
// but what we want here is the type of the underlying value being borrowed.
// So peel off one-level, turning the &T into T.
@ -1264,7 +1272,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
{
Some(ty) => Ok(ty),
None => {
debug!("By-ref binding of non-derefable type");
debug!("By-ref binding of non-derefable type: {base_ty:?}");
Err(self
.cx
.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
};
self.pat_deref_place(pat.hir_id, place_with_id, pat, target_ty)?
}
adjustment::PatAdjust::PinDeref => {
debug!("`PinDeref` of non-pinned-reference type: {:?}", adjust.source);
let target_ty = adjust.source.pinned_ty().ok_or_else(|| {
self.cx.report_bug(
self.cx.tcx().hir_span(pat.hir_id),
"`PinDeref` of non-pinned-reference type",
)
})?;
let kind = ProjectionKind::Field(FieldIdx::ZERO, FIRST_VARIANT);
place_with_id = self.cat_projection(pat.hir_id, place_with_id, target_ty, kind);
self.cat_deref(pat.hir_id, place_with_id)?
}
};
}
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
// Deref patterns on boxes are lowered using a built-in deref.
hir::ByRef::No => self.cat_deref(hir_id, base_place),
// For other types, we create a temporary to match on.
hir::ByRef::Yes(mutability) => {
hir::ByRef::Yes(_, mutability) => {
let re_erased = self.cx.tcx().lifetimes.re_erased;
let ty = Ty::new_ref(self.cx.tcx(), re_erased, target_ty, mutability);
// A deref pattern stores the result of `Deref::deref` or `DerefMut::deref_mut` ...

View file

@ -18,7 +18,7 @@ use rustc_hir::{
use rustc_hir_analysis::autoderef::report_autoderef_recursion_limit_error;
use rustc_infer::infer::RegionVariableOrigin;
use rustc_middle::traits::PatternOriginExpr;
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use rustc_middle::ty::{self, Pinnedness, Ty, TypeVisitableExt};
use rustc_middle::{bug, span_bug};
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
use rustc_session::parse::feature_err;
@ -413,7 +413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pat,
derefed_tys.iter().filter_map(|adjust| match adjust.kind {
PatAdjust::OverloadedDeref => Some(adjust.source),
PatAdjust::BuiltinDeref => None,
PatAdjust::BuiltinDeref | PatAdjust::PinDeref => None,
}),
);
}
@ -471,7 +471,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pat_info: PatInfo<'tcx>,
) -> Ty<'tcx> {
#[cfg(debug_assertions)]
if pat_info.binding_mode == ByRef::Yes(Mutability::Mut)
if matches!(pat_info.binding_mode, ByRef::Yes(_, Mutability::Mut))
&& pat_info.max_ref_mutbl != MutblCap::Mut
&& self.downgrade_mut_inside_shared()
{
@ -489,12 +489,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let old_pat_info = pat_info;
let pat_info = PatInfo { current_depth: old_pat_info.current_depth + 1, ..old_pat_info };
let adjust_binding_mode = |inner_pinnedness, inner_mutability| {
match pat_info.binding_mode {
// If default binding mode is by value, make it `ref`, `ref mut`, `ref pin const`
// or `ref pin mut` (depending on whether we observe `&`, `&mut`, `&pin const` or
// `&pin mut`).
ByRef::No => ByRef::Yes(inner_pinnedness, inner_mutability),
// When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`).
// Pinnedness is preserved.
ByRef::Yes(pinnedness, Mutability::Mut) => ByRef::Yes(pinnedness, inner_mutability),
// Once a `ref`, always a `ref`.
// This is because a `& &mut` cannot mutate the underlying value.
// Pinnedness is preserved.
ByRef::Yes(pinnedness, Mutability::Not) => ByRef::Yes(pinnedness, Mutability::Not),
}
};
match pat.kind {
// Peel off a `&` or `&mut` from the scrutinee type. See the examples in
// Peel off a `&` or `&mut`from the scrutinee type. See the examples in
// `tests/ui/rfcs/rfc-2005-default-binding-mode`.
_ if let AdjustMode::Peel { kind: peel_kind } = adjust_mode
&& pat.default_binding_modes
&& let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind()
&& let &ty::Ref(_, inner_ty, inner_mutability) = expected.kind()
&& self.should_peel_ref(peel_kind, expected) =>
{
debug!("inspecting {:?}", expected);
@ -508,22 +524,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.or_default()
.push(PatAdjustment { kind: PatAdjust::BuiltinDeref, source: expected });
let mut binding_mode = ByRef::Yes(match pat_info.binding_mode {
// If default binding mode is by value, make it `ref` or `ref mut`
// (depending on whether we observe `&` or `&mut`).
ByRef::No |
// When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`).
ByRef::Yes(Mutability::Mut) => inner_mutability,
// Once a `ref`, always a `ref`.
// This is because a `& &mut` cannot mutate the underlying value.
ByRef::Yes(Mutability::Not) => Mutability::Not,
});
let mut binding_mode = adjust_binding_mode(Pinnedness::Not, inner_mutability);
let mut max_ref_mutbl = pat_info.max_ref_mutbl;
if self.downgrade_mut_inside_shared() {
binding_mode = binding_mode.cap_ref_mutability(max_ref_mutbl.as_mutbl());
}
if binding_mode == ByRef::Yes(Mutability::Not) {
if matches!(binding_mode, ByRef::Yes(_, Mutability::Not)) {
max_ref_mutbl = MutblCap::Not;
}
debug!("default binding mode is now {:?}", binding_mode);
@ -533,6 +540,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Recurse with the new expected type.
self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, new_pat_info)
}
// If `pin_ergonomics` is enabled, peel the `&pin` from the pinned reference type. See the
// examples in `tests/ui/async-await/pin-ergonomics/`.
_ if self.tcx.features().pin_ergonomics()
&& let AdjustMode::Peel { kind: peel_kind } = adjust_mode
&& pat.default_binding_modes
&& self.should_peel_smart_pointer(peel_kind, expected)
&& let Some(pinned_ty) = expected.pinned_ty()
// Currently, only pinned reference is specially handled, leaving other
// pinned types (e.g. `Pin<Box<T>>` to deref patterns) handled as a
// deref pattern.
&& let &ty::Ref(_, inner_ty, inner_mutability) = pinned_ty.kind() =>
{
debug!("scrutinee ty {expected:?} is a pinned reference, inserting pin deref");
// Preserve the pinned type. We'll need it later during THIR lowering.
self.typeck_results
.borrow_mut()
.pat_adjustments_mut()
.entry(pat.hir_id)
.or_default()
.push(PatAdjustment { kind: PatAdjust::PinDeref, source: expected });
let binding_mode = adjust_binding_mode(Pinnedness::Pinned, inner_mutability);
// If the pinnedness is `Not`, it means the pattern is unpinned
// and thus requires an `Unpin` bound.
if binding_mode == ByRef::Yes(Pinnedness::Not, Mutability::Mut) {
self.register_bound(
inner_ty,
self.tcx.require_lang_item(hir::LangItem::Unpin, pat.span),
self.misc(pat.span),
);
}
// Use the old pat info to keep `current_depth` to its old value.
let new_pat_info = PatInfo { binding_mode, ..old_pat_info };
// Recurse with the new expected type.
// using `break` instead of `return` in case where any shared codes are added
// after the `match pat.kind {}`.
self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, new_pat_info)
}
// If `deref_patterns` is enabled, peel a smart pointer from the scrutinee type. See the
// examples in `tests/ui/pattern/deref_patterns/`.
_ if self.tcx.features().deref_patterns()
@ -1061,7 +1106,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Determine the binding mode...
let bm = match user_bind_annot {
BindingMode(ByRef::No, Mutability::Mut) if let ByRef::Yes(def_br_mutbl) = def_br => {
BindingMode(ByRef::No, Mutability::Mut) if let ByRef::Yes(_, def_br_mutbl) = def_br => {
// Only mention the experimental `mut_ref` feature if if we're in edition 2024 and
// using other experimental matching features compatible with it.
if pat.span.at_least_rust_2024()
@ -1091,8 +1136,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
BindingMode(ByRef::Yes(user_br_mutbl), _) => {
if let ByRef::Yes(def_br_mutbl) = def_br {
BindingMode(ByRef::Yes(_, user_br_mutbl), _) => {
if let ByRef::Yes(_, def_br_mutbl) = def_br {
// `ref`/`ref mut` overrides the binding mode on edition <= 2021
self.add_rust_2024_migration_desugared_pat(
pat_info.top_info.hir_id,
@ -1108,7 +1153,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
};
if bm.0 == ByRef::Yes(Mutability::Mut)
if matches!(bm.0, ByRef::Yes(_, Mutability::Mut))
&& let MutblCap::WeaklyNot(and_pat_span) = pat_info.max_ref_mutbl
{
let mut err = struct_span_code_err!(
@ -1136,7 +1181,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let local_ty = self.local_ty(pat.span, pat.hir_id);
let eq_ty = match bm.0 {
ByRef::Yes(mutbl) => {
ByRef::Yes(Pinnedness::Not, mutbl) => {
// If the binding is like `ref x | ref mut x`,
// then `x` is assigned a value of type `&M T` where M is the
// mutability and T is the expected type.
@ -1146,6 +1191,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// See (note_1) for an explanation.
self.new_ref_ty(pat.span, mutbl, expected)
}
// Wrapping the type into `Pin` if the binding is like `ref pin const|mut x`
ByRef::Yes(Pinnedness::Pinned, mutbl) => Ty::new_adt(
self.tcx,
self.tcx.adt_def(self.tcx.require_lang_item(hir::LangItem::Pin, pat.span)),
self.tcx.mk_args(&[self.new_ref_ty(pat.span, mutbl, expected).into()]),
),
// Otherwise, the type of x is the expected type `T`.
ByRef::No => expected, // As above, `T <: typeof(x)` is required, but we use equality, see (note_1).
};
@ -2605,7 +2656,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected = self.try_structurally_resolve_type(pat.span, expected);
// Determine whether we're consuming an inherited reference and resetting the default
// binding mode, based on edition and enabled experimental features.
if let ByRef::Yes(inh_mut) = pat_info.binding_mode {
if let ByRef::Yes(_, inh_mut) = pat_info.binding_mode {
match self.ref_pat_matches_inherited_ref(pat.span.edition()) {
InheritedRefMatchRule::EatOuter => {
// ref pattern attempts to consume inherited reference
@ -3126,8 +3177,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If the user-provided binding modifier doesn't match the default binding mode, we'll
// need to suggest reference patterns, which can affect other bindings.
// For simplicity, we opt to suggest making the pattern fully explicit.
info.suggest_eliding_modes &=
user_bind_annot == BindingMode(ByRef::Yes(def_br_mutbl), Mutability::Not);
info.suggest_eliding_modes &= matches!(
user_bind_annot,
BindingMode(ByRef::Yes(_, mutbl), Mutability::Not) if mutbl == def_br_mutbl
);
if user_bind_annot == BindingMode(ByRef::No, Mutability::Mut) {
info.bad_mut_modifiers = true;
"`mut` binding modifier"

View file

@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for StaticMutRefs {
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &Stmt<'_>) {
if let hir::StmtKind::Let(loc) = stmt.kind
&& let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind
&& let hir::ByRef::Yes(m) = ba.0
&& let hir::ByRef::Yes(_, m) = ba.0
&& let Some(init) = loc.init
&& let Some(err_span) = path_is_static_mut(init, init.span)
{

View file

@ -232,4 +232,7 @@ pub enum PatAdjust {
/// An implicit call to `Deref(Mut)::deref(_mut)` before matching, such as when matching the
/// pattern `[..]` against a scrutinee of type `Vec<T>`.
OverloadedDeref,
/// An implicit dereference before matching a `&pin` reference (under feature `pin_ergonomics`),
/// which will be lowered as a builtin deref of the private field `__pointer` in `Pin`
PinDeref,
}

View file

@ -55,6 +55,8 @@ bitflags::bitflags! {
const IS_UNSAFE_CELL = 1 << 9;
/// Indicates whether the type is `UnsafePinned`.
const IS_UNSAFE_PINNED = 1 << 10;
/// Indicates whether the type is `Pin`.
const IS_PIN = 1 << 11;
}
}
rustc_data_structures::external_bitflags_debug! { AdtFlags }
@ -313,6 +315,9 @@ impl AdtDefData {
if tcx.is_lang_item(did, LangItem::UnsafePinned) {
flags |= AdtFlags::IS_UNSAFE_PINNED;
}
if tcx.is_lang_item(did, LangItem::Pin) {
flags |= AdtFlags::IS_PIN;
}
AdtDefData { did, variants, flags, repr }
}
@ -428,6 +433,12 @@ impl<'tcx> AdtDef<'tcx> {
self.flags().contains(AdtFlags::IS_MANUALLY_DROP)
}
/// Returns `true` if this is `Pin<T>`.
#[inline]
pub fn is_pin(self) -> bool {
self.flags().contains(AdtFlags::IS_PIN)
}
/// Returns `true` if this type has a destructor.
pub fn has_dtor(self, tcx: TyCtxt<'tcx>) -> bool {
self.destructor(tcx).is_some()

View file

@ -1349,6 +1349,13 @@ impl<'tcx> Ty<'tcx> {
}
}
pub fn pinned_ty(self) -> Option<Ty<'tcx>> {
match self.kind() {
Adt(def, args) if def.is_pin() => Some(args.type_at(0)),
_ => None,
}
}
/// Panics if called on any type other than `Box<T>`.
pub fn expect_boxed_ty(self) -> Ty<'tcx> {
self.boxed_ty()

View file

@ -11,6 +11,7 @@ use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap};
use rustc_hir::hir_id::OwnerId;
use rustc_hir::{
self as hir, BindingMode, ByRef, HirId, ItemLocalId, ItemLocalMap, ItemLocalSet, Mutability,
Pinnedness,
};
use rustc_index::IndexVec;
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
@ -479,7 +480,7 @@ impl<'tcx> TypeckResults<'tcx> {
let mut has_ref_mut = false;
pat.walk(|pat| {
if let hir::PatKind::Binding(_, id, _, _) = pat.kind
&& let Some(BindingMode(ByRef::Yes(Mutability::Mut), _)) =
&& let Some(BindingMode(ByRef::Yes(_, Mutability::Mut), _)) =
self.pat_binding_modes().get(id)
{
has_ref_mut = true;
@ -503,7 +504,7 @@ impl<'tcx> TypeckResults<'tcx> {
ByRef::No
} else {
let mutable = self.pat_has_ref_mut_binding(inner);
ByRef::Yes(if mutable { Mutability::Mut } else { Mutability::Not })
ByRef::Yes(Pinnedness::Not, if mutable { Mutability::Mut } else { Mutability::Not })
}
}

View file

@ -1,9 +1,10 @@
use std::sync::Arc;
use rustc_abi::FieldIdx;
use rustc_hir::ByRef;
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use rustc_middle::ty::{self, Pinnedness, Ty, TypeVisitableExt};
use crate::builder::Builder;
use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder};
@ -299,7 +300,24 @@ impl<'tcx> MatchPairTree<'tcx> {
None
}
PatKind::DerefPattern { ref subpattern, borrow: ByRef::Yes(mutability) } => {
PatKind::DerefPattern { ref subpattern, borrow: ByRef::Yes(Pinnedness::Pinned, _) } => {
let Some(ref_ty) = pattern.ty.pinned_ty() else {
rustc_middle::bug!("RefPin pattern on non-`Pin` type {:?}", pattern.ty);
};
MatchPairTree::for_pattern(
place_builder.field(FieldIdx::ZERO, ref_ty).deref(),
subpattern,
cx,
&mut subpairs,
extra_data,
);
None
}
PatKind::DerefPattern {
ref subpattern,
borrow: ByRef::Yes(Pinnedness::Not, mutability),
} => {
// Create a new temporary for each deref pattern.
// FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls?
let temp = cx.temp(

View file

@ -5,20 +5,21 @@
//! This also includes code for pattern bindings in `let` statements and
//! function parameters.
use std::assert_matches::debug_assert_matches;
use std::borrow::Borrow;
use std::mem;
use std::sync::Arc;
use itertools::{Itertools, Position};
use rustc_abi::VariantIdx;
use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::{BindingMode, ByRef, LetStmt, LocalSource, Node};
use rustc_middle::bug;
use rustc_hir::{BindingMode, ByRef, LangItem, LetStmt, LocalSource, Node, Pinnedness};
use rustc_middle::middle::region;
use rustc_middle::mir::*;
use rustc_middle::thir::{self, *};
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, ValTree, ValTreeKind};
use rustc_middle::{bug, span_bug};
use rustc_pattern_analysis::constructor::RangeEnd;
use rustc_pattern_analysis::rustc::{DeconstructedPat, RustcPatCtxt};
use rustc_span::{BytePos, Pos, Span, Symbol, sym};
@ -917,6 +918,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
visit_subpat(self, subpattern, &user_tys.deref(), f);
}
PatKind::DerefPattern { ref subpattern, borrow: ByRef::Yes(Pinnedness::Pinned, _) } => {
visit_subpat(self, subpattern, &user_tys.leaf(FieldIdx::ZERO).deref(), f);
}
PatKind::DerefPattern { ref subpattern, .. } => {
visit_subpat(self, subpattern, &ProjectedUserTypesNode::None, f);
}
@ -2747,9 +2752,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, binding.source);
self.cfg.push_assign(block, source_info, ref_for_guard, rvalue);
}
ByRef::Yes(mutbl) => {
// The arm binding will be by reference, so eagerly create it now. Drops must
// be scheduled to emit `StorageDead` on the guard's failure/break branches.
ByRef::Yes(pinnedness, mutbl) => {
// The arm binding will be by reference, so eagerly create it now // be scheduled to emit `StorageDead` on the guard's failure/break branches.
let value_for_arm = self.storage_live_binding(
block,
binding.var_id,
@ -2761,6 +2765,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let rvalue =
Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source);
let rvalue = match pinnedness {
ty::Pinnedness::Not => rvalue,
ty::Pinnedness::Pinned => {
self.pin_borrowed_local(block, value_for_arm.local, rvalue, source_info)
}
};
self.cfg.push_assign(block, source_info, value_for_arm, rvalue);
// For the guard binding, take a shared reference to that reference.
let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, value_for_arm);
@ -2797,14 +2807,59 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
let rvalue = match binding.binding_mode.0 {
ByRef::No => Rvalue::Use(self.consume_by_copy_or_move(binding.source)),
ByRef::Yes(mutbl) => {
Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source)
ByRef::Yes(pinnedness, mutbl) => {
let rvalue =
Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source);
match pinnedness {
ty::Pinnedness::Not => rvalue,
ty::Pinnedness::Pinned => {
self.pin_borrowed_local(block, local.local, rvalue, source_info)
}
}
}
};
self.cfg.push_assign(block, source_info, local, rvalue);
}
}
/// Given an rvalue `&[mut]borrow` and a local `local`, generate the pinned borrow for it:
/// ```ignore (illustrative)
/// pinned_temp = &borrow;
/// local = Pin { __pointer: move pinned_temp };
/// ```
fn pin_borrowed_local(
&mut self,
block: BasicBlock,
local: Local,
borrow: Rvalue<'tcx>,
source_info: SourceInfo,
) -> Rvalue<'tcx> {
debug_assert_matches!(borrow, Rvalue::Ref(..));
let local_ty = self.local_decls[local].ty;
let pinned_ty = local_ty.pinned_ty().unwrap_or_else(|| {
span_bug!(
source_info.span,
"expect type `Pin` for a pinned binding, found type {:?}",
local_ty
)
});
let pinned_temp =
Place::from(self.local_decls.push(LocalDecl::new(pinned_ty, source_info.span)));
self.cfg.push_assign(block, source_info, pinned_temp, borrow);
Rvalue::Aggregate(
Box::new(AggregateKind::Adt(
self.tcx.require_lang_item(LangItem::Pin, source_info.span),
FIRST_VARIANT,
self.tcx.mk_args(&[pinned_ty.into()]),
None,
None,
)),
std::iter::once(Operand::Move(pinned_temp)).collect(),
)
}
/// Each binding (`ref mut var`/`ref var`/`mut var`/`var`, where the bound
/// `var` has type `T` in the arm body) in a pattern maps to 2 locals. The
/// first local is a binding for occurrences of `var` in the guard, which

View file

@ -383,7 +383,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
}
visit::walk_pat(self, pat);
}
PatKind::Binding { mode: BindingMode(ByRef::Yes(rm), _), ty, .. } => {
PatKind::Binding { mode: BindingMode(ByRef::Yes(_, rm), _), ty, .. } => {
if self.inside_adt {
let ty::Ref(_, ty, _) = ty.kind() else {
span_bug!(

View file

@ -797,7 +797,7 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
// We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`.
let mut conflicts_ref = Vec::new();
sub.each_binding(|_, mode, _, span| {
if matches!(mode, ByRef::Yes(_)) {
if matches!(mode, ByRef::Yes(..)) {
conflicts_ref.push(span)
}
});
@ -813,7 +813,7 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
return;
}
ByRef::No => return,
ByRef::Yes(m) => m,
ByRef::Yes(_, m) => m,
};
// We now have `ref $mut_outer binding @ sub` (semantically).
@ -823,7 +823,7 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
let mut conflicts_mut_ref = Vec::new();
sub.each_binding(|name, mode, ty, span| {
match mode {
ByRef::Yes(mut_inner) => match (mut_outer, mut_inner) {
ByRef::Yes(_, mut_inner) => match (mut_outer, mut_inner) {
// Both sides are `ref`.
(Mutability::Not, Mutability::Not) => {}
// 2x `ref mut`.

View file

@ -212,7 +212,7 @@ impl<'a> PatMigration<'a> {
}
if !self.info.suggest_eliding_modes
&& explicit_ba.0 == ByRef::No
&& let ByRef::Yes(mutbl) = mode.0
&& let ByRef::Yes(_, mutbl) = mode.0
{
// If we can't fix the pattern by eliding modifiers, we'll need to make the pattern
// fully explicit. i.e. we'll need to suggest reference patterns for this.

View file

@ -11,7 +11,7 @@ use rustc_abi::{FieldIdx, Integer};
use rustc_errors::codes::*;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
use rustc_hir::{self as hir, LangItem, RangeEnd};
use rustc_hir::{self as hir, ByRef, LangItem, Mutability, Pinnedness, RangeEnd};
use rustc_index::Idx;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::interpret::LitToConstInput;
@ -114,6 +114,16 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let borrow = self.typeck_results.deref_pat_borrow_mode(adjust.source, pat);
PatKind::DerefPattern { subpattern: thir_pat, borrow }
}
PatAdjust::PinDeref => {
let mutable = self.typeck_results.pat_has_ref_mut_binding(pat);
PatKind::DerefPattern {
subpattern: thir_pat,
borrow: ByRef::Yes(
Pinnedness::Pinned,
if mutable { Mutability::Mut } else { Mutability::Not },
),
}
}
};
Box::new(Pat { span, ty: adjust.source, kind })
});
@ -354,11 +364,22 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
// A ref x pattern is the same node used for x, and as such it has
// x's type, which is &T, where we want T (the type being matched).
let var_ty = ty;
if let hir::ByRef::Yes(_) = mode.0 {
if let ty::Ref(_, rty, _) = ty.kind() {
ty = *rty;
} else {
bug!("`ref {}` has wrong type {}", ident, ty);
if let hir::ByRef::Yes(pinnedness, _) = mode.0 {
match pinnedness {
hir::Pinnedness::Pinned
if let Some(pty) = ty.pinned_ty()
&& let &ty::Ref(_, rty, _) = pty.kind() =>
{
debug_assert!(
self.tcx.features().pin_ergonomics(),
"`pin_ergonomics` must be enabled to have a by-pin-ref binding"
);
ty = rty;
}
hir::Pinnedness::Not if let &ty::Ref(_, rty, _) = ty.kind() => {
ty = rty;
}
_ => bug!("`ref {}` has wrong type {}", ident, ty),
}
};

View file

@ -36,8 +36,8 @@ use rustc_ast::tokenstream::{
use rustc_ast::util::case::Case;
use rustc_ast::{
self as ast, AnonConst, AttrArgs, AttrId, ByRef, Const, CoroutineKind, DUMMY_NODE_ID,
DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit,
Visibility, VisibilityKind,
DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Pinnedness, Recovered,
Safety, StrLit, Visibility, VisibilityKind,
};
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
@ -1317,7 +1317,12 @@ impl<'a> Parser<'a> {
/// Parses reference binding mode (`ref`, `ref mut`, or nothing).
fn parse_byref(&mut self) -> ByRef {
if self.eat_keyword(exp!(Ref)) { ByRef::Yes(self.parse_mutability()) } else { ByRef::No }
if self.eat_keyword(exp!(Ref)) {
// FIXME(pin_ergonomics): support `ref pin const|mut` bindings
ByRef::Yes(Pinnedness::Not, self.parse_mutability())
} else {
ByRef::No
}
}
/// Possibly parses mutability (`const` or `mut`).

View file

@ -7,7 +7,8 @@ use rustc_ast::util::parser::ExprPrecedence;
use rustc_ast::visit::{self, Visitor};
use rustc_ast::{
self as ast, Arm, AttrVec, BindingMode, ByRef, Expr, ExprKind, LocalKind, MacCall, Mutability,
Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, Stmt, StmtKind,
Pat, PatField, PatFieldsRest, PatKind, Path, Pinnedness, QSelf, RangeEnd, RangeSyntax, Stmt,
StmtKind,
};
use rustc_ast_pretty::pprust;
use rustc_errors::{Applicability, Diag, DiagArgValue, PResult, StashKey};
@ -778,7 +779,11 @@ impl<'a> Parser<'a> {
}
// Parse ref ident @ pat / ref mut ident @ pat
let mutbl = self.parse_mutability();
self.parse_pat_ident(BindingMode(ByRef::Yes(mutbl), Mutability::Not), syntax_loc)?
self.parse_pat_ident(
// FIXME(pin_ergonomics): support `ref pin const|mut` bindings
BindingMode(ByRef::Yes(Pinnedness::Not, mutbl), Mutability::Not),
syntax_loc,
)?
} else if self.eat_keyword(exp!(Box)) {
self.parse_pat_box()?
} else if self.check_inline_const(0) {
@ -1093,7 +1098,7 @@ impl<'a> Parser<'a> {
self.ban_mut_general_pat(mut_span, &pat, changed_any_binding);
}
if matches!(pat.kind, PatKind::Ident(BindingMode(ByRef::Yes(_), Mutability::Mut), ..)) {
if matches!(pat.kind, PatKind::Ident(BindingMode(ByRef::Yes(..), Mutability::Mut), ..)) {
self.psess.gated_spans.gate(sym::mut_ref, pat.span);
}
Ok(pat.kind)

View file

@ -981,7 +981,7 @@ pub enum ConstructorSet<Cx: PatCx> {
/// This type has the following list of constructors. If `variants` is empty and
/// `non_exhaustive` is false, don't use this; use `NoConstructors` instead.
Variants { variants: IndexVec<Cx::VariantIdx, VariantVisibility>, non_exhaustive: bool },
/// The type is `&T`.
/// The type is `&T`
Ref,
/// The type is a union.
Union,

View file

@ -94,7 +94,7 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<Hir
// We'll just ignore mut and ref mut for simplicity sake right now
if let hir::PatKind::Binding(hir::BindingMode(by_ref, hir::Mutability::Not), value_hir_id, ident, sub_pat) =
pat.kind
&& by_ref != hir::ByRef::Yes(hir::Mutability::Mut)
&& !matches!(by_ref, hir::ByRef::Yes(_, hir::Mutability::Mut))
{
// This block catches bindings with sub patterns. It would be hard to build a correct suggestion
// for them and it's likely that the user knows what they are doing in such a case.

View file

@ -63,7 +63,7 @@ fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<Mutability> {
.qpath_res(qpath, arm.pat.hir_id)
.ctor_parent(cx)
.is_lang_item(cx, LangItem::OptionSome)
&& let PatKind::Binding(BindingMode(ByRef::Yes(mutabl), _), .., ident, _) = first_pat.kind
&& let PatKind::Binding(BindingMode(ByRef::Yes(_, mutabl), _), .., ident, _) = first_pat.kind
&& let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind
&& e.res(cx).ctor_parent(cx).is_lang_item(cx, LangItem::OptionSome)
&& let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind

View file

@ -172,7 +172,7 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
},
)),
) => {
return !matches!(annot, BindingMode(ByRef::Yes(_), _)) && pat_ident.name == first_seg.ident.name;
return !matches!(annot, BindingMode(ByRef::Yes(..), _)) && pat_ident.name == first_seg.ident.name;
},
// Example: `Custom::TypeA => Custom::TypeB`, or `None => None`
(

View file

@ -176,7 +176,7 @@ fn get_pat_binding<'tcx>(
if let PatKind::Binding(bind_annot, hir_id, ident, _) = pat.kind
&& hir_id == local
{
if matches!(bind_annot.0, rustc_ast::ByRef::Yes(_)) {
if matches!(bind_annot.0, rustc_ast::ByRef::Yes(..)) {
let _ = byref_ident.insert(ident);
}
// the second call of `replace()` returns a `Some(span)`, meaning a multi-binding pattern

View file

@ -56,7 +56,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>)
_ => false,
},
// local binding capturing a reference
Node::LetStmt(l) if matches!(l.pat.kind, PatKind::Binding(BindingMode(ByRef::Yes(_), _), ..)) => {
Node::LetStmt(l) if matches!(l.pat.kind, PatKind::Binding(BindingMode(ByRef::Yes(..), _), ..)) => {
return;
},
_ => false,

View file

@ -150,7 +150,7 @@ fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
let init_expr_str = Sugg::hir_with_applicability(cx, init_expr, "..", &mut applicability).maybe_paren();
// Take care when binding is `ref`
let sugg = if let PatKind::Binding(
BindingMode(ByRef::Yes(ref_mutability), binding_mutability),
BindingMode(ByRef::Yes(_,ref_mutability), binding_mutability),
_hir_id,
ident,
subpattern,
@ -169,7 +169,7 @@ fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
// Handle subpattern (@ subpattern)
let maybe_subpattern = match subpattern {
Some(Pat {
kind: PatKind::Binding(BindingMode(ByRef::Yes(_), _), _, subident, None),
kind: PatKind::Binding(BindingMode(ByRef::Yes(..), _), _, subident, None),
..
}) => {
// avoid `&ref`
@ -504,8 +504,8 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
let requires_semi = matches!(cx.tcx.parent_hir_node(expr.hir_id), Node::Stmt(_));
let method_call_str = match by_ref {
ByRef::Yes(Mutability::Mut) => ".as_mut()",
ByRef::Yes(Mutability::Not) => ".as_ref()",
ByRef::Yes(_, Mutability::Mut) => ".as_mut()",
ByRef::Yes(_, Mutability::Not) => ".as_ref()",
ByRef::No => "",
};
let sugg = format!(

View file

@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for ToplevelRefArg {
) {
if !matches!(k, FnKind::Closure) {
for arg in iter_input_pats(decl, body) {
if let PatKind::Binding(BindingMode(ByRef::Yes(_), _), ..) = arg.pat.kind
if let PatKind::Binding(BindingMode(ByRef::Yes(..), _), ..) = arg.pat.kind
&& is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id)
&& !arg.span.in_external_macro(cx.tcx.sess.source_map())
{
@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for ToplevelRefArg {
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
if let StmtKind::Let(local) = stmt.kind
&& let PatKind::Binding(BindingMode(ByRef::Yes(mutabl), _), .., name, None) = local.pat.kind
&& let PatKind::Binding(BindingMode(ByRef::Yes(_, mutabl), _), .., name, None) = local.pat.kind
&& let Some(init) = local.init
// Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue.
&& is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id)

View file

@ -745,10 +745,14 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
let ann = match ann {
BindingMode::NONE => "NONE",
BindingMode::REF => "REF",
BindingMode::REF_PIN => "REF_PIN",
BindingMode::MUT => "MUT",
BindingMode::REF_MUT => "REF_MUT",
BindingMode::REF_PIN_MUT => "REF_PIN_MUT",
BindingMode::MUT_REF => "MUT_REF",
BindingMode::MUT_REF_PIN => "MUT_REF_PIN",
BindingMode::MUT_REF_MUT => "MUT_REF_MUT",
BindingMode::MUT_REF_PIN_MUT => "MUT_REF_PIN_MUT",
};
kind!("Binding(BindingMode::{ann}, _, {name}, {sub})");
self.ident(name);

View file

@ -212,7 +212,12 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
// Custom `Deref` impl might have side effects
ExprKind::Unary(UnOp::Deref, e)
if self.cx.typeck_results().expr_ty(e).builtin_deref(true).is_none() =>
if self
.cx
.typeck_results()
.expr_ty(e)
.builtin_deref(true)
.is_none() =>
{
self.eagerness |= NoChange;
},

View file

@ -783,7 +783,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind {
ByRef::No if !is_copy(cx, cx.typeck_results().node_type(id)) => {
capture = CaptureKind::Value;
},
ByRef::Yes(Mutability::Mut) if capture != CaptureKind::Value => {
ByRef::Yes(_, Mutability::Mut) if capture != CaptureKind::Value => {
capture = CaptureKind::Ref(Mutability::Mut);
},
_ => (),
@ -1831,7 +1831,7 @@ pub fn is_expr_identity_of_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr<
.typeck_results()
.pat_binding_modes()
.get(pat.hir_id)
.is_some_and(|mode| matches!(mode.0, ByRef::Yes(_)))
.is_some_and(|mode| matches!(mode.0, ByRef::Yes(..)))
{
// If the parameter is `(x, y)` of type `&(T, T)`, or `[x, y]` of type `&[T; 2]`, then
// due to match ergonomics, the inner patterns become references. Don't consider this

View file

@ -134,7 +134,8 @@ impl Rewrite for Pat {
let mut_prefix = format_mutability(mutability).trim();
let (ref_kw, mut_infix) = match by_ref {
ByRef::Yes(rmutbl) => ("ref", format_mutability(rmutbl).trim()),
// FIXME(pin_ergonomics): format the pinnedness
ByRef::Yes(_, rmutbl) => ("ref", format_mutability(rmutbl).trim()),
ByRef::No => ("", ""),
};
let id_str = rewrite_ident(context, ident);

View file

@ -0,0 +1,33 @@
// MIR for `bar_const` after built
fn bar_const(_1: Pin<&Bar<T, U>>) -> () {
debug bar => _1;
let mut _0: ();
let _2: std::pin::Pin<&T>;
let _3: std::pin::Pin<&U>;
let mut _4: &T;
let mut _5: &U;
scope 1 {
debug x => _2;
debug y => _3;
}
bb0: {
PlaceMention(_1);
StorageLive(_2);
_4 = &((*(_1.0: &Bar<T, U>)).0: T);
_2 = Pin::<&T> { pointer: move _4 };
StorageLive(_3);
_5 = &((*(_1.0: &Bar<T, U>)).1: U);
_3 = Pin::<&U> { pointer: move _5 };
_0 = const ();
StorageDead(_3);
StorageDead(_2);
return;
}
bb1: {
FakeRead(ForMatchedPlace(None), _1);
unreachable;
}
}

View file

@ -0,0 +1,33 @@
// MIR for `bar_mut` after built
fn bar_mut(_1: Pin<&mut Bar<T, U>>) -> () {
debug bar => _1;
let mut _0: ();
let _2: std::pin::Pin<&mut T>;
let _3: std::pin::Pin<&mut U>;
let mut _4: &mut T;
let mut _5: &mut U;
scope 1 {
debug x => _2;
debug y => _3;
}
bb0: {
PlaceMention(_1);
StorageLive(_2);
_4 = &mut ((*(_1.0: &mut Bar<T, U>)).0: T);
_2 = Pin::<&mut T> { pointer: move _4 };
StorageLive(_3);
_5 = &mut ((*(_1.0: &mut Bar<T, U>)).1: U);
_3 = Pin::<&mut U> { pointer: move _5 };
_0 = const ();
StorageDead(_3);
StorageDead(_2);
return;
}
bb1: {
FakeRead(ForMatchedPlace(None), _1);
unreachable;
}
}

View file

@ -0,0 +1,422 @@
// MIR for `baz_baz_const` after built
fn baz_baz_const(_1: Pin<&Baz<Baz<T, U>, Baz<T, U>>>) -> () {
debug baz => _1;
let mut _0: ();
let mut _2: isize;
let mut _3: isize;
let mut _4: isize;
let mut _5: isize;
let mut _6: isize;
let mut _7: isize;
let mut _8: isize;
let _9: std::pin::Pin<&T>;
let _10: std::pin::Pin<&U>;
let _11: std::pin::Pin<&T>;
let _12: std::pin::Pin<&U>;
let mut _13: &T;
let mut _14: &U;
let mut _15: &T;
let mut _16: &U;
let _17: std::pin::Pin<&T>;
let _18: std::pin::Pin<&U>;
let _19: std::pin::Pin<&T>;
let _20: std::pin::Pin<&U>;
let mut _21: &T;
let mut _22: &U;
let mut _23: &T;
let mut _24: &U;
let _25: std::pin::Pin<&T>;
let _26: std::pin::Pin<&U>;
let _27: std::pin::Pin<&T>;
let _28: std::pin::Pin<&U>;
let mut _29: &T;
let mut _30: &U;
let mut _31: &T;
let mut _32: &U;
let _33: std::pin::Pin<&T>;
let _34: std::pin::Pin<&U>;
let _35: std::pin::Pin<&T>;
let _36: std::pin::Pin<&U>;
let mut _37: &T;
let mut _38: &U;
let mut _39: &T;
let mut _40: &U;
let _41: std::pin::Pin<&T>;
let _42: std::pin::Pin<&U>;
let _43: std::pin::Pin<&T>;
let _44: std::pin::Pin<&U>;
let mut _45: &T;
let mut _46: &U;
let mut _47: &T;
let mut _48: &U;
let _49: std::pin::Pin<&T>;
let _50: std::pin::Pin<&U>;
let _51: std::pin::Pin<&T>;
let _52: std::pin::Pin<&U>;
let mut _53: &T;
let mut _54: &U;
let mut _55: &T;
let mut _56: &U;
let _57: std::pin::Pin<&T>;
let _58: std::pin::Pin<&U>;
let _59: std::pin::Pin<&T>;
let _60: std::pin::Pin<&U>;
let mut _61: &T;
let mut _62: &U;
let mut _63: &T;
let mut _64: &U;
let _65: std::pin::Pin<&T>;
let _66: std::pin::Pin<&U>;
let _67: std::pin::Pin<&T>;
let _68: std::pin::Pin<&U>;
let mut _69: &T;
let mut _70: &U;
let mut _71: &T;
let mut _72: &U;
scope 1 {
debug x => _9;
debug y => _10;
debug z => _11;
debug w => _12;
}
scope 2 {
debug x => _17;
debug y => _18;
debug z => _19;
debug w => _20;
}
scope 3 {
debug x => _25;
debug y => _26;
debug z => _27;
debug w => _28;
}
scope 4 {
debug x => _33;
debug y => _34;
debug z => _35;
debug w => _36;
}
scope 5 {
debug x => _41;
debug y => _42;
debug z => _43;
debug w => _44;
}
scope 6 {
debug x => _49;
debug y => _50;
debug z => _51;
debug w => _52;
}
scope 7 {
debug x => _57;
debug y => _58;
debug z => _59;
debug w => _60;
}
scope 8 {
debug x => _65;
debug y => _66;
debug z => _67;
debug w => _68;
}
bb0: {
PlaceMention(_1);
_8 = discriminant((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)));
switchInt(move _8) -> [0: bb2, 1: bb16, otherwise: bb1];
}
bb1: {
FakeRead(ForMatchedPlace(None), _1);
unreachable;
}
bb2: {
_4 = discriminant((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>));
switchInt(move _4) -> [0: bb4, 1: bb10, otherwise: bb3];
}
bb3: {
goto -> bb1;
}
bb4: {
_2 = discriminant((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>));
switchInt(move _2) -> [0: bb6, 1: bb8, otherwise: bb5];
}
bb5: {
goto -> bb3;
}
bb6: {
falseEdge -> [real: bb36, imaginary: bb8];
}
bb7: {
goto -> bb5;
}
bb8: {
falseEdge -> [real: bb35, imaginary: bb10];
}
bb9: {
goto -> bb5;
}
bb10: {
_3 = discriminant((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>));
switchInt(move _3) -> [0: bb12, 1: bb14, otherwise: bb11];
}
bb11: {
goto -> bb3;
}
bb12: {
falseEdge -> [real: bb34, imaginary: bb14];
}
bb13: {
goto -> bb11;
}
bb14: {
falseEdge -> [real: bb33, imaginary: bb16];
}
bb15: {
goto -> bb11;
}
bb16: {
_7 = discriminant((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>));
switchInt(move _7) -> [0: bb18, 1: bb24, otherwise: bb17];
}
bb17: {
goto -> bb1;
}
bb18: {
_5 = discriminant((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>));
switchInt(move _5) -> [0: bb20, 1: bb22, otherwise: bb19];
}
bb19: {
goto -> bb17;
}
bb20: {
falseEdge -> [real: bb32, imaginary: bb22];
}
bb21: {
goto -> bb19;
}
bb22: {
falseEdge -> [real: bb31, imaginary: bb24];
}
bb23: {
goto -> bb19;
}
bb24: {
_6 = discriminant((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>));
switchInt(move _6) -> [0: bb26, 1: bb28, otherwise: bb25];
}
bb25: {
goto -> bb17;
}
bb26: {
falseEdge -> [real: bb30, imaginary: bb28];
}
bb27: {
goto -> bb25;
}
bb28: {
StorageLive(_65);
_69 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Bar).0: T);
_65 = Pin::<&T> { pointer: move _69 };
StorageLive(_66);
_70 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Bar).1: U);
_66 = Pin::<&U> { pointer: move _70 };
StorageLive(_67);
_71 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Bar).0: T);
_67 = Pin::<&T> { pointer: move _71 };
StorageLive(_68);
_72 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Bar).1: U);
_68 = Pin::<&U> { pointer: move _72 };
_0 = const ();
StorageDead(_68);
StorageDead(_67);
StorageDead(_66);
StorageDead(_65);
goto -> bb37;
}
bb29: {
goto -> bb25;
}
bb30: {
StorageLive(_57);
_61 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Bar).0: T);
_57 = Pin::<&T> { pointer: move _61 };
StorageLive(_58);
_62 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Bar).1: U);
_58 = Pin::<&U> { pointer: move _62 };
StorageLive(_59);
_63 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Foo).0: T);
_59 = Pin::<&T> { pointer: move _63 };
StorageLive(_60);
_64 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Foo).1: U);
_60 = Pin::<&U> { pointer: move _64 };
_0 = const ();
StorageDead(_60);
StorageDead(_59);
StorageDead(_58);
StorageDead(_57);
goto -> bb37;
}
bb31: {
StorageLive(_49);
_53 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Foo).0: T);
_49 = Pin::<&T> { pointer: move _53 };
StorageLive(_50);
_54 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Foo).1: U);
_50 = Pin::<&U> { pointer: move _54 };
StorageLive(_51);
_55 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Bar).0: T);
_51 = Pin::<&T> { pointer: move _55 };
StorageLive(_52);
_56 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Bar).1: U);
_52 = Pin::<&U> { pointer: move _56 };
_0 = const ();
StorageDead(_52);
StorageDead(_51);
StorageDead(_50);
StorageDead(_49);
goto -> bb37;
}
bb32: {
StorageLive(_41);
_45 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Foo).0: T);
_41 = Pin::<&T> { pointer: move _45 };
StorageLive(_42);
_46 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Foo).1: U);
_42 = Pin::<&U> { pointer: move _46 };
StorageLive(_43);
_47 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Foo).0: T);
_43 = Pin::<&T> { pointer: move _47 };
StorageLive(_44);
_48 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Foo).1: U);
_44 = Pin::<&U> { pointer: move _48 };
_0 = const ();
StorageDead(_44);
StorageDead(_43);
StorageDead(_42);
StorageDead(_41);
goto -> bb37;
}
bb33: {
StorageLive(_33);
_37 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Bar).0: T);
_33 = Pin::<&T> { pointer: move _37 };
StorageLive(_34);
_38 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Bar).1: U);
_34 = Pin::<&U> { pointer: move _38 };
StorageLive(_35);
_39 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Bar).0: T);
_35 = Pin::<&T> { pointer: move _39 };
StorageLive(_36);
_40 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Bar).1: U);
_36 = Pin::<&U> { pointer: move _40 };
_0 = const ();
StorageDead(_36);
StorageDead(_35);
StorageDead(_34);
StorageDead(_33);
goto -> bb37;
}
bb34: {
StorageLive(_25);
_29 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Bar).0: T);
_25 = Pin::<&T> { pointer: move _29 };
StorageLive(_26);
_30 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Bar).1: U);
_26 = Pin::<&U> { pointer: move _30 };
StorageLive(_27);
_31 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Foo).0: T);
_27 = Pin::<&T> { pointer: move _31 };
StorageLive(_28);
_32 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Foo).1: U);
_28 = Pin::<&U> { pointer: move _32 };
_0 = const ();
StorageDead(_28);
StorageDead(_27);
StorageDead(_26);
StorageDead(_25);
goto -> bb37;
}
bb35: {
StorageLive(_17);
_21 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Foo).0: T);
_17 = Pin::<&T> { pointer: move _21 };
StorageLive(_18);
_22 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Foo).1: U);
_18 = Pin::<&U> { pointer: move _22 };
StorageLive(_19);
_23 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Bar).0: T);
_19 = Pin::<&T> { pointer: move _23 };
StorageLive(_20);
_24 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Bar).1: U);
_20 = Pin::<&U> { pointer: move _24 };
_0 = const ();
StorageDead(_20);
StorageDead(_19);
StorageDead(_18);
StorageDead(_17);
goto -> bb37;
}
bb36: {
StorageLive(_9);
_13 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Foo).0: T);
_9 = Pin::<&T> { pointer: move _13 };
StorageLive(_10);
_14 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Foo).1: U);
_10 = Pin::<&U> { pointer: move _14 };
StorageLive(_11);
_15 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Foo).0: T);
_11 = Pin::<&T> { pointer: move _15 };
StorageLive(_12);
_16 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Foo).1: U);
_12 = Pin::<&U> { pointer: move _16 };
_0 = const ();
StorageDead(_12);
StorageDead(_11);
StorageDead(_10);
StorageDead(_9);
goto -> bb37;
}
bb37: {
return;
}
}

View file

@ -0,0 +1,422 @@
// MIR for `baz_baz_mut` after built
fn baz_baz_mut(_1: Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>) -> () {
debug baz => _1;
let mut _0: ();
let mut _2: isize;
let mut _3: isize;
let mut _4: isize;
let mut _5: isize;
let mut _6: isize;
let mut _7: isize;
let mut _8: isize;
let _9: std::pin::Pin<&mut T>;
let _10: std::pin::Pin<&mut U>;
let _11: std::pin::Pin<&mut T>;
let _12: std::pin::Pin<&mut U>;
let mut _13: &mut T;
let mut _14: &mut U;
let mut _15: &mut T;
let mut _16: &mut U;
let _17: std::pin::Pin<&mut T>;
let _18: std::pin::Pin<&mut U>;
let _19: std::pin::Pin<&mut T>;
let _20: std::pin::Pin<&mut U>;
let mut _21: &mut T;
let mut _22: &mut U;
let mut _23: &mut T;
let mut _24: &mut U;
let _25: std::pin::Pin<&mut T>;
let _26: std::pin::Pin<&mut U>;
let _27: std::pin::Pin<&mut T>;
let _28: std::pin::Pin<&mut U>;
let mut _29: &mut T;
let mut _30: &mut U;
let mut _31: &mut T;
let mut _32: &mut U;
let _33: std::pin::Pin<&mut T>;
let _34: std::pin::Pin<&mut U>;
let _35: std::pin::Pin<&mut T>;
let _36: std::pin::Pin<&mut U>;
let mut _37: &mut T;
let mut _38: &mut U;
let mut _39: &mut T;
let mut _40: &mut U;
let _41: std::pin::Pin<&mut T>;
let _42: std::pin::Pin<&mut U>;
let _43: std::pin::Pin<&mut T>;
let _44: std::pin::Pin<&mut U>;
let mut _45: &mut T;
let mut _46: &mut U;
let mut _47: &mut T;
let mut _48: &mut U;
let _49: std::pin::Pin<&mut T>;
let _50: std::pin::Pin<&mut U>;
let _51: std::pin::Pin<&mut T>;
let _52: std::pin::Pin<&mut U>;
let mut _53: &mut T;
let mut _54: &mut U;
let mut _55: &mut T;
let mut _56: &mut U;
let _57: std::pin::Pin<&mut T>;
let _58: std::pin::Pin<&mut U>;
let _59: std::pin::Pin<&mut T>;
let _60: std::pin::Pin<&mut U>;
let mut _61: &mut T;
let mut _62: &mut U;
let mut _63: &mut T;
let mut _64: &mut U;
let _65: std::pin::Pin<&mut T>;
let _66: std::pin::Pin<&mut U>;
let _67: std::pin::Pin<&mut T>;
let _68: std::pin::Pin<&mut U>;
let mut _69: &mut T;
let mut _70: &mut U;
let mut _71: &mut T;
let mut _72: &mut U;
scope 1 {
debug x => _9;
debug y => _10;
debug z => _11;
debug w => _12;
}
scope 2 {
debug x => _17;
debug y => _18;
debug z => _19;
debug w => _20;
}
scope 3 {
debug x => _25;
debug y => _26;
debug z => _27;
debug w => _28;
}
scope 4 {
debug x => _33;
debug y => _34;
debug z => _35;
debug w => _36;
}
scope 5 {
debug x => _41;
debug y => _42;
debug z => _43;
debug w => _44;
}
scope 6 {
debug x => _49;
debug y => _50;
debug z => _51;
debug w => _52;
}
scope 7 {
debug x => _57;
debug y => _58;
debug z => _59;
debug w => _60;
}
scope 8 {
debug x => _65;
debug y => _66;
debug z => _67;
debug w => _68;
}
bb0: {
PlaceMention(_1);
_8 = discriminant((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)));
switchInt(move _8) -> [0: bb2, 1: bb16, otherwise: bb1];
}
bb1: {
FakeRead(ForMatchedPlace(None), _1);
unreachable;
}
bb2: {
_4 = discriminant((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>));
switchInt(move _4) -> [0: bb4, 1: bb10, otherwise: bb3];
}
bb3: {
goto -> bb1;
}
bb4: {
_2 = discriminant((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>));
switchInt(move _2) -> [0: bb6, 1: bb8, otherwise: bb5];
}
bb5: {
goto -> bb3;
}
bb6: {
falseEdge -> [real: bb36, imaginary: bb8];
}
bb7: {
goto -> bb5;
}
bb8: {
falseEdge -> [real: bb35, imaginary: bb10];
}
bb9: {
goto -> bb5;
}
bb10: {
_3 = discriminant((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>));
switchInt(move _3) -> [0: bb12, 1: bb14, otherwise: bb11];
}
bb11: {
goto -> bb3;
}
bb12: {
falseEdge -> [real: bb34, imaginary: bb14];
}
bb13: {
goto -> bb11;
}
bb14: {
falseEdge -> [real: bb33, imaginary: bb16];
}
bb15: {
goto -> bb11;
}
bb16: {
_7 = discriminant((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>));
switchInt(move _7) -> [0: bb18, 1: bb24, otherwise: bb17];
}
bb17: {
goto -> bb1;
}
bb18: {
_5 = discriminant((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>));
switchInt(move _5) -> [0: bb20, 1: bb22, otherwise: bb19];
}
bb19: {
goto -> bb17;
}
bb20: {
falseEdge -> [real: bb32, imaginary: bb22];
}
bb21: {
goto -> bb19;
}
bb22: {
falseEdge -> [real: bb31, imaginary: bb24];
}
bb23: {
goto -> bb19;
}
bb24: {
_6 = discriminant((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>));
switchInt(move _6) -> [0: bb26, 1: bb28, otherwise: bb25];
}
bb25: {
goto -> bb17;
}
bb26: {
falseEdge -> [real: bb30, imaginary: bb28];
}
bb27: {
goto -> bb25;
}
bb28: {
StorageLive(_65);
_69 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Bar).0: T);
_65 = Pin::<&mut T> { pointer: move _69 };
StorageLive(_66);
_70 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Bar).1: U);
_66 = Pin::<&mut U> { pointer: move _70 };
StorageLive(_67);
_71 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Bar).0: T);
_67 = Pin::<&mut T> { pointer: move _71 };
StorageLive(_68);
_72 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Bar).1: U);
_68 = Pin::<&mut U> { pointer: move _72 };
_0 = const ();
StorageDead(_68);
StorageDead(_67);
StorageDead(_66);
StorageDead(_65);
goto -> bb37;
}
bb29: {
goto -> bb25;
}
bb30: {
StorageLive(_57);
_61 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Bar).0: T);
_57 = Pin::<&mut T> { pointer: move _61 };
StorageLive(_58);
_62 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Bar).1: U);
_58 = Pin::<&mut U> { pointer: move _62 };
StorageLive(_59);
_63 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Foo).0: T);
_59 = Pin::<&mut T> { pointer: move _63 };
StorageLive(_60);
_64 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Foo).1: U);
_60 = Pin::<&mut U> { pointer: move _64 };
_0 = const ();
StorageDead(_60);
StorageDead(_59);
StorageDead(_58);
StorageDead(_57);
goto -> bb37;
}
bb31: {
StorageLive(_49);
_53 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Foo).0: T);
_49 = Pin::<&mut T> { pointer: move _53 };
StorageLive(_50);
_54 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Foo).1: U);
_50 = Pin::<&mut U> { pointer: move _54 };
StorageLive(_51);
_55 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Bar).0: T);
_51 = Pin::<&mut T> { pointer: move _55 };
StorageLive(_52);
_56 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Bar).1: U);
_52 = Pin::<&mut U> { pointer: move _56 };
_0 = const ();
StorageDead(_52);
StorageDead(_51);
StorageDead(_50);
StorageDead(_49);
goto -> bb37;
}
bb32: {
StorageLive(_41);
_45 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Foo).0: T);
_41 = Pin::<&mut T> { pointer: move _45 };
StorageLive(_42);
_46 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Foo).1: U);
_42 = Pin::<&mut U> { pointer: move _46 };
StorageLive(_43);
_47 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Foo).0: T);
_43 = Pin::<&mut T> { pointer: move _47 };
StorageLive(_44);
_48 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Foo).1: U);
_44 = Pin::<&mut U> { pointer: move _48 };
_0 = const ();
StorageDead(_44);
StorageDead(_43);
StorageDead(_42);
StorageDead(_41);
goto -> bb37;
}
bb33: {
StorageLive(_33);
_37 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Bar).0: T);
_33 = Pin::<&mut T> { pointer: move _37 };
StorageLive(_34);
_38 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Bar).1: U);
_34 = Pin::<&mut U> { pointer: move _38 };
StorageLive(_35);
_39 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Bar).0: T);
_35 = Pin::<&mut T> { pointer: move _39 };
StorageLive(_36);
_40 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Bar).1: U);
_36 = Pin::<&mut U> { pointer: move _40 };
_0 = const ();
StorageDead(_36);
StorageDead(_35);
StorageDead(_34);
StorageDead(_33);
goto -> bb37;
}
bb34: {
StorageLive(_25);
_29 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Bar).0: T);
_25 = Pin::<&mut T> { pointer: move _29 };
StorageLive(_26);
_30 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Bar).1: U);
_26 = Pin::<&mut U> { pointer: move _30 };
StorageLive(_27);
_31 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Foo).0: T);
_27 = Pin::<&mut T> { pointer: move _31 };
StorageLive(_28);
_32 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Foo).1: U);
_28 = Pin::<&mut U> { pointer: move _32 };
_0 = const ();
StorageDead(_28);
StorageDead(_27);
StorageDead(_26);
StorageDead(_25);
goto -> bb37;
}
bb35: {
StorageLive(_17);
_21 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Foo).0: T);
_17 = Pin::<&mut T> { pointer: move _21 };
StorageLive(_18);
_22 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Foo).1: U);
_18 = Pin::<&mut U> { pointer: move _22 };
StorageLive(_19);
_23 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Bar).0: T);
_19 = Pin::<&mut T> { pointer: move _23 };
StorageLive(_20);
_24 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Bar).1: U);
_20 = Pin::<&mut U> { pointer: move _24 };
_0 = const ();
StorageDead(_20);
StorageDead(_19);
StorageDead(_18);
StorageDead(_17);
goto -> bb37;
}
bb36: {
StorageLive(_9);
_13 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Foo).0: T);
_9 = Pin::<&mut T> { pointer: move _13 };
StorageLive(_10);
_14 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Foo).1: U);
_10 = Pin::<&mut U> { pointer: move _14 };
StorageLive(_11);
_15 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Foo).0: T);
_11 = Pin::<&mut T> { pointer: move _15 };
StorageLive(_12);
_16 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Foo).1: U);
_12 = Pin::<&mut U> { pointer: move _16 };
_0 = const ();
StorageDead(_12);
StorageDead(_11);
StorageDead(_10);
StorageDead(_9);
goto -> bb37;
}
bb37: {
return;
}
}

View file

@ -0,0 +1,76 @@
// MIR for `baz_const` after built
fn baz_const(_1: Pin<&Baz<T, U>>) -> () {
debug baz => _1;
let mut _0: ();
let mut _2: isize;
let _3: std::pin::Pin<&T>;
let _4: std::pin::Pin<&U>;
let mut _5: &T;
let mut _6: &U;
let _7: std::pin::Pin<&T>;
let _8: std::pin::Pin<&U>;
let mut _9: &T;
let mut _10: &U;
scope 1 {
debug x => _3;
debug y => _4;
}
scope 2 {
debug x => _7;
debug y => _8;
}
bb0: {
PlaceMention(_1);
_2 = discriminant((*(_1.0: &Baz<T, U>)));
switchInt(move _2) -> [0: bb2, 1: bb4, otherwise: bb1];
}
bb1: {
FakeRead(ForMatchedPlace(None), _1);
unreachable;
}
bb2: {
falseEdge -> [real: bb6, imaginary: bb4];
}
bb3: {
goto -> bb1;
}
bb4: {
StorageLive(_7);
_9 = &(((*(_1.0: &Baz<T, U>)) as Bar).0: T);
_7 = Pin::<&T> { pointer: move _9 };
StorageLive(_8);
_10 = &(((*(_1.0: &Baz<T, U>)) as Bar).1: U);
_8 = Pin::<&U> { pointer: move _10 };
_0 = const ();
StorageDead(_8);
StorageDead(_7);
goto -> bb7;
}
bb5: {
goto -> bb1;
}
bb6: {
StorageLive(_3);
_5 = &(((*(_1.0: &Baz<T, U>)) as Foo).0: T);
_3 = Pin::<&T> { pointer: move _5 };
StorageLive(_4);
_6 = &(((*(_1.0: &Baz<T, U>)) as Foo).1: U);
_4 = Pin::<&U> { pointer: move _6 };
_0 = const ();
StorageDead(_4);
StorageDead(_3);
goto -> bb7;
}
bb7: {
return;
}
}

View file

@ -0,0 +1,76 @@
// MIR for `baz_mut` after built
fn baz_mut(_1: Pin<&mut Baz<T, U>>) -> () {
debug baz => _1;
let mut _0: ();
let mut _2: isize;
let _3: std::pin::Pin<&mut T>;
let _4: std::pin::Pin<&mut U>;
let mut _5: &mut T;
let mut _6: &mut U;
let _7: std::pin::Pin<&mut T>;
let _8: std::pin::Pin<&mut U>;
let mut _9: &mut T;
let mut _10: &mut U;
scope 1 {
debug x => _3;
debug y => _4;
}
scope 2 {
debug x => _7;
debug y => _8;
}
bb0: {
PlaceMention(_1);
_2 = discriminant((*(_1.0: &mut Baz<T, U>)));
switchInt(move _2) -> [0: bb2, 1: bb4, otherwise: bb1];
}
bb1: {
FakeRead(ForMatchedPlace(None), _1);
unreachable;
}
bb2: {
falseEdge -> [real: bb6, imaginary: bb4];
}
bb3: {
goto -> bb1;
}
bb4: {
StorageLive(_7);
_9 = &mut (((*(_1.0: &mut Baz<T, U>)) as Bar).0: T);
_7 = Pin::<&mut T> { pointer: move _9 };
StorageLive(_8);
_10 = &mut (((*(_1.0: &mut Baz<T, U>)) as Bar).1: U);
_8 = Pin::<&mut U> { pointer: move _10 };
_0 = const ();
StorageDead(_8);
StorageDead(_7);
goto -> bb7;
}
bb5: {
goto -> bb1;
}
bb6: {
StorageLive(_3);
_5 = &mut (((*(_1.0: &mut Baz<T, U>)) as Foo).0: T);
_3 = Pin::<&mut T> { pointer: move _5 };
StorageLive(_4);
_6 = &mut (((*(_1.0: &mut Baz<T, U>)) as Foo).1: U);
_4 = Pin::<&mut U> { pointer: move _6 };
_0 = const ();
StorageDead(_4);
StorageDead(_3);
goto -> bb7;
}
bb7: {
return;
}
}

View file

@ -0,0 +1,47 @@
// MIR for `foo_bar_const` after built
fn foo_bar_const(_1: Pin<&Foo<Bar<T, U>, Bar<T, U>>>) -> () {
debug foo => _1;
let mut _0: ();
let _2: std::pin::Pin<&T>;
let _3: std::pin::Pin<&U>;
let _4: std::pin::Pin<&T>;
let _5: std::pin::Pin<&U>;
let mut _6: &T;
let mut _7: &U;
let mut _8: &T;
let mut _9: &U;
scope 1 {
debug x => _2;
debug y => _3;
debug z => _4;
debug w => _5;
}
bb0: {
PlaceMention(_1);
StorageLive(_2);
_6 = &(((*(_1.0: &Foo<Bar<T, U>, Bar<T, U>>)).0: Bar<T, U>).0: T);
_2 = Pin::<&T> { pointer: move _6 };
StorageLive(_3);
_7 = &(((*(_1.0: &Foo<Bar<T, U>, Bar<T, U>>)).0: Bar<T, U>).1: U);
_3 = Pin::<&U> { pointer: move _7 };
StorageLive(_4);
_8 = &(((*(_1.0: &Foo<Bar<T, U>, Bar<T, U>>)).1: Bar<T, U>).0: T);
_4 = Pin::<&T> { pointer: move _8 };
StorageLive(_5);
_9 = &(((*(_1.0: &Foo<Bar<T, U>, Bar<T, U>>)).1: Bar<T, U>).1: U);
_5 = Pin::<&U> { pointer: move _9 };
_0 = const ();
StorageDead(_5);
StorageDead(_4);
StorageDead(_3);
StorageDead(_2);
return;
}
bb1: {
FakeRead(ForMatchedPlace(None), _1);
unreachable;
}
}

View file

@ -0,0 +1,47 @@
// MIR for `foo_bar_mut` after built
fn foo_bar_mut(_1: Pin<&mut Foo<Bar<T, U>, Bar<T, U>>>) -> () {
debug foo => _1;
let mut _0: ();
let _2: std::pin::Pin<&mut T>;
let _3: std::pin::Pin<&mut U>;
let _4: std::pin::Pin<&mut T>;
let _5: std::pin::Pin<&mut U>;
let mut _6: &mut T;
let mut _7: &mut U;
let mut _8: &mut T;
let mut _9: &mut U;
scope 1 {
debug x => _2;
debug y => _3;
debug z => _4;
debug w => _5;
}
bb0: {
PlaceMention(_1);
StorageLive(_2);
_6 = &mut (((*(_1.0: &mut Foo<Bar<T, U>, Bar<T, U>>)).0: Bar<T, U>).0: T);
_2 = Pin::<&mut T> { pointer: move _6 };
StorageLive(_3);
_7 = &mut (((*(_1.0: &mut Foo<Bar<T, U>, Bar<T, U>>)).0: Bar<T, U>).1: U);
_3 = Pin::<&mut U> { pointer: move _7 };
StorageLive(_4);
_8 = &mut (((*(_1.0: &mut Foo<Bar<T, U>, Bar<T, U>>)).1: Bar<T, U>).0: T);
_4 = Pin::<&mut T> { pointer: move _8 };
StorageLive(_5);
_9 = &mut (((*(_1.0: &mut Foo<Bar<T, U>, Bar<T, U>>)).1: Bar<T, U>).1: U);
_5 = Pin::<&mut U> { pointer: move _9 };
_0 = const ();
StorageDead(_5);
StorageDead(_4);
StorageDead(_3);
StorageDead(_2);
return;
}
bb1: {
FakeRead(ForMatchedPlace(None), _1);
unreachable;
}
}

View file

@ -0,0 +1,33 @@
// MIR for `foo_const` after built
fn foo_const(_1: Pin<&Foo<T, U>>) -> () {
debug foo => _1;
let mut _0: ();
let _2: std::pin::Pin<&T>;
let _3: std::pin::Pin<&U>;
let mut _4: &T;
let mut _5: &U;
scope 1 {
debug x => _2;
debug y => _3;
}
bb0: {
PlaceMention(_1);
StorageLive(_2);
_4 = &((*(_1.0: &Foo<T, U>)).0: T);
_2 = Pin::<&T> { pointer: move _4 };
StorageLive(_3);
_5 = &((*(_1.0: &Foo<T, U>)).1: U);
_3 = Pin::<&U> { pointer: move _5 };
_0 = const ();
StorageDead(_3);
StorageDead(_2);
return;
}
bb1: {
FakeRead(ForMatchedPlace(None), _1);
unreachable;
}
}

View file

@ -0,0 +1,33 @@
// MIR for `foo_mut` after built
fn foo_mut(_1: Pin<&mut Foo<T, U>>) -> () {
debug foo => _1;
let mut _0: ();
let _2: std::pin::Pin<&mut T>;
let _3: std::pin::Pin<&mut U>;
let mut _4: &mut T;
let mut _5: &mut U;
scope 1 {
debug x => _2;
debug y => _3;
}
bb0: {
PlaceMention(_1);
StorageLive(_2);
_4 = &mut ((*(_1.0: &mut Foo<T, U>)).0: T);
_2 = Pin::<&mut T> { pointer: move _4 };
StorageLive(_3);
_5 = &mut ((*(_1.0: &mut Foo<T, U>)).1: U);
_3 = Pin::<&mut U> { pointer: move _5 };
_0 = const ();
StorageDead(_3);
StorageDead(_2);
return;
}
bb1: {
FakeRead(ForMatchedPlace(None), _1);
unreachable;
}
}

View file

@ -0,0 +1,95 @@
// skip-filecheck
#![feature(pin_ergonomics)]
#![allow(incomplete_features)]
// This test verifies that a `&pin mut Foo` can be projected to a pinned
// reference `&pin mut T` of a `?Unpin` field , and can be projected to
// an unpinned reference `&mut U` of an `Unpin` field .
struct Foo<T, U> {
x: T,
y: U,
}
struct Bar<T, U>(T, U);
enum Baz<T, U> {
Foo(T, U),
Bar { x: T, y: U },
}
// EMIT_MIR project_pattern_match.foo_mut.built.after.mir
fn foo_mut<T, U: Unpin>(foo: &pin mut Foo<T, U>) {
let Foo { x, y } = foo;
}
// EMIT_MIR project_pattern_match.foo_const.built.after.mir
fn foo_const<T, U: Unpin>(foo: &pin const Foo<T, U>) {
let Foo { x, y } = foo;
}
// EMIT_MIR project_pattern_match.bar_mut.built.after.mir
fn bar_mut<T, U: Unpin>(bar: &pin mut Bar<T, U>) {
let Bar(x, y) = bar;
}
// EMIT_MIR project_pattern_match.bar_const.built.after.mir
fn bar_const<T, U: Unpin>(bar: &pin const Bar<T, U>) {
let Bar(x, y) = bar;
}
// EMIT_MIR project_pattern_match.foo_bar_mut.built.after.mir
fn foo_bar_mut<T, U: Unpin>(foo: &pin mut Foo<Bar<T, U>, Bar<T, U>>) {
let Foo { x: Bar(x, y), y: Bar(z, w) } = foo;
}
// EMIT_MIR project_pattern_match.foo_bar_const.built.after.mir
fn foo_bar_const<T, U: Unpin>(foo: &pin const Foo<Bar<T, U>, Bar<T, U>>) {
let Foo { x: Bar(x, y), y: Bar(z, w) } = foo;
}
// EMIT_MIR project_pattern_match.baz_mut.built.after.mir
fn baz_mut<T, U: Unpin>(baz: &pin mut Baz<T, U>) {
match baz {
Baz::Foo(x, y) => {}
Baz::Bar { x, y } => {}
}
}
// EMIT_MIR project_pattern_match.baz_const.built.after.mir
fn baz_const<T, U: Unpin>(baz: &pin const Baz<T, U>) {
match baz {
Baz::Foo(x, y) => {}
Baz::Bar { x, y } => {}
}
}
// EMIT_MIR project_pattern_match.baz_baz_mut.built.after.mir
fn baz_baz_mut<T, U: Unpin>(baz: &pin mut Baz<Baz<T, U>, Baz<T, U>>) {
match baz {
Baz::Foo(Baz::Foo(x, y), Baz::Foo(z, w)) => {}
Baz::Foo(Baz::Foo(x, y), Baz::Bar { x: z, y: w }) => {}
Baz::Foo(Baz::Bar { x, y }, Baz::Foo(z, w)) => {}
Baz::Foo(Baz::Bar { x, y }, Baz::Bar { x: z, y: w }) => {}
Baz::Bar { x: Baz::Foo(x, y), y: Baz::Foo(z, w) } => {}
Baz::Bar { x: Baz::Foo(x, y), y: Baz::Bar { x: z, y: w } } => {}
Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Foo(z, w) } => {}
Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Bar { x: z, y: w } } => {}
}
}
// EMIT_MIR project_pattern_match.baz_baz_const.built.after.mir
fn baz_baz_const<T, U: Unpin>(baz: &pin const Baz<Baz<T, U>, Baz<T, U>>) {
match baz {
Baz::Foo(Baz::Foo(x, y), Baz::Foo(z, w)) => {}
Baz::Foo(Baz::Foo(x, y), Baz::Bar { x: z, y: w }) => {}
Baz::Foo(Baz::Bar { x, y }, Baz::Foo(z, w)) => {}
Baz::Foo(Baz::Bar { x, y }, Baz::Bar { x: z, y: w }) => {}
Baz::Bar { x: Baz::Foo(x, y), y: Baz::Foo(z, w) } => {}
Baz::Bar { x: Baz::Foo(x, y), y: Baz::Bar { x: z, y: w } } => {}
Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Foo(z, w) } => {}
Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Bar { x: z, y: w } } => {}
}
}
fn main() {}

View file

@ -0,0 +1,91 @@
//@ revisions: pin_ergonomics normal
//@ edition:2024
//@ check-pass
// //@[normal] check-pass
// //@[pin_ergonomics] rustc-env:RUSTC_LOG=rustc_hir_typeck::expr_use_visitor=DEBUG
#![cfg_attr(pin_ergonomics, feature(pin_ergonomics))]
#![feature(deref_patterns)]
#![allow(incomplete_features)]
// This test verifies that the `pin_ergonomics` feature works well
// together with the `deref_patterns` feature.
use std::pin::Pin;
struct Foo<T, U> {
x: T,
y: U,
}
struct Bar<T, U>(T, U);
enum Baz<T, U> {
Foo(T, U),
Bar { x: T, y: U },
}
fn foo_mut<T: Unpin, U: Unpin>(foo: Pin<&mut Foo<T, U>>) {
let Foo { .. } = foo;
let Pin { .. } = foo;
let _ = || {
let Foo { .. } = foo;
let Pin { .. } = foo;
};
#[cfg(pin_ergonomics)]
let Foo { x, y } = foo;
#[cfg(pin_ergonomics)]
let _ = || {
let Foo { x, y } = foo;
};
}
fn foo_const<T: Unpin, U: Unpin>(foo: Pin<&Foo<T, U>>) {
let Foo { .. } = foo;
let Pin { .. } = foo;
let _ = || {
let Foo { .. } = foo;
let Pin { .. } = foo;
};
#[cfg(pin_ergonomics)]
let Foo { x, y } = foo;
#[cfg(pin_ergonomics)]
let _ = || {
let Foo { x, y } = foo;
};
}
fn bar_mut<T: Unpin, U: Unpin>(bar: Pin<&mut Bar<T, U>>) {
let Bar(..) = bar;
let Pin { .. } = bar;
let _ = || {
let Bar(..) = bar;
let Pin { .. } = bar;
};
#[cfg(pin_ergonomics)]
let Bar(x, y) = bar;
#[cfg(pin_ergonomics)]
let _ = || {
let Bar(x, y) = bar;
};
}
fn bar_const<T: Unpin, U: Unpin>(bar: Pin<&Bar<T, U>>) {
let Bar(..) = bar;
let Pin { .. } = bar;
let _ = || {
let Bar(..) = bar;
let Pin { .. } = bar;
};
#[cfg(pin_ergonomics)]
let Bar(x, y) = bar;
#[cfg(pin_ergonomics)]
let _ = || {
let Bar(x, y) = bar;
};
}
fn main() {}

View file

@ -0,0 +1,66 @@
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:27:9
|
LL | Foo { .. } => {}
| ^^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Foo<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Foo<T, U>>`
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:31:9
|
LL | Foo { .. } => {}
| ^^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Foo<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Foo<T, U>>`
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:49:9
|
LL | Foo { .. } => {}
| ^^^^^^^^^^ matches on the result of dereferencing `Pin<&Foo<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Foo<T, U>>`
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:53:9
|
LL | Foo { .. } => {}
| ^^^^^^^^^^ matches on the result of dereferencing `Pin<&Foo<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Foo<T, U>>`
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:71:9
|
LL | Bar(..) => {}
| ^^^^^^^ matches on the result of dereferencing `Pin<&mut Bar<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Bar<T, U>>`
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:75:9
|
LL | Bar(..) => {}
| ^^^^^^^ matches on the result of dereferencing `Pin<&mut Bar<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Bar<T, U>>`
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:93:9
|
LL | Bar(..) => {}
| ^^^^^^^ matches on the result of dereferencing `Pin<&Bar<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Bar<T, U>>`
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:97:9
|
LL | Bar(..) => {}
| ^^^^^^^ matches on the result of dereferencing `Pin<&Bar<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Bar<T, U>>`
error: aborting due to 8 previous errors

View file

@ -0,0 +1,130 @@
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:27:9
|
LL | Foo { .. } => {}
| ^^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Foo<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Foo<T, U>>`
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:37:9
|
LL | Foo { x, y } => {}
| ^^^^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Foo<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Foo<T, U>>`
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:31:9
|
LL | Foo { .. } => {}
| ^^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Foo<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Foo<T, U>>`
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:42:9
|
LL | Foo { .. } => {}
| ^^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Foo<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Foo<T, U>>`
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:49:9
|
LL | Foo { .. } => {}
| ^^^^^^^^^^ matches on the result of dereferencing `Pin<&Foo<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Foo<T, U>>`
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:59:9
|
LL | Foo { x, y } => {}
| ^^^^^^^^^^^^ matches on the result of dereferencing `Pin<&Foo<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Foo<T, U>>`
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:53:9
|
LL | Foo { .. } => {}
| ^^^^^^^^^^ matches on the result of dereferencing `Pin<&Foo<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Foo<T, U>>`
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:64:9
|
LL | Foo { .. } => {}
| ^^^^^^^^^^ matches on the result of dereferencing `Pin<&Foo<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Foo<T, U>>`
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:71:9
|
LL | Bar(..) => {}
| ^^^^^^^ matches on the result of dereferencing `Pin<&mut Bar<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Bar<T, U>>`
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:81:9
|
LL | Bar(x, y) => {}
| ^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Bar<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Bar<T, U>>`
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:75:9
|
LL | Bar(..) => {}
| ^^^^^^^ matches on the result of dereferencing `Pin<&mut Bar<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Bar<T, U>>`
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:86:9
|
LL | Bar(x, y) => {}
| ^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Bar<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Bar<T, U>>`
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:93:9
|
LL | Bar(..) => {}
| ^^^^^^^ matches on the result of dereferencing `Pin<&Bar<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Bar<T, U>>`
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:103:9
|
LL | Bar(x, y) => {}
| ^^^^^^^^^ matches on the result of dereferencing `Pin<&Bar<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Bar<T, U>>`
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:97:9
|
LL | Bar(..) => {}
| ^^^^^^^ matches on the result of dereferencing `Pin<&Bar<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Bar<T, U>>`
error: mix of deref patterns and normal constructors
--> $DIR/pattern-matching-mix-deref-pattern.rs:108:9
|
LL | Bar(x, y) => {}
| ^^^^^^^^^ matches on the result of dereferencing `Pin<&Bar<T, U>>`
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Bar<T, U>>`
error: aborting due to 16 previous errors

View file

@ -0,0 +1,113 @@
//@ revisions: pin_ergonomics normal
//@ edition:2024
#![cfg_attr(pin_ergonomics, feature(pin_ergonomics))]
#![feature(deref_patterns)]
#![allow(incomplete_features)]
// This test verifies that the `pin_ergonomics` feature works well
// together with the `deref_patterns` feature under the error:
// "mix of deref patterns and normal constructors".
use std::pin::Pin;
struct Foo<T, U> {
x: T,
y: U,
}
struct Bar<T, U>(T, U);
enum Baz<T, U> {
Foo(T, U),
Bar { x: T, y: U },
}
fn foo_mut<T: Unpin, U: Unpin>(foo: Pin<&mut Foo<T, U>>) {
match foo {
Foo { .. } => {} //~ ERROR mix of deref patterns and normal constructors
Pin { .. } => {}
}
let _ = || match foo {
Foo { .. } => {} //~ ERROR mix of deref patterns and normal constructors
Pin { .. } => {}
};
#[cfg(pin_ergonomics)]
match foo {
Foo { x, y } => {} //[pin_ergonomics]~ ERROR mix of deref patterns and normal constructors
Pin { .. } => {}
}
#[cfg(pin_ergonomics)]
let _ = || match foo {
Foo { .. } => {} //[pin_ergonomics]~ ERROR mix of deref patterns and normal constructors
Pin { .. } => {}
};
}
fn foo_const<T: Unpin, U: Unpin>(foo: Pin<&Foo<T, U>>) {
match foo {
Foo { .. } => {} //~ ERROR mix of deref patterns and normal constructors
Pin { .. } => {}
}
let _ = || match foo {
Foo { .. } => {} //~ ERROR mix of deref patterns and normal constructors
Pin { .. } => {}
};
#[cfg(pin_ergonomics)]
match foo {
Foo { x, y } => {} //[pin_ergonomics]~ ERROR mix of deref patterns and normal constructors
Pin { .. } => {}
}
#[cfg(pin_ergonomics)]
let _ = || match foo {
Foo { .. } => {} //[pin_ergonomics]~ ERROR mix of deref patterns and normal constructors
Pin { .. } => {}
};
}
fn bar_mut<T: Unpin, U: Unpin>(bar: Pin<&mut Bar<T, U>>) {
match bar {
Bar(..) => {} //~ ERROR mix of deref patterns and normal constructors
Pin { .. } => {}
}
let _ = || match bar {
Bar(..) => {} //~ ERROR mix of deref patterns and normal constructors
Pin { .. } => {}
};
#[cfg(pin_ergonomics)]
match bar {
Bar(x, y) => {} //[pin_ergonomics]~ ERROR mix of deref patterns and normal constructors
Pin { .. } => {}
}
#[cfg(pin_ergonomics)]
let _ = || match bar {
Bar(x, y) => {} //[pin_ergonomics]~ ERROR mix of deref patterns and normal constructors
Pin { .. } => {}
};
}
fn bar_const<T: Unpin, U: Unpin>(bar: Pin<&Bar<T, U>>) {
match bar {
Bar(..) => {} //~ ERROR mix of deref patterns and normal constructors
Pin { .. } => {}
}
let _ = || match bar {
Bar(..) => {} //~ ERROR mix of deref patterns and normal constructors
Pin { .. } => {}
};
#[cfg(pin_ergonomics)]
match bar {
Bar(x, y) => {} //[pin_ergonomics]~ ERROR mix of deref patterns and normal constructors
Pin { .. } => {}
}
#[cfg(pin_ergonomics)]
let _ = || match bar {
Bar(x, y) => {} //[pin_ergonomics]~ ERROR mix of deref patterns and normal constructors
Pin { .. } => {}
};
}
fn main() {}

View file

@ -0,0 +1,313 @@
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:35:9
|
LL | let Foo { x, y } = foo;
| ^^^^^^^^^^^^ --- this expression has type `Pin<&mut Foo<T, U>>`
| |
| expected `Pin<&mut Foo<T, U>>`, found `Foo<_, _>`
|
= note: expected struct `Pin<&mut Foo<T, U>>`
found struct `Foo<_, _>`
help: consider dereferencing to access the inner value using the Deref trait
|
LL | let Foo { x, y } = *foo;
| +
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:42:9
|
LL | let Foo { x, y } = foo;
| ^^^^^^^^^^^^ --- this expression has type `Pin<&Foo<T, U>>`
| |
| expected `Pin<&Foo<T, U>>`, found `Foo<_, _>`
|
= note: expected struct `Pin<&Foo<T, U>>`
found struct `Foo<_, _>`
help: consider dereferencing to access the inner value using the Deref trait
|
LL | let Foo { x, y } = *foo;
| +
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:49:9
|
LL | let Bar(x, y) = bar;
| ^^^^^^^^^ --- this expression has type `Pin<&mut Bar<T, U>>`
| |
| expected `Pin<&mut Bar<T, U>>`, found `Bar<_, _>`
|
= note: expected struct `Pin<&mut Bar<T, U>>`
found struct `Bar<_, _>`
help: consider dereferencing to access the inner value using the Deref trait
|
LL | let Bar(x, y) = *bar;
| +
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:56:9
|
LL | let Bar(x, y) = bar;
| ^^^^^^^^^ --- this expression has type `Pin<&Bar<T, U>>`
| |
| expected `Pin<&Bar<T, U>>`, found `Bar<_, _>`
|
= note: expected struct `Pin<&Bar<T, U>>`
found struct `Bar<_, _>`
help: consider dereferencing to access the inner value using the Deref trait
|
LL | let Bar(x, y) = *bar;
| +
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:63:9
|
LL | let Foo { x: Bar(x, y), y: Bar(z, w) } = foo;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --- this expression has type `Pin<&mut Foo<Bar<T, U>, Bar<T, U>>>`
| |
| expected `Pin<&mut Foo<Bar<T, U>, Bar<T, U>>>`, found `Foo<_, _>`
|
= note: expected struct `Pin<&mut Foo<Bar<T, U>, Bar<T, U>>>`
found struct `Foo<_, _>`
help: consider dereferencing to access the inner value using the Deref trait
|
LL | let Foo { x: Bar(x, y), y: Bar(z, w) } = *foo;
| +
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:72:9
|
LL | let Foo { x: Bar(x, y), y: Bar(z, w) } = foo;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --- this expression has type `Pin<&Foo<Bar<T, U>, Bar<T, U>>>`
| |
| expected `Pin<&Foo<Bar<T, U>, Bar<T, U>>>`, found `Foo<_, _>`
|
= note: expected struct `Pin<&Foo<Bar<T, U>, Bar<T, U>>>`
found struct `Foo<_, _>`
help: consider dereferencing to access the inner value using the Deref trait
|
LL | let Foo { x: Bar(x, y), y: Bar(z, w) } = *foo;
| +
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:82:9
|
LL | match baz {
| --- this expression has type `Pin<&mut Baz<T, U>>`
LL | Baz::Foo(x, y) => {
| ^^^^^^^^^^^^^^ expected `Pin<&mut Baz<T, U>>`, found `Baz<_, _>`
|
= note: expected struct `Pin<&mut Baz<T, U>>`
found enum `Baz<_, _>`
help: consider dereferencing to access the inner value using the Deref trait
|
LL | match *baz {
| +
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:87:9
|
LL | match baz {
| --- this expression has type `Pin<&mut Baz<T, U>>`
...
LL | Baz::Bar { x, y } => {
| ^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz<T, U>>`, found `Baz<_, _>`
|
= note: expected struct `Pin<&mut Baz<T, U>>`
found enum `Baz<_, _>`
help: consider dereferencing to access the inner value using the Deref trait
|
LL | match *baz {
| +
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:97:9
|
LL | match baz {
| --- this expression has type `Pin<&Baz<T, U>>`
LL | Baz::Foo(x, y) => {
| ^^^^^^^^^^^^^^ expected `Pin<&Baz<T, U>>`, found `Baz<_, _>`
|
= note: expected struct `Pin<&Baz<T, U>>`
found enum `Baz<_, _>`
help: consider dereferencing to access the inner value using the Deref trait
|
LL | match *baz {
| +
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:102:9
|
LL | match baz {
| --- this expression has type `Pin<&Baz<T, U>>`
...
LL | Baz::Bar { x, y } => {
| ^^^^^^^^^^^^^^^^^ expected `Pin<&Baz<T, U>>`, found `Baz<_, _>`
|
= note: expected struct `Pin<&Baz<T, U>>`
found enum `Baz<_, _>`
help: consider dereferencing to access the inner value using the Deref trait
|
LL | match *baz {
| +
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:112:9
|
LL | match baz {
| --- this expression has type `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`
LL | Baz::Foo(Baz::Foo(x, y), Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`, found `Baz<_, _>`
|
= note: expected struct `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`
found enum `Baz<_, _>`
help: consider dereferencing to access the inner value using the Deref trait
|
LL | match *baz {
| +
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:119:9
|
LL | match baz {
| --- this expression has type `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`
...
LL | Baz::Foo(Baz::Bar { x, y }, Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`, found `Baz<_, _>`
|
= note: expected struct `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`
found enum `Baz<_, _>`
help: consider dereferencing to access the inner value using the Deref trait
|
LL | match *baz {
| +
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:126:9
|
LL | match baz {
| --- this expression has type `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`
...
LL | Baz::Bar { x: Baz::Foo(x, y), y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`, found `Baz<_, _>`
|
= note: expected struct `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`
found enum `Baz<_, _>`
help: consider dereferencing to access the inner value using the Deref trait
|
LL | match *baz {
| +
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:133:9
|
LL | match baz {
| --- this expression has type `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`
...
LL | Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`, found `Baz<_, _>`
|
= note: expected struct `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`
found enum `Baz<_, _>`
help: consider dereferencing to access the inner value using the Deref trait
|
LL | match *baz {
| +
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:145:9
|
LL | match baz {
| --- this expression has type `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
LL | Baz::Foo(foo, _) if let Baz::Foo(x, y) = foo => {
| ^^^^^^^^^^^^^^^^ expected `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`, found `Baz<_, _>`
|
= note: expected struct `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
found enum `Baz<_, _>`
help: consider dereferencing to access the inner value using the Deref trait
|
LL | match *baz {
| +
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:150:9
|
LL | match baz {
| --- this expression has type `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
...
LL | Baz::Bar { x: _, y: bar } if let Baz::Bar { x, y } = bar => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`, found `Baz<_, _>`
|
= note: expected struct `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
found enum `Baz<_, _>`
help: consider dereferencing to access the inner value using the Deref trait
|
LL | match *baz {
| +
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:155:9
|
LL | match baz {
| --- this expression has type `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
...
LL | Baz::Foo(Baz::Foo(x, y), Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`, found `Baz<_, _>`
|
= note: expected struct `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
found enum `Baz<_, _>`
help: consider dereferencing to access the inner value using the Deref trait
|
LL | match *baz {
| +
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:162:9
|
LL | match baz {
| --- this expression has type `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
...
LL | Baz::Foo(Baz::Bar { x, y }, Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`, found `Baz<_, _>`
|
= note: expected struct `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
found enum `Baz<_, _>`
help: consider dereferencing to access the inner value using the Deref trait
|
LL | match *baz {
| +
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:169:9
|
LL | match baz {
| --- this expression has type `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
...
LL | Baz::Bar { x: Baz::Foo(x, y), y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`, found `Baz<_, _>`
|
= note: expected struct `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
found enum `Baz<_, _>`
help: consider dereferencing to access the inner value using the Deref trait
|
LL | match *baz {
| +
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:176:9
|
LL | match baz {
| --- this expression has type `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
...
LL | Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`, found `Baz<_, _>`
|
= note: expected struct `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
found enum `Baz<_, _>`
help: consider dereferencing to access the inner value using the Deref trait
|
LL | match *baz {
| +
error: aborting due to 20 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -0,0 +1,186 @@
//@ revisions: pin_ergonomics normal
//@ edition:2024
//@[pin_ergonomics] check-pass
#![cfg_attr(pin_ergonomics, feature(pin_ergonomics))]
#![feature(if_let_guard)]
#![allow(incomplete_features)]
use std::pin::Pin;
// This test verifies that a `&pin mut Foo` can be projected to a pinned
// reference `&pin mut T` of a `?Unpin` field , and can be projected to
// an unpinned reference `&mut U` of an `Unpin` field.
struct Foo<T, U> {
x: T,
y: U,
}
struct Bar<T, U>(T, U);
enum Baz<T, U> {
Foo(T, U),
Bar { x: T, y: U },
}
trait IsPinMut {}
trait IsPinConst {}
impl<T: ?Sized> IsPinMut for Pin<&mut T> {}
impl<T: ?Sized> IsPinConst for Pin<&T> {}
fn assert_pin_mut<T: IsPinMut>(_: T) {}
fn assert_pin_const<T: IsPinConst>(_: T) {}
fn foo_mut<T, U: Unpin>(foo: Pin<&mut Foo<T, U>>) {
let Foo { x, y } = foo;
//[normal]~^ ERROR mismatched types
assert_pin_mut(x);
assert_pin_mut(y);
}
fn foo_const<T, U: Unpin>(foo: Pin<&Foo<T, U>>) {
let Foo { x, y } = foo;
//[normal]~^ ERROR mismatched types
assert_pin_const(x);
assert_pin_const(y);
}
fn bar_mut<T, U: Unpin>(bar: Pin<&mut Bar<T, U>>) {
let Bar(x, y) = bar;
//[normal]~^ ERROR mismatched types
assert_pin_mut(x);
assert_pin_mut(y);
}
fn bar_const<T, U: Unpin>(bar: Pin<&Bar<T, U>>) {
let Bar(x, y) = bar;
//[normal]~^ ERROR mismatched types
assert_pin_const(x);
assert_pin_const(y);
}
fn foo_bar_mut<T, U: Unpin>(foo: Pin<&mut Foo<Bar<T, U>, Bar<T, U>>>) {
let Foo { x: Bar(x, y), y: Bar(z, w) } = foo;
//[normal]~^ ERROR mismatched types
assert_pin_mut(x);
assert_pin_mut(y);
assert_pin_mut(z);
assert_pin_mut(w);
}
fn foo_bar_const<T, U: Unpin>(foo: Pin<&Foo<Bar<T, U>, Bar<T, U>>>) {
let Foo { x: Bar(x, y), y: Bar(z, w) } = foo;
//[normal]~^ ERROR mismatched types
assert_pin_const(x);
assert_pin_const(y);
assert_pin_const(z);
assert_pin_const(w);
}
fn baz_mut<T, U: Unpin>(baz: Pin<&mut Baz<T, U>>) {
match baz {
Baz::Foo(x, y) => {
//[normal]~^ ERROR mismatched types
assert_pin_mut(x);
assert_pin_mut(y);
}
Baz::Bar { x, y } => {
//[normal]~^ ERROR mismatched types
assert_pin_mut(x);
assert_pin_mut(y);
}
}
}
fn baz_const<T, U: Unpin>(baz: Pin<&Baz<T, U>>) {
match baz {
Baz::Foo(x, y) => {
//[normal]~^ ERROR mismatched types
assert_pin_const(x);
assert_pin_const(y);
}
Baz::Bar { x, y } => {
//[normal]~^ ERROR mismatched types
assert_pin_const(x);
assert_pin_const(y);
}
}
}
fn baz_baz_mut<T, U: Unpin>(baz: Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>) {
match baz {
Baz::Foo(Baz::Foo(x, y), Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => {
//[normal]~^ ERROR mismatched types
assert_pin_mut(x);
assert_pin_mut(y);
assert_pin_mut(z);
assert_pin_mut(w);
}
Baz::Foo(Baz::Bar { x, y }, Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => {
//[normal]~^ ERROR mismatched types
assert_pin_mut(x);
assert_pin_mut(y);
assert_pin_mut(z);
assert_pin_mut(w);
}
Baz::Bar { x: Baz::Foo(x, y), y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => {
//[normal]~^ ERROR mismatched types
assert_pin_mut(x);
assert_pin_mut(y);
assert_pin_mut(z);
assert_pin_mut(w);
}
Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => {
//[normal]~^ ERROR mismatched types
assert_pin_mut(x);
assert_pin_mut(y);
assert_pin_mut(z);
assert_pin_mut(w);
}
}
}
fn baz_baz_const<T, U: Unpin>(baz: Pin<&Baz<Baz<T, U>, Baz<T, U>>>) {
match baz {
Baz::Foo(foo, _) if let Baz::Foo(x, y) = foo => {
//[normal]~^ ERROR mismatched types
assert_pin_const(x);
assert_pin_const(y);
}
Baz::Bar { x: _, y: bar } if let Baz::Bar { x, y } = bar => {
//[normal]~^ ERROR mismatched types
assert_pin_const(x);
assert_pin_const(y);
}
Baz::Foo(Baz::Foo(x, y), Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => {
//[normal]~^ ERROR mismatched types
assert_pin_const(x);
assert_pin_const(y);
assert_pin_const(z);
assert_pin_const(w);
}
Baz::Foo(Baz::Bar { x, y }, Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => {
//[normal]~^ ERROR mismatched types
assert_pin_const(x);
assert_pin_const(y);
assert_pin_const(z);
assert_pin_const(w);
}
Baz::Bar { x: Baz::Foo(x, y), y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => {
//[normal]~^ ERROR mismatched types
assert_pin_const(x);
assert_pin_const(y);
assert_pin_const(z);
assert_pin_const(w);
}
Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => {
//[normal]~^ ERROR mismatched types
assert_pin_const(x);
assert_pin_const(y);
assert_pin_const(z);
assert_pin_const(w);
}
}
}
fn main() {}