From 296a363b603a40dc877d4dd7522ac34ccfb6e6f0 Mon Sep 17 00:00:00 2001 From: Frank King Date: Sun, 13 Apr 2025 22:57:37 +0800 Subject: [PATCH 1/2] Implement pattern matching for `&pin mut|const T` --- compiler/rustc_ast/src/ast.rs | 25 +- compiler/rustc_ast_ir/src/lib.rs | 7 + compiler/rustc_ast_pretty/src/pprust/state.rs | 7 +- .../src/diagnostics/mutability_errors.rs | 2 +- compiler/rustc_borrowck/src/lib.rs | 10 + compiler/rustc_hir/src/hir.rs | 2 +- .../rustc_hir_analysis/src/check/region.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 7 +- .../rustc_hir_typeck/src/expr_use_visitor.rs | 30 +- compiler/rustc_hir_typeck/src/pat.rs | 101 ++++- compiler/rustc_lint/src/static_mut_refs.rs | 2 +- compiler/rustc_middle/src/ty/adjustment.rs | 3 + compiler/rustc_middle/src/ty/adt.rs | 11 + compiler/rustc_middle/src/ty/sty.rs | 7 + .../rustc_middle/src/ty/typeck_results.rs | 5 +- .../src/builder/matches/match_pair.rs | 22 +- .../src/builder/matches/mod.rs | 69 ++- .../rustc_mir_build/src/check_unsafety.rs | 2 +- .../src/thir/pattern/check_match.rs | 6 +- .../src/thir/pattern/migration.rs | 2 +- .../rustc_mir_build/src/thir/pattern/mod.rs | 33 +- compiler/rustc_parse/src/parser/mod.rs | 11 +- compiler/rustc_parse/src/parser/pat.rs | 11 +- .../rustc_pattern_analysis/src/constructor.rs | 2 +- compiler/rustc_pattern_analysis/src/rustc.rs | 37 +- .../clippy_lints/src/index_refutable_slice.rs | 2 +- .../clippy_lints/src/matches/match_as_ref.rs | 2 +- .../src/matches/needless_match.rs | 2 +- .../src/matches/redundant_guards.rs | 2 +- .../clippy_lints/src/methods/clone_on_copy.rs | 2 +- src/tools/clippy/clippy_lints/src/misc.rs | 4 +- .../clippy/clippy_lints/src/question_mark.rs | 8 +- .../clippy/clippy_lints/src/utils/author.rs | 4 + .../clippy/clippy_utils/src/eager_or_lazy.rs | 7 +- src/tools/clippy/clippy_utils/src/lib.rs | 4 +- src/tools/rustfmt/src/patterns.rs | 3 +- ...ct_pattern_match.bar_const.built.after.mir | 33 ++ ...ject_pattern_match.bar_mut.built.after.mir | 33 ++ ...attern_match.baz_baz_const.built.after.mir | 422 ++++++++++++++++++ ..._pattern_match.baz_baz_mut.built.after.mir | 422 ++++++++++++++++++ ...ct_pattern_match.baz_const.built.after.mir | 76 ++++ ...ject_pattern_match.baz_mut.built.after.mir | 76 ++++ ...attern_match.foo_bar_const.built.after.mir | 47 ++ ..._pattern_match.foo_bar_mut.built.after.mir | 47 ++ ...ct_pattern_match.foo_const.built.after.mir | 33 ++ ...ject_pattern_match.foo_mut.built.after.mir | 33 ++ .../pin-ergonomics/project_pattern_match.rs | 95 ++++ .../pattern-matching-deref-pattern.rs | 91 ++++ ...n-matching-mix-deref-pattern.normal.stderr | 66 +++ ...ng-mix-deref-pattern.pin_ergonomics.stderr | 130 ++++++ .../pattern-matching-mix-deref-pattern.rs | 113 +++++ .../pattern-matching.normal.stderr | 313 +++++++++++++ tests/ui/pin-ergonomics/pattern-matching.rs | 186 ++++++++ 53 files changed, 2575 insertions(+), 97 deletions(-) create mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.bar_const.built.after.mir create mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.bar_mut.built.after.mir create mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_const.built.after.mir create mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_mut.built.after.mir create mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.baz_const.built.after.mir create mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.baz_mut.built.after.mir create mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_const.built.after.mir create mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_mut.built.after.mir create mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.foo_const.built.after.mir create mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.foo_mut.built.after.mir create mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.rs create mode 100644 tests/ui/pin-ergonomics/pattern-matching-deref-pattern.rs create mode 100644 tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.normal.stderr create mode 100644 tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.pin_ergonomics.stderr create mode 100644 tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.rs create mode 100644 tests/ui/pin-ergonomics/pattern-matching.normal.stderr create mode 100644 tests/ui/pin-ergonomics/pattern-matching.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 8c2b521c560d9..c9dadc6c7861c 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -786,14 +786,14 @@ pub struct PatField { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Encodable, Decodable, HashStable_Generic)] 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 @@ -811,20 +811,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 ", } } } diff --git a/compiler/rustc_ast_ir/src/lib.rs b/compiler/rustc_ast_ir/src/lib.rs index 0898433a74c53..8f7a1986c5cdf 100644 --- a/compiler/rustc_ast_ir/src/lib.rs +++ b/compiler/rustc_ast_ir/src/lib.rs @@ -101,3 +101,10 @@ pub enum Pinnedness { Not, Pinned, } + +impl Pinnedness { + /// Return `true` if self is pinned + pub fn is_pinned(self) -> bool { + matches!(self, Self::Pinned) + } +} diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index def0cb74d295b..4da33fd495a60 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1713,10 +1713,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); diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index a06540f832507..1245b8f83be83 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1218,7 +1218,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; diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 321b18c9b78b2..6c745e9343077 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2498,6 +2498,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(..) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e7898648c2b05..2d4545a9f1ab6 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -12,7 +12,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_attr_data_structures::AttributeKind; use rustc_data_structures::fingerprint::Fingerprint; diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 95f6fba6487a6..c55afe3df24ff 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -559,7 +559,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)), diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index bda02042aa66b..9448ce05b8d4f 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1919,10 +1919,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); diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 2034131882820..b9f1463d8007d 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -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` ... diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index bf4611e1e34a0..375d5e679e9bc 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -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; @@ -412,7 +412,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, }), ); } @@ -470,7 +470,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() { @@ -488,12 +488,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); @@ -507,22 +523,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); @@ -532,6 +539,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>` 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, Some(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() @@ -1052,7 +1097,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() @@ -1082,8 +1127,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, @@ -1099,7 +1144,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!( @@ -1127,7 +1172,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. @@ -1137,6 +1182,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, Some(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). }; @@ -2603,7 +2654,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 @@ -3124,8 +3175,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 + ); "binding modifier" } else { info.bad_ref_pats = true; diff --git a/compiler/rustc_lint/src/static_mut_refs.rs b/compiler/rustc_lint/src/static_mut_refs.rs index 4dda3c7951b87..59142a0d12711 100644 --- a/compiler/rustc_lint/src/static_mut_refs.rs +++ b/compiler/rustc_lint/src/static_mut_refs.rs @@ -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) { diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index 74573455f531a..2920c9cb42ab4 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -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`. 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, } diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 275458fc85f8d..f82e7fe891578 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -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`. + #[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() diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 8bb3b3f1263fa..a0efec8132637 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1286,6 +1286,13 @@ impl<'tcx> Ty<'tcx> { } } + pub fn pinned_ty(self) -> Option> { + 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`. pub fn expect_boxed_ty(self) -> Ty<'tcx> { self.boxed_ty() diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 88583407d25d7..9766432b6942a 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -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}; @@ -462,7 +463,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; @@ -486,7 +487,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 }) } } diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index 3a7854a5e118d..45367be4cd91b 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -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}; @@ -278,7 +279,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( diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 2c29b8628417f..854329ab0cd65 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -5,22 +5,22 @@ //! This also includes code for pattern bindings in `let` statements and //! function parameters. -use std::assert_matches::assert_matches; +use std::assert_matches::{assert_matches, debug_assert_matches}; use std::borrow::Borrow; use std::mem; use std::sync::Arc; -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::{self, *}; use rustc_middle::thir::{self, *}; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, ValTree, ValTreeKind}; use rustc_pattern_analysis::constructor::RangeEnd; use rustc_pattern_analysis::rustc::{DeconstructedPat, RustcPatCtxt}; +use rustc_middle::{bug, span_bug}; use rustc_span::{BytePos, Pos, Span, Symbol, sym}; use tracing::{debug, instrument}; @@ -931,6 +931,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); } @@ -2704,7 +2708,7 @@ 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) => { + ByRef::Yes(pinnedness, mutbl) => { // The arm binding will be by reference, so eagerly create it now. let value_for_arm = self.storage_live_binding( block, @@ -2716,6 +2720,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); @@ -2758,14 +2768,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, Some(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 diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 0b6b36640e92b..078e4e3186a2a 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -382,7 +382,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!( diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 7f47754f6bcd0..32e51c5519646 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -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`. diff --git a/compiler/rustc_mir_build/src/thir/pattern/migration.rs b/compiler/rustc_mir_build/src/thir/pattern/migration.rs index 12c457f13fc12..b1824575cfaea 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/migration.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/migration.rs @@ -164,7 +164,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. diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index a44afed5492d3..206165823b125 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -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), } }; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 90491e5324912..767447773443d 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -35,8 +35,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; @@ -1316,7 +1316,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`). diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 64653ee2a04c9..81cbe13923591 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -8,7 +8,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}; @@ -776,7 +777,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) { @@ -1083,7 +1088,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) diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index 09685640e5022..1174aa104f7f6 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -983,7 +983,7 @@ pub enum ConstructorSet { /// 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, non_exhaustive: bool }, - /// The type is `&T`. + /// The type is `&T` Ref, /// The type is a union. Union, diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index ee72b676b38e1..9a015b47efce1 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -232,19 +232,32 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { let slice = match ctor { Struct | Variant(_) | UnionField => match ty.kind() { ty::Tuple(fs) => reveal_and_alloc(cx, fs.iter()), - ty::Adt(adt, _) => { - let variant = &adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt)); - let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| { - let is_visible = - adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); - let is_uninhabited = cx.is_uninhabited(*ty); - let is_unstable = cx.tcx.lookup_stability(field.did).is_some_and(|stab| { - stab.is_unstable() && stab.feature != sym::rustc_private + ty::Adt(adt, args) => { + if adt.is_box() { + // The only legal patterns of type `Box` (outside `std`) are `_` and box + // patterns. If we're here we can assume this is a box pattern. + reveal_and_alloc(cx, once(args.type_at(0))) + } else if adt.is_pin() + && let ty::Ref(_, rty, _) = args.type_at(0).kind() + && self.tcx.features().pin_ergonomics() + { + reveal_and_alloc(cx, once(*rty)) + } else { + let variant = + &adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt)); + let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| { + let is_visible = + adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); + let is_uninhabited = cx.is_uninhabited(*ty); + let is_unstable = + cx.tcx.lookup_stability(field.did).is_some_and(|stab| { + stab.is_unstable() && stab.feature != sym::rustc_private + }); + let skip = is_uninhabited && (!is_visible || is_unstable); + (ty, PrivateUninhabitedField(skip)) }); - let skip = is_uninhabited && (!is_visible || is_unstable); - (ty, PrivateUninhabitedField(skip)) - }); - cx.dropless_arena.alloc_from_iter(tys) + cx.dropless_arena.alloc_from_iter(tys) + } } _ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"), }, diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs index 3d131a7825aff..deee514afd21c 100644 --- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs +++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs @@ -93,7 +93,7 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap, ex: &Expr<'_>, arms: &[Arm<'_>], expr: fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option { if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind && is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), 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 && is_res_lang_ctor(cx, path_res(cx, e), LangItem::OptionSome) && let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind diff --git a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs index b04db03f8d2e7..80e53fb06e1a3 100644 --- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs @@ -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` ( diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs index 7c6d45e424006..0f631b1258c06 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs @@ -175,7 +175,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 diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs index 2ecf3eb897988..35f03070e65f1 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs @@ -69,7 +69,7 @@ pub(super) fn check( _ => 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, diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index 09ee6f7037c64..a79b20903bc7c 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -158,7 +158,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { ) { 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()) { @@ -177,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { 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) diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index de12a25b03dff..a0e36ecd29a8b 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -148,7 +148,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, @@ -167,7 +167,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` @@ -476,8 +476,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!( diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index ac92ab5a245cc..35223bf7ca3b5 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -716,10 +716,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); diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index 9d38672efada9..d0ea267224212 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -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; }, diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index ff1ee663f9bf2..037c346444a6c 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -898,7 +898,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); }, _ => (), @@ -1905,7 +1905,7 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { .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 a tuple `(x, y)` is of type `&(i32, i32)`, then due to match ergonomics, // the inner patterns become references. Don't consider this the identity function diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index cb3879f4be8c9..41db29c42b25a 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -135,7 +135,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); diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.bar_const.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.bar_const.built.after.mir new file mode 100644 index 0000000000000..15f7446cc5912 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.bar_const.built.after.mir @@ -0,0 +1,33 @@ +// MIR for `bar_const` after built + +fn bar_const(_1: Pin<&Bar>) -> () { + 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)).0: T); + _2 = Pin::<&T> { pointer: move _4 }; + StorageLive(_3); + _5 = &((*(_1.0: &Bar)).1: U); + _3 = Pin::<&U> { pointer: move _5 }; + _0 = const (); + StorageDead(_3); + StorageDead(_2); + return; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } +} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.bar_mut.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.bar_mut.built.after.mir new file mode 100644 index 0000000000000..46fd15502ffb1 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.bar_mut.built.after.mir @@ -0,0 +1,33 @@ +// MIR for `bar_mut` after built + +fn bar_mut(_1: Pin<&mut Bar>) -> () { + 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)).0: T); + _2 = Pin::<&mut T> { pointer: move _4 }; + StorageLive(_3); + _5 = &mut ((*(_1.0: &mut Bar)).1: U); + _3 = Pin::<&mut U> { pointer: move _5 }; + _0 = const (); + StorageDead(_3); + StorageDead(_2); + return; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } +} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_const.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_const.built.after.mir new file mode 100644 index 0000000000000..8cfaf50a5f876 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_const.built.after.mir @@ -0,0 +1,422 @@ +// MIR for `baz_baz_const` after built + +fn baz_baz_const(_1: Pin<&Baz, Baz>>) -> () { + 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>))); + switchInt(move _8) -> [0: bb2, 1: bb16, otherwise: bb1]; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb2: { + _4 = discriminant((((*(_1.0: &Baz, Baz>)) as Foo).0: Baz)); + switchInt(move _4) -> [0: bb4, 1: bb10, otherwise: bb3]; + } + + bb3: { + goto -> bb1; + } + + bb4: { + _2 = discriminant((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz)); + 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>)) as Foo).1: Baz)); + 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>)) as Bar).0: Baz)); + switchInt(move _7) -> [0: bb18, 1: bb24, otherwise: bb17]; + } + + bb17: { + goto -> bb1; + } + + bb18: { + _5 = discriminant((((*(_1.0: &Baz, Baz>)) as Bar).1: Baz)); + 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>)) as Bar).1: Baz)); + 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>)) as Bar).0: Baz) as Bar).0: T); + _65 = Pin::<&T> { pointer: move _69 }; + StorageLive(_66); + _70 = &(((((*(_1.0: &Baz, Baz>)) as Bar).0: Baz) as Bar).1: U); + _66 = Pin::<&U> { pointer: move _70 }; + StorageLive(_67); + _71 = &(((((*(_1.0: &Baz, Baz>)) as Bar).1: Baz) as Bar).0: T); + _67 = Pin::<&T> { pointer: move _71 }; + StorageLive(_68); + _72 = &(((((*(_1.0: &Baz, Baz>)) as Bar).1: Baz) 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>)) as Bar).0: Baz) as Bar).0: T); + _57 = Pin::<&T> { pointer: move _61 }; + StorageLive(_58); + _62 = &(((((*(_1.0: &Baz, Baz>)) as Bar).0: Baz) as Bar).1: U); + _58 = Pin::<&U> { pointer: move _62 }; + StorageLive(_59); + _63 = &(((((*(_1.0: &Baz, Baz>)) as Bar).1: Baz) as Foo).0: T); + _59 = Pin::<&T> { pointer: move _63 }; + StorageLive(_60); + _64 = &(((((*(_1.0: &Baz, Baz>)) as Bar).1: Baz) 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>)) as Bar).0: Baz) as Foo).0: T); + _49 = Pin::<&T> { pointer: move _53 }; + StorageLive(_50); + _54 = &(((((*(_1.0: &Baz, Baz>)) as Bar).0: Baz) as Foo).1: U); + _50 = Pin::<&U> { pointer: move _54 }; + StorageLive(_51); + _55 = &(((((*(_1.0: &Baz, Baz>)) as Bar).1: Baz) as Bar).0: T); + _51 = Pin::<&T> { pointer: move _55 }; + StorageLive(_52); + _56 = &(((((*(_1.0: &Baz, Baz>)) as Bar).1: Baz) 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>)) as Bar).0: Baz) as Foo).0: T); + _41 = Pin::<&T> { pointer: move _45 }; + StorageLive(_42); + _46 = &(((((*(_1.0: &Baz, Baz>)) as Bar).0: Baz) as Foo).1: U); + _42 = Pin::<&U> { pointer: move _46 }; + StorageLive(_43); + _47 = &(((((*(_1.0: &Baz, Baz>)) as Bar).1: Baz) as Foo).0: T); + _43 = Pin::<&T> { pointer: move _47 }; + StorageLive(_44); + _48 = &(((((*(_1.0: &Baz, Baz>)) as Bar).1: Baz) 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>)) as Foo).0: Baz) as Bar).0: T); + _33 = Pin::<&T> { pointer: move _37 }; + StorageLive(_34); + _38 = &(((((*(_1.0: &Baz, Baz>)) as Foo).0: Baz) as Bar).1: U); + _34 = Pin::<&U> { pointer: move _38 }; + StorageLive(_35); + _39 = &(((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz) as Bar).0: T); + _35 = Pin::<&T> { pointer: move _39 }; + StorageLive(_36); + _40 = &(((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz) 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>)) as Foo).0: Baz) as Bar).0: T); + _25 = Pin::<&T> { pointer: move _29 }; + StorageLive(_26); + _30 = &(((((*(_1.0: &Baz, Baz>)) as Foo).0: Baz) as Bar).1: U); + _26 = Pin::<&U> { pointer: move _30 }; + StorageLive(_27); + _31 = &(((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz) as Foo).0: T); + _27 = Pin::<&T> { pointer: move _31 }; + StorageLive(_28); + _32 = &(((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz) 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>)) as Foo).0: Baz) as Foo).0: T); + _17 = Pin::<&T> { pointer: move _21 }; + StorageLive(_18); + _22 = &(((((*(_1.0: &Baz, Baz>)) as Foo).0: Baz) as Foo).1: U); + _18 = Pin::<&U> { pointer: move _22 }; + StorageLive(_19); + _23 = &(((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz) as Bar).0: T); + _19 = Pin::<&T> { pointer: move _23 }; + StorageLive(_20); + _24 = &(((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz) 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>)) as Foo).0: Baz) as Foo).0: T); + _9 = Pin::<&T> { pointer: move _13 }; + StorageLive(_10); + _14 = &(((((*(_1.0: &Baz, Baz>)) as Foo).0: Baz) as Foo).1: U); + _10 = Pin::<&U> { pointer: move _14 }; + StorageLive(_11); + _15 = &(((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz) as Foo).0: T); + _11 = Pin::<&T> { pointer: move _15 }; + StorageLive(_12); + _16 = &(((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz) as Foo).1: U); + _12 = Pin::<&U> { pointer: move _16 }; + _0 = const (); + StorageDead(_12); + StorageDead(_11); + StorageDead(_10); + StorageDead(_9); + goto -> bb37; + } + + bb37: { + return; + } +} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_mut.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_mut.built.after.mir new file mode 100644 index 0000000000000..43c523cbf5717 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_mut.built.after.mir @@ -0,0 +1,422 @@ +// MIR for `baz_baz_mut` after built + +fn baz_baz_mut(_1: Pin<&mut Baz, Baz>>) -> () { + 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>))); + switchInt(move _8) -> [0: bb2, 1: bb16, otherwise: bb1]; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb2: { + _4 = discriminant((((*(_1.0: &mut Baz, Baz>)) as Foo).0: Baz)); + switchInt(move _4) -> [0: bb4, 1: bb10, otherwise: bb3]; + } + + bb3: { + goto -> bb1; + } + + bb4: { + _2 = discriminant((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz)); + 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>)) as Foo).1: Baz)); + 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>)) as Bar).0: Baz)); + switchInt(move _7) -> [0: bb18, 1: bb24, otherwise: bb17]; + } + + bb17: { + goto -> bb1; + } + + bb18: { + _5 = discriminant((((*(_1.0: &mut Baz, Baz>)) as Bar).1: Baz)); + 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>)) as Bar).1: Baz)); + 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>)) as Bar).0: Baz) as Bar).0: T); + _65 = Pin::<&mut T> { pointer: move _69 }; + StorageLive(_66); + _70 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).0: Baz) as Bar).1: U); + _66 = Pin::<&mut U> { pointer: move _70 }; + StorageLive(_67); + _71 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).1: Baz) as Bar).0: T); + _67 = Pin::<&mut T> { pointer: move _71 }; + StorageLive(_68); + _72 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).1: Baz) 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>)) as Bar).0: Baz) as Bar).0: T); + _57 = Pin::<&mut T> { pointer: move _61 }; + StorageLive(_58); + _62 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).0: Baz) as Bar).1: U); + _58 = Pin::<&mut U> { pointer: move _62 }; + StorageLive(_59); + _63 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).1: Baz) as Foo).0: T); + _59 = Pin::<&mut T> { pointer: move _63 }; + StorageLive(_60); + _64 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).1: Baz) 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>)) as Bar).0: Baz) as Foo).0: T); + _49 = Pin::<&mut T> { pointer: move _53 }; + StorageLive(_50); + _54 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).0: Baz) as Foo).1: U); + _50 = Pin::<&mut U> { pointer: move _54 }; + StorageLive(_51); + _55 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).1: Baz) as Bar).0: T); + _51 = Pin::<&mut T> { pointer: move _55 }; + StorageLive(_52); + _56 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).1: Baz) 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>)) as Bar).0: Baz) as Foo).0: T); + _41 = Pin::<&mut T> { pointer: move _45 }; + StorageLive(_42); + _46 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).0: Baz) as Foo).1: U); + _42 = Pin::<&mut U> { pointer: move _46 }; + StorageLive(_43); + _47 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).1: Baz) as Foo).0: T); + _43 = Pin::<&mut T> { pointer: move _47 }; + StorageLive(_44); + _48 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).1: Baz) 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>)) as Foo).0: Baz) as Bar).0: T); + _33 = Pin::<&mut T> { pointer: move _37 }; + StorageLive(_34); + _38 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).0: Baz) as Bar).1: U); + _34 = Pin::<&mut U> { pointer: move _38 }; + StorageLive(_35); + _39 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz) as Bar).0: T); + _35 = Pin::<&mut T> { pointer: move _39 }; + StorageLive(_36); + _40 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz) 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>)) as Foo).0: Baz) as Bar).0: T); + _25 = Pin::<&mut T> { pointer: move _29 }; + StorageLive(_26); + _30 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).0: Baz) as Bar).1: U); + _26 = Pin::<&mut U> { pointer: move _30 }; + StorageLive(_27); + _31 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz) as Foo).0: T); + _27 = Pin::<&mut T> { pointer: move _31 }; + StorageLive(_28); + _32 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz) 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>)) as Foo).0: Baz) as Foo).0: T); + _17 = Pin::<&mut T> { pointer: move _21 }; + StorageLive(_18); + _22 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).0: Baz) as Foo).1: U); + _18 = Pin::<&mut U> { pointer: move _22 }; + StorageLive(_19); + _23 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz) as Bar).0: T); + _19 = Pin::<&mut T> { pointer: move _23 }; + StorageLive(_20); + _24 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz) 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>)) as Foo).0: Baz) as Foo).0: T); + _9 = Pin::<&mut T> { pointer: move _13 }; + StorageLive(_10); + _14 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).0: Baz) as Foo).1: U); + _10 = Pin::<&mut U> { pointer: move _14 }; + StorageLive(_11); + _15 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz) as Foo).0: T); + _11 = Pin::<&mut T> { pointer: move _15 }; + StorageLive(_12); + _16 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz) 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; + } +} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_const.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_const.built.after.mir new file mode 100644 index 0000000000000..5538449cc43cc --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_const.built.after.mir @@ -0,0 +1,76 @@ +// MIR for `baz_const` after built + +fn baz_const(_1: Pin<&Baz>) -> () { + 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))); + 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)) as Bar).0: T); + _7 = Pin::<&T> { pointer: move _9 }; + StorageLive(_8); + _10 = &(((*(_1.0: &Baz)) 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)) as Foo).0: T); + _3 = Pin::<&T> { pointer: move _5 }; + StorageLive(_4); + _6 = &(((*(_1.0: &Baz)) as Foo).1: U); + _4 = Pin::<&U> { pointer: move _6 }; + _0 = const (); + StorageDead(_4); + StorageDead(_3); + goto -> bb7; + } + + bb7: { + return; + } +} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_mut.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_mut.built.after.mir new file mode 100644 index 0000000000000..4ae472cba3a58 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_mut.built.after.mir @@ -0,0 +1,76 @@ +// MIR for `baz_mut` after built + +fn baz_mut(_1: Pin<&mut Baz>) -> () { + 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))); + 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)) as Bar).0: T); + _7 = Pin::<&mut T> { pointer: move _9 }; + StorageLive(_8); + _10 = &mut (((*(_1.0: &mut Baz)) 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)) as Foo).0: T); + _3 = Pin::<&mut T> { pointer: move _5 }; + StorageLive(_4); + _6 = &mut (((*(_1.0: &mut Baz)) as Foo).1: U); + _4 = Pin::<&mut U> { pointer: move _6 }; + _0 = const (); + StorageDead(_4); + StorageDead(_3); + goto -> bb7; + } + + bb7: { + return; + } +} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_const.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_const.built.after.mir new file mode 100644 index 0000000000000..8b397ffd18142 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_const.built.after.mir @@ -0,0 +1,47 @@ +// MIR for `foo_bar_const` after built + +fn foo_bar_const(_1: Pin<&Foo, Bar>>) -> () { + 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>)).0: Bar).0: T); + _2 = Pin::<&T> { pointer: move _6 }; + StorageLive(_3); + _7 = &(((*(_1.0: &Foo, Bar>)).0: Bar).1: U); + _3 = Pin::<&U> { pointer: move _7 }; + StorageLive(_4); + _8 = &(((*(_1.0: &Foo, Bar>)).1: Bar).0: T); + _4 = Pin::<&T> { pointer: move _8 }; + StorageLive(_5); + _9 = &(((*(_1.0: &Foo, Bar>)).1: Bar).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; + } +} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_mut.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_mut.built.after.mir new file mode 100644 index 0000000000000..2e8128bb9d1e4 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_mut.built.after.mir @@ -0,0 +1,47 @@ +// MIR for `foo_bar_mut` after built + +fn foo_bar_mut(_1: Pin<&mut Foo, Bar>>) -> () { + 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>)).0: Bar).0: T); + _2 = Pin::<&mut T> { pointer: move _6 }; + StorageLive(_3); + _7 = &mut (((*(_1.0: &mut Foo, Bar>)).0: Bar).1: U); + _3 = Pin::<&mut U> { pointer: move _7 }; + StorageLive(_4); + _8 = &mut (((*(_1.0: &mut Foo, Bar>)).1: Bar).0: T); + _4 = Pin::<&mut T> { pointer: move _8 }; + StorageLive(_5); + _9 = &mut (((*(_1.0: &mut Foo, Bar>)).1: Bar).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; + } +} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_const.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_const.built.after.mir new file mode 100644 index 0000000000000..b77b341d4ef76 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_const.built.after.mir @@ -0,0 +1,33 @@ +// MIR for `foo_const` after built + +fn foo_const(_1: Pin<&Foo>) -> () { + 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)).0: T); + _2 = Pin::<&T> { pointer: move _4 }; + StorageLive(_3); + _5 = &((*(_1.0: &Foo)).1: U); + _3 = Pin::<&U> { pointer: move _5 }; + _0 = const (); + StorageDead(_3); + StorageDead(_2); + return; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } +} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_mut.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_mut.built.after.mir new file mode 100644 index 0000000000000..c7b88d239f87a --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_mut.built.after.mir @@ -0,0 +1,33 @@ +// MIR for `foo_mut` after built + +fn foo_mut(_1: Pin<&mut Foo>) -> () { + 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)).0: T); + _2 = Pin::<&mut T> { pointer: move _4 }; + StorageLive(_3); + _5 = &mut ((*(_1.0: &mut Foo)).1: U); + _3 = Pin::<&mut U> { pointer: move _5 }; + _0 = const (); + StorageDead(_3); + StorageDead(_2); + return; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } +} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.rs b/tests/mir-opt/pin-ergonomics/project_pattern_match.rs new file mode 100644 index 0000000000000..8808111f303b3 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.rs @@ -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 { + x: T, + y: U, +} + +struct Bar(T, U); + +enum Baz { + Foo(T, U), + Bar { x: T, y: U }, +} + +// EMIT_MIR project_pattern_match.foo_mut.built.after.mir +fn foo_mut(foo: &pin mut Foo) { + let Foo { x, y } = foo; +} + +// EMIT_MIR project_pattern_match.foo_const.built.after.mir +fn foo_const(foo: &pin const Foo) { + let Foo { x, y } = foo; +} + +// EMIT_MIR project_pattern_match.bar_mut.built.after.mir +fn bar_mut(bar: &pin mut Bar) { + let Bar(x, y) = bar; +} + +// EMIT_MIR project_pattern_match.bar_const.built.after.mir +fn bar_const(bar: &pin const Bar) { + let Bar(x, y) = bar; +} + +// EMIT_MIR project_pattern_match.foo_bar_mut.built.after.mir +fn foo_bar_mut(foo: &pin mut Foo, Bar>) { + 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(foo: &pin const Foo, Bar>) { + let Foo { x: Bar(x, y), y: Bar(z, w) } = foo; +} + +// EMIT_MIR project_pattern_match.baz_mut.built.after.mir +fn baz_mut(baz: &pin mut Baz) { + match baz { + Baz::Foo(x, y) => {} + Baz::Bar { x, y } => {} + } +} + +// EMIT_MIR project_pattern_match.baz_const.built.after.mir +fn baz_const(baz: &pin const Baz) { + 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(baz: &pin mut Baz, Baz>) { + 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(baz: &pin const Baz, Baz>) { + 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() {} diff --git a/tests/ui/pin-ergonomics/pattern-matching-deref-pattern.rs b/tests/ui/pin-ergonomics/pattern-matching-deref-pattern.rs new file mode 100644 index 0000000000000..23d29e6f9dae4 --- /dev/null +++ b/tests/ui/pin-ergonomics/pattern-matching-deref-pattern.rs @@ -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 { + x: T, + y: U, +} + +struct Bar(T, U); + +enum Baz { + Foo(T, U), + Bar { x: T, y: U }, +} + +fn foo_mut(foo: Pin<&mut Foo>) { + 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(foo: Pin<&Foo>) { + 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(bar: Pin<&mut Bar>) { + 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(bar: Pin<&Bar>) { + 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() {} diff --git a/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.normal.stderr b/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.normal.stderr new file mode 100644 index 0000000000000..2389fe9ed98cd --- /dev/null +++ b/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.normal.stderr @@ -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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Foo>` + +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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Foo>` + +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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Foo>` + +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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Foo>` + +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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Bar>` + +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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Bar>` + +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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Bar>` + +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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Bar>` + +error: aborting due to 8 previous errors + diff --git a/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.pin_ergonomics.stderr b/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.pin_ergonomics.stderr new file mode 100644 index 0000000000000..f23e5cf72a45e --- /dev/null +++ b/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.pin_ergonomics.stderr @@ -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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Foo>` + +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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Foo>` + +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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Foo>` + +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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Foo>` + +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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Foo>` + +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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Foo>` + +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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Foo>` + +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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Foo>` + +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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Bar>` + +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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Bar>` + +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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Bar>` + +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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Bar>` + +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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Bar>` + +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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Bar>` + +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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Bar>` + +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>` +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Bar>` + +error: aborting due to 16 previous errors + diff --git a/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.rs b/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.rs new file mode 100644 index 0000000000000..c5ba9dbeb2e6e --- /dev/null +++ b/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.rs @@ -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 { + x: T, + y: U, +} + +struct Bar(T, U); + +enum Baz { + Foo(T, U), + Bar { x: T, y: U }, +} + +fn foo_mut(foo: Pin<&mut Foo>) { + 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(foo: Pin<&Foo>) { + 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(bar: Pin<&mut Bar>) { + 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(bar: Pin<&Bar>) { + 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() {} diff --git a/tests/ui/pin-ergonomics/pattern-matching.normal.stderr b/tests/ui/pin-ergonomics/pattern-matching.normal.stderr new file mode 100644 index 0000000000000..7aaa51e81ed90 --- /dev/null +++ b/tests/ui/pin-ergonomics/pattern-matching.normal.stderr @@ -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>` + | | + | expected `Pin<&mut Foo>`, found `Foo<_, _>` + | + = note: expected struct `Pin<&mut Foo>` + 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>` + | | + | expected `Pin<&Foo>`, found `Foo<_, _>` + | + = note: expected struct `Pin<&Foo>` + 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>` + | | + | expected `Pin<&mut Bar>`, found `Bar<_, _>` + | + = note: expected struct `Pin<&mut Bar>` + 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>` + | | + | expected `Pin<&Bar>`, found `Bar<_, _>` + | + = note: expected struct `Pin<&Bar>` + 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>>` + | | + | expected `Pin<&mut Foo, Bar>>`, found `Foo<_, _>` + | + = note: expected struct `Pin<&mut Foo, Bar>>` + 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>>` + | | + | expected `Pin<&Foo, Bar>>`, found `Foo<_, _>` + | + = note: expected struct `Pin<&Foo, Bar>>` + 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>` +LL | Baz::Foo(x, y) => { + | ^^^^^^^^^^^^^^ expected `Pin<&mut Baz>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&mut Baz>` + 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>` +... +LL | Baz::Bar { x, y } => { + | ^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&mut Baz>` + 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>` +LL | Baz::Foo(x, y) => { + | ^^^^^^^^^^^^^^ expected `Pin<&Baz>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&Baz>` + 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>` +... +LL | Baz::Bar { x, y } => { + | ^^^^^^^^^^^^^^^^^ expected `Pin<&Baz>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&Baz>` + 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>>` +LL | Baz::Foo(Baz::Foo(x, y), Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz, Baz>>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&mut Baz, Baz>>` + 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>>` +... +LL | Baz::Foo(Baz::Bar { x, y }, Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz, Baz>>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&mut Baz, Baz>>` + 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>>` +... +LL | Baz::Bar { x: Baz::Foo(x, y), y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz, Baz>>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&mut Baz, Baz>>` + 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>>` +... +LL | Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz, Baz>>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&mut Baz, Baz>>` + 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>>` +LL | Baz::Foo(foo, _) if let Baz::Foo(x, y) = foo => { + | ^^^^^^^^^^^^^^^^ expected `Pin<&Baz, Baz>>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&Baz, Baz>>` + 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>>` +... +LL | Baz::Bar { x: _, y: bar } if let Baz::Bar { x, y } = bar => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz, Baz>>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&Baz, Baz>>` + 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>>` +... +LL | Baz::Foo(Baz::Foo(x, y), Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz, Baz>>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&Baz, Baz>>` + 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>>` +... +LL | Baz::Foo(Baz::Bar { x, y }, Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz, Baz>>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&Baz, Baz>>` + 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>>` +... +LL | Baz::Bar { x: Baz::Foo(x, y), y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz, Baz>>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&Baz, Baz>>` + 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>>` +... +LL | Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz, Baz>>`, found `Baz<_, _>` + | + = note: expected struct `Pin<&Baz, Baz>>` + 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`. diff --git a/tests/ui/pin-ergonomics/pattern-matching.rs b/tests/ui/pin-ergonomics/pattern-matching.rs new file mode 100644 index 0000000000000..e480ebfc00626 --- /dev/null +++ b/tests/ui/pin-ergonomics/pattern-matching.rs @@ -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 { + x: T, + y: U, +} + +struct Bar(T, U); + +enum Baz { + Foo(T, U), + Bar { x: T, y: U }, +} + +trait IsPinMut {} +trait IsPinConst {} +impl IsPinMut for Pin<&mut T> {} +impl IsPinConst for Pin<&T> {} + +fn assert_pin_mut(_: T) {} +fn assert_pin_const(_: T) {} + +fn foo_mut(foo: Pin<&mut Foo>) { + let Foo { x, y } = foo; + //[normal]~^ ERROR mismatched types + assert_pin_mut(x); + assert_pin_mut(y); +} + +fn foo_const(foo: Pin<&Foo>) { + let Foo { x, y } = foo; + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_pin_const(y); +} + +fn bar_mut(bar: Pin<&mut Bar>) { + let Bar(x, y) = bar; + //[normal]~^ ERROR mismatched types + assert_pin_mut(x); + assert_pin_mut(y); +} + +fn bar_const(bar: Pin<&Bar>) { + let Bar(x, y) = bar; + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_pin_const(y); +} + +fn foo_bar_mut(foo: Pin<&mut Foo, Bar>>) { + 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(foo: Pin<&Foo, Bar>>) { + 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(baz: Pin<&mut Baz>) { + 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(baz: Pin<&Baz>) { + 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(baz: Pin<&mut Baz, Baz>>) { + 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(baz: Pin<&Baz, Baz>>) { + 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() {} From 03f797030f8a7ce536a61cdd0f826ca27ade5f5b Mon Sep 17 00:00:00 2001 From: Frank King Date: Sat, 19 Jul 2025 21:54:05 +0800 Subject: [PATCH 2/2] require `T: !Unpin` for `&pin mut T` to be projected to `&pin mut T.U` where `U: ?Unpin` --- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 25 +- compiler/rustc_hir_typeck/src/pat.rs | 214 ++++++--- compiler/rustc_middle/src/ty/sty.rs | 10 + .../rustc_middle/src/ty/typeck_results.rs | 26 ++ .../src/builder/matches/mod.rs | 4 +- .../rustc_pattern_analysis/src/constructor.rs | 2 +- compiler/rustc_pattern_analysis/src/rustc.rs | 37 +- .../src/traits/select/candidate_assembly.rs | 76 +++- .../src/traits/select/confirmation.rs | 5 + .../src/traits/select/mod.rs | 52 ++- ...ct_pattern_match.bar_const.built.after.mir | 33 -- ...ject_pattern_match.bar_mut.built.after.mir | 33 -- ...attern_match.baz_baz_const.built.after.mir | 422 ------------------ ..._pattern_match.baz_baz_mut.built.after.mir | 422 ------------------ ...ct_pattern_match.baz_const.built.after.mir | 76 ---- ...ject_pattern_match.baz_mut.built.after.mir | 76 ---- ...attern_match.foo_bar_const.built.after.mir | 47 -- ..._pattern_match.foo_bar_mut.built.after.mir | 47 -- ...ct_pattern_match.foo_const.built.after.mir | 33 -- ...ject_pattern_match.foo_mut.built.after.mir | 33 -- .../pin-ergonomics/project_pattern_match.rs | 95 ---- .../pattern-matching.normal.stderr | 327 +++++--------- tests/ui/pin-ergonomics/pattern-matching.rs | 186 ++++---- .../pin-ergonomics/projection-unpin-checks.rs | 132 ++++++ .../projection-unpin-checks.stderr | 333 ++++++++++++++ 25 files changed, 1015 insertions(+), 1731 deletions(-) delete mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.bar_const.built.after.mir delete mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.bar_mut.built.after.mir delete mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_const.built.after.mir delete mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_mut.built.after.mir delete mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.baz_const.built.after.mir delete mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.baz_mut.built.after.mir delete mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_const.built.after.mir delete mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_mut.built.after.mir delete mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.foo_const.built.after.mir delete mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.foo_mut.built.after.mir delete mode 100644 tests/mir-opt/pin-ergonomics/project_pattern_match.rs create mode 100644 tests/ui/pin-ergonomics/projection-unpin-checks.rs create mode 100644 tests/ui/pin-ergonomics/projection-unpin-checks.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 0b3d50ff2199f..422c28edea0a4 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -23,7 +23,7 @@ use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{ self, AdtKind, CanonicalUserType, GenericArgsRef, GenericParamDefKind, IsIdentity, - SizedTraitKind, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitableExt, UserArgs, + SizedTraitKind, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitableExt, Upcast, UserArgs, UserSelfTy, }; use rustc_middle::{bug, span_bug}; @@ -463,6 +463,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + pub(crate) fn register_negative_bound( + &self, + ty: Ty<'tcx>, + def_id: DefId, + cause: traits::ObligationCause<'tcx>, + ) { + if !ty.references_error() { + let trait_ref = ty::TraitRef::new(self.tcx, def_id, [ty]); + let predicate = + ty::TraitPredicate { trait_ref, polarity: ty::PredicatePolarity::Negative } + .upcast(self.tcx); + self.fulfillment_cx.borrow_mut().register_predicate_obligation( + self, + traits::Obligation { + cause, + recursion_depth: 0, + param_env: self.param_env, + predicate, + }, + ); + } + } + pub(crate) fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> LoweredTy<'tcx> { let ty = self.lowerer().lower_ty(hir_ty); self.register_wf_obligation(ty.into(), hir_ty.span, ObligationCauseCode::WellFormed(None)); diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 375d5e679e9bc..bc18934f6b923 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -27,7 +27,7 @@ use rustc_span::edition::Edition; use rustc_span::source_map::Spanned; use rustc_span::{BytePos, DUMMY_SP, Ident, Span, kw, sym}; use rustc_trait_selection::infer::InferCtxtExt; -use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; +use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt}; use tracing::{debug, instrument, trace}; use ty::VariantDef; use ty::adjustment::{PatAdjust, PatAdjustment}; @@ -402,19 +402,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.check_pat_inner(pat, opt_path_res, adjust_mode, expected, pat_info); self.write_ty(pat.hir_id, ty); - // If we implicitly inserted overloaded dereferences before matching, check the pattern to - // see if the dereferenced types need `DerefMut` bounds. - if let Some(derefed_tys) = self.typeck_results.borrow().pat_adjustments().get(pat.hir_id) - && derefed_tys.iter().any(|adjust| adjust.kind == PatAdjust::OverloadedDeref) - { - self.register_deref_mut_bounds_if_needed( - pat.span, - pat, - derefed_tys.iter().filter_map(|adjust| match adjust.kind { - PatAdjust::OverloadedDeref => Some(adjust.source), - PatAdjust::BuiltinDeref | PatAdjust::PinDeref => None, - }), - ); + // If we implicitly inserted overloaded dereferences and pinned dereferences before matching, + // check the pattern to see if the dereferenced types need `DerefMut` or `!Unpin` bounds. + if let Some(derefed_tys) = self.typeck_results.borrow().pat_adjustments().get(pat.hir_id) { + let mut has_overloaded_deref = false; + let mut has_pin_deref = false; + derefed_tys.iter().for_each(|adjust| match adjust.kind { + PatAdjust::BuiltinDeref => {} + PatAdjust::OverloadedDeref => has_overloaded_deref = true, + PatAdjust::PinDeref => has_pin_deref = true, + }); + if has_overloaded_deref { + self.register_deref_mut_bounds_if_needed( + pat.span, + pat, + derefed_tys.iter().filter_map(|adjust| match adjust.kind { + PatAdjust::OverloadedDeref => Some(adjust.source), + PatAdjust::BuiltinDeref | PatAdjust::PinDeref => None, + }), + ); + } + if has_pin_deref { + self.register_not_unpin_bounds_if_needed( + pat.span, + pat, + derefed_tys.iter().filter_map(|adjust| match adjust.kind { + PatAdjust::BuiltinDeref | PatAdjust::OverloadedDeref => None, + PatAdjust::PinDeref => { + Some(adjust.source.pinned_ref().expect("expected pinned reference").0) + } + }), + ); + } } // (note_1): In most of the cases where (note_1) is referenced @@ -552,13 +571,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && 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 @@ -566,16 +578,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if binding_mode == ByRef::Yes(Pinnedness::Not, Mutability::Mut) { self.register_bound( inner_ty, - self.tcx.require_lang_item(hir::LangItem::Unpin, Some(pat.span)), + self.tcx.require_lang_item(hir::LangItem::Unpin, pat.span), self.misc(pat.span), - ); + ) } + // Once we've checked `pat`, we'll add a `!Unpin` bound if it contains any + // `ref pin` bindings. See `Self::register_not_unpin_bounds_if_needed`. + + debug!("default binding mode is now {:?}", binding_mode); + // 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) + + self.check_deref_pattern( + pat, + opt_path_res, + adjust_mode, + expected, + inner_ty, + PatAdjust::PinDeref, + 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/`. @@ -584,35 +607,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && pat.default_binding_modes && self.should_peel_smart_pointer(peel_kind, expected) => { - debug!("scrutinee ty {expected:?} is a smart pointer, inserting overloaded deref"); + debug!("scrutinee ty {expected:?} is a smart pointer, inserting pin deref"); + // The scrutinee is a smart pointer; implicitly dereference it. This adds a // requirement that `expected: DerefPure`. - let mut inner_ty = self.deref_pat_target(pat.span, expected); + let inner_ty = self.deref_pat_target(pat.span, expected); // Once we've checked `pat`, we'll add a `DerefMut` bound if it contains any // `ref mut` bindings. See `Self::register_deref_mut_bounds_if_needed`. - let mut typeck_results = self.typeck_results.borrow_mut(); - let mut pat_adjustments_table = typeck_results.pat_adjustments_mut(); - let pat_adjustments = pat_adjustments_table.entry(pat.hir_id).or_default(); - // We may reach the recursion limit if a user matches on a type `T` satisfying - // `T: Deref`; error gracefully in this case. - // FIXME(deref_patterns): If `deref_patterns` stabilizes, it may make sense to move - // this check out of this branch. Alternatively, this loop could be implemented with - // autoderef and this check removed. For now though, don't break code compiling on - // stable with lots of `&`s and a low recursion limit, if anyone's done that. - if self.tcx.recursion_limit().value_within_limit(pat_adjustments.len()) { - // Preserve the smart pointer type for THIR lowering and closure upvar analysis. - pat_adjustments - .push(PatAdjustment { kind: PatAdjust::OverloadedDeref, source: expected }); - } else { - let guar = report_autoderef_recursion_limit_error(self.tcx, pat.span, expected); - inner_ty = Ty::new_error(self.tcx, guar); - } - drop(typeck_results); - - // Recurse, using the old pat info to keep `current_depth` to its old value. - // Peeling smart pointers does not update the default binding mode. - self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, old_pat_info) + self.check_deref_pattern( + pat, + opt_path_res, + adjust_mode, + expected, + inner_ty, + PatAdjust::OverloadedDeref, + old_pat_info, + ) } PatKind::Missing | PatKind::Wild | PatKind::Err(_) => expected, // We allow any type here; we ensure that the type is uninhabited during match checking. @@ -683,6 +694,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn check_deref_pattern( + &self, + pat: &'tcx Pat<'tcx>, + opt_path_res: Option, ErrorGuaranteed>>, + adjust_mode: AdjustMode, + expected: Ty<'tcx>, + mut inner_ty: Ty<'tcx>, + pat_adjust_kind: PatAdjust, + pat_info: PatInfo<'tcx>, + ) -> Ty<'tcx> { + debug_assert!( + !matches!(pat_adjust_kind, PatAdjust::BuiltinDeref), + "unexpected deref pattern for builtin reference type {expected:?}", + ); + + let mut typeck_results = self.typeck_results.borrow_mut(); + let mut pat_adjustments_table = typeck_results.pat_adjustments_mut(); + let pat_adjustments = pat_adjustments_table.entry(pat.hir_id).or_default(); + // We may reach the recursion limit if a user matches on a type `T` satisfying + // `T: Deref`; error gracefully in this case. + // FIXME(deref_patterns): If `deref_patterns` stabilizes, it may make sense to move + // this check out of this branch. Alternatively, this loop could be implemented with + // autoderef and this check removed. For now though, don't break code compiling on + // stable with lots of `&`s and a low recursion limit, if anyone's done that. + if self.tcx.recursion_limit().value_within_limit(pat_adjustments.len()) { + // Preserve the smart pointer type for THIR lowering and closure upvar analysis. + pat_adjustments.push(PatAdjustment { kind: pat_adjust_kind, source: expected }); + } else { + let guar = report_autoderef_recursion_limit_error(self.tcx, pat.span, expected); + inner_ty = Ty::new_error(self.tcx, guar); + } + drop(typeck_results); + + // Recurse, using the old pat info to keep `current_depth` to its old value. + // Peeling smart pointers does not update the default binding mode. + self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, pat_info) + } + /// How should the binding mode and expected type be adjusted? /// /// When the pattern contains a path, `opt_path_res` must be `Some(path_res)`. @@ -1185,7 +1234,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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, Some(pat.span))), + 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`. @@ -2628,6 +2677,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + /// Check if the interior of a pin pattern (either explicit or implicit) has any `ref pin` + /// bindings of non-`Unpin` types, which would require `!Unpin` to be emitted. + fn register_not_unpin_bounds_if_needed( + &self, + span: Span, + inner: &'tcx Pat<'tcx>, + derefed_tys: impl IntoIterator>, + ) { + // Check if there are subpatterns with `ref pin` binding modes of non-`Unpin` types. + let unpin = self.tcx.require_lang_item(hir::LangItem::Unpin, span); + let cause = self.misc(span); + let unpin_obligations = self.probe(|_| { + let ocx = ObligationCtxt::new(&self); + self.typeck_results.borrow().pat_walk_ref_pin_binding_of_non_unpin_type(inner, |ty| { + let ty = ocx + .normalize(&cause, self.param_env, ty) + .pinned_ref() + .expect("expect pinned reference") + .0; + debug!("check if `Unpin` is implemented for `{ty:?}`"); + ocx.register_bound(cause.clone(), self.param_env, ty, unpin); + }); + ocx.select_all_or_error() + }); + + // If any, the current pattern type should implement `!Unpin`. + if !unpin_obligations.is_empty() { + for pinned_derefed_ty in derefed_tys { + debug!("register `!Unpin` for `{pinned_derefed_ty:?}`"); + self.register_negative_bound( + pinned_derefed_ty, + self.tcx.require_lang_item(hir::LangItem::Unpin, span), + self.misc(span), + ); + } + } + } + // Precondition: Pat is Ref(inner) fn check_pat_ref( &self, @@ -2654,7 +2741,9 @@ 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 { + // FIXME(pin_ergonomics): since `&pin` pattern is supported, the condition here + // should be adjusted to `pat_pin == inh_pin` + if let ByRef::Yes(Pinnedness::Not, 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 @@ -2673,9 +2762,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return expected; } InheritedRefMatchRule::EatInner => { - if let ty::Ref(_, _, r_mutbl) = *expected.kind() - && pat_mutbl <= r_mutbl - { + let expected_ref_or_pinned_ref = || { + if self.tcx.features().pin_ergonomics() + && let Some(ty::Ref(_, _, r_mutbl)) = + expected.pinned_ty().map(|ty| *ty.kind()) + && pat_mutbl <= r_mutbl + { + return Some((Pinnedness::Pinned, r_mutbl)); + } + if let ty::Ref(_, _, r_mutbl) = *expected.kind() + && pat_mutbl <= r_mutbl + { + return Some((Pinnedness::Not, r_mutbl)); + } + None + }; + if let Some((_, r_mutbl)) = expected_ref_or_pinned_ref() { // Match against the reference type; don't consume the inherited ref. // NB: The check for compatible pattern and ref type mutability assumes that // `&` patterns can match against mutable references (RFC 3627, Rule 5). If diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index a0efec8132637..b6c5f43e8c1e8 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1293,6 +1293,16 @@ impl<'tcx> Ty<'tcx> { } } + pub fn pinned_ref(self) -> Option<(Ty<'tcx>, ty::Mutability)> { + if let Adt(def, args) = self.kind() + && def.is_pin() + && let &ty::Ref(_, ty, mutbl) = args.type_at(0).kind() + { + return Some((ty, mutbl)); + } + None + } + /// Panics if called on any type other than `Box`. pub fn expect_boxed_ty(self) -> Ty<'tcx> { self.boxed_ty() diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 9766432b6942a..efdfca82d681e 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -476,6 +476,32 @@ impl<'tcx> TypeckResults<'tcx> { has_ref_mut } + /// Visits the pattern recursively whether it contains a `ref pin` binding + /// of non-`Unpin` type in it. + /// + /// This is used to determined whether a `&pin` pattern should emit a `!Unpin` + /// call for its pattern scrutinee. + /// + /// This is computed from the typeck results since we want to make + /// sure to apply any match-ergonomics adjustments, which we cannot + /// determine from the HIR alone. + pub fn pat_walk_ref_pin_binding_of_non_unpin_type<'a>( + &self, + pat: &hir::Pat<'_>, + mut ty_visitor: impl FnMut(Ty<'tcx>) + 'a, + ) { + pat.walk(|pat| { + if let hir::PatKind::Binding(_, id, _, _) = pat.kind + && let Some(BindingMode(ByRef::Yes(Pinnedness::Pinned, _), _)) = + self.pat_binding_modes().get(id) + { + let ty = self.pat_ty(pat); + ty_visitor(ty); + } + true + }); + } + /// How should a deref pattern find the place for its inner pattern to match on? /// /// In most cases, if the pattern recursively contains a `ref mut` binding, we find the inner diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 854329ab0cd65..ab3613584d9ff 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -18,9 +18,9 @@ use rustc_middle::middle::region; use rustc_middle::mir::{self, *}; 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_middle::{bug, span_bug}; use rustc_span::{BytePos, Pos, Span, Symbol, sym}; use tracing::{debug, instrument}; @@ -2811,7 +2811,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.push_assign(block, source_info, pinned_temp, borrow); Rvalue::Aggregate( Box::new(AggregateKind::Adt( - self.tcx.require_lang_item(LangItem::Pin, Some(source_info.span)), + self.tcx.require_lang_item(LangItem::Pin, source_info.span), FIRST_VARIANT, self.tcx.mk_args(&[pinned_ty.into()]), None, diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index 1174aa104f7f6..09685640e5022 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -983,7 +983,7 @@ pub enum ConstructorSet { /// 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, non_exhaustive: bool }, - /// The type is `&T` + /// The type is `&T`. Ref, /// The type is a union. Union, diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 9a015b47efce1..ee72b676b38e1 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -232,32 +232,19 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { let slice = match ctor { Struct | Variant(_) | UnionField => match ty.kind() { ty::Tuple(fs) => reveal_and_alloc(cx, fs.iter()), - ty::Adt(adt, args) => { - if adt.is_box() { - // The only legal patterns of type `Box` (outside `std`) are `_` and box - // patterns. If we're here we can assume this is a box pattern. - reveal_and_alloc(cx, once(args.type_at(0))) - } else if adt.is_pin() - && let ty::Ref(_, rty, _) = args.type_at(0).kind() - && self.tcx.features().pin_ergonomics() - { - reveal_and_alloc(cx, once(*rty)) - } else { - let variant = - &adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt)); - let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| { - let is_visible = - adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); - let is_uninhabited = cx.is_uninhabited(*ty); - let is_unstable = - cx.tcx.lookup_stability(field.did).is_some_and(|stab| { - stab.is_unstable() && stab.feature != sym::rustc_private - }); - let skip = is_uninhabited && (!is_visible || is_unstable); - (ty, PrivateUninhabitedField(skip)) + ty::Adt(adt, _) => { + let variant = &adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt)); + let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| { + let is_visible = + adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); + let is_uninhabited = cx.is_uninhabited(*ty); + let is_unstable = cx.tcx.lookup_stability(field.did).is_some_and(|stab| { + stab.is_unstable() && stab.feature != sym::rustc_private }); - cx.dropless_arena.alloc_from_iter(tys) - } + let skip = is_uninhabited && (!is_visible || is_unstable); + (ty, PrivateUninhabitedField(skip)) + }); + cx.dropless_arena.alloc_from_iter(tys) } _ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"), }, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 2c7089507a897..816389426c921 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -52,20 +52,35 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false }; + let def_id = obligation.predicate.def_id(); + let tcx = self.tcx(); + + let lang_item = tcx.as_lang_item(def_id); + // Negative trait predicates have different rules than positive trait predicates. if obligation.polarity() == ty::PredicatePolarity::Negative { self.assemble_candidates_for_trait_alias(obligation, &mut candidates); self.assemble_candidates_from_impls(obligation, &mut candidates); self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?; + + match lang_item { + Some(LangItem::Unpin) if tcx.features().pin_ergonomics() => { + debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty()); + + // impl `!Unpin` automatically for tuples, slices, and arrays + // to support projections for pinned patterns. + self.assemble_builtin_neg_unpin_candidate( + obligation.predicate.self_ty().skip_binder(), + &mut candidates, + ); + } + _ => {} + } } else { self.assemble_candidates_for_trait_alias(obligation, &mut candidates); // Other bounds. Consider both in-scope bounds from fn decl // and applicable impls. There is a certain set of precedence rules here. - let def_id = obligation.predicate.def_id(); - let tcx = self.tcx(); - - let lang_item = tcx.as_lang_item(def_id); match lang_item { Some(LangItem::Copy | LangItem::Clone) => { debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty()); @@ -1218,6 +1233,59 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + /// Assembles `!Unpin` candidates for built-in types with no libcore-defined + /// `!Unpin` impls. + #[instrument(level = "debug", skip(self, candidates))] + fn assemble_builtin_neg_unpin_candidate( + &mut self, + self_ty: Ty<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + match *self_ty.kind() { + // `Unpin` types + ty::FnDef(..) + | ty::FnPtr(..) + | ty::Error(_) + | ty::Uint(_) + | ty::Int(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Ref(..) + | ty::Dynamic(..) + | ty::Str + | ty::Foreign(..) + | ty::UnsafeBinder(_) + | ty::Pat(..) => {} + + ty::Array(..) | ty::Slice(_) | ty::Tuple(_) => { + candidates.vec.push(BuiltinCandidate); + } + + // FIXME(pin_ergonomics): should we impl `!Unpin` for coroutines or closures? + ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) => {} + + ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => {} + + ty::Infer(ty::TyVar(_)) => { + candidates.ambiguous = true; + } + + // We can make this an ICE if/once we actually instantiate the trait obligation eagerly. + ty::Bound(..) => {} + + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); + } + } + } + /// Assembles the `Sized` and `MetaSized` traits which are built-in to the language itself. #[instrument(level = "debug", skip(self, candidates))] fn assemble_builtin_sized_candidate( diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 488094b15ac60..92040b1b5d584 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -269,6 +269,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { bug!("`PointeeSized` is removing during lowering"); } Some(LangItem::Copy | LangItem::Clone) => self.copy_clone_conditions(self_ty), + Some(LangItem::Unpin) if obligation.polarity() == ty::PredicatePolarity::Negative => { + self.neg_unpin_conditions(self_ty) + } Some(LangItem::FusedIterator) => { if self.coroutine_is_gen(self_ty) { ty::Binder::dummy(vec![]) @@ -294,6 +297,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { cause, obligation.recursion_depth + 1, trait_def, + obligation.polarity(), types, ) } @@ -420,6 +424,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { cause.clone(), obligation.recursion_depth + 1, obligation.predicate.def_id(), + obligation.polarity(), constituents.types, ); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 2b563c5b8d5fa..2a751d055a33d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2240,6 +2240,52 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } } + fn neg_unpin_conditions(&mut self, self_ty: Ty<'tcx>) -> ty::Binder<'tcx, Vec>> { + match *self_ty.kind() { + ty::Array(ty, _) | ty::Slice(ty) => { + // (*) binder moved here + ty::Binder::dummy(vec![ty]) + } + ty::Tuple(tys) => { + // (*) binder moved here + ty::Binder::dummy(tys.iter().collect()) + } + + // `Unpin` types + ty::FnDef(..) + | ty::FnPtr(..) + | ty::Error(_) + | ty::Uint(_) + | ty::Int(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Ref(..) + | ty::Dynamic(..) + | ty::Str + | ty::Foreign(..) + | ty::UnsafeBinder(_) + | ty::Pat(..) => bug!("`Unpin` type cannot have `!Unpin` bound"), + + ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Infer(ty::TyVar(_)) + | ty::Bound(..) + | ty::Adt(..) + | ty::Alias(..) + | ty::Param(..) + | ty::Placeholder(..) + | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty) + } + } + } + fn coroutine_is_gen(&mut self, self_ty: Ty<'tcx>) -> bool { matches!(*self_ty.kind(), ty::Coroutine(did, ..) if self.tcx().coroutine_is_gen(did)) @@ -2389,6 +2435,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { cause: ObligationCause<'tcx>, recursion_depth: usize, trait_def_id: DefId, + polarity: ty::PredicatePolarity, types: Vec>, ) -> PredicateObligations<'tcx> { // Because the types were potentially derived from @@ -2433,7 +2480,10 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ty::TraitRef::new_from_args(tcx, trait_def_id, err_args) }; - let obligation = Obligation::new(self.tcx(), cause.clone(), param_env, trait_ref); + let trait_predicate = ty::TraitPredicate { trait_ref, polarity }; + + let obligation = + Obligation::new(self.tcx(), cause.clone(), param_env, trait_predicate); obligations.push(obligation); obligations }) diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.bar_const.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.bar_const.built.after.mir deleted file mode 100644 index 15f7446cc5912..0000000000000 --- a/tests/mir-opt/pin-ergonomics/project_pattern_match.bar_const.built.after.mir +++ /dev/null @@ -1,33 +0,0 @@ -// MIR for `bar_const` after built - -fn bar_const(_1: Pin<&Bar>) -> () { - 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)).0: T); - _2 = Pin::<&T> { pointer: move _4 }; - StorageLive(_3); - _5 = &((*(_1.0: &Bar)).1: U); - _3 = Pin::<&U> { pointer: move _5 }; - _0 = const (); - StorageDead(_3); - StorageDead(_2); - return; - } - - bb1: { - FakeRead(ForMatchedPlace(None), _1); - unreachable; - } -} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.bar_mut.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.bar_mut.built.after.mir deleted file mode 100644 index 46fd15502ffb1..0000000000000 --- a/tests/mir-opt/pin-ergonomics/project_pattern_match.bar_mut.built.after.mir +++ /dev/null @@ -1,33 +0,0 @@ -// MIR for `bar_mut` after built - -fn bar_mut(_1: Pin<&mut Bar>) -> () { - 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)).0: T); - _2 = Pin::<&mut T> { pointer: move _4 }; - StorageLive(_3); - _5 = &mut ((*(_1.0: &mut Bar)).1: U); - _3 = Pin::<&mut U> { pointer: move _5 }; - _0 = const (); - StorageDead(_3); - StorageDead(_2); - return; - } - - bb1: { - FakeRead(ForMatchedPlace(None), _1); - unreachable; - } -} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_const.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_const.built.after.mir deleted file mode 100644 index 8cfaf50a5f876..0000000000000 --- a/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_const.built.after.mir +++ /dev/null @@ -1,422 +0,0 @@ -// MIR for `baz_baz_const` after built - -fn baz_baz_const(_1: Pin<&Baz, Baz>>) -> () { - 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>))); - switchInt(move _8) -> [0: bb2, 1: bb16, otherwise: bb1]; - } - - bb1: { - FakeRead(ForMatchedPlace(None), _1); - unreachable; - } - - bb2: { - _4 = discriminant((((*(_1.0: &Baz, Baz>)) as Foo).0: Baz)); - switchInt(move _4) -> [0: bb4, 1: bb10, otherwise: bb3]; - } - - bb3: { - goto -> bb1; - } - - bb4: { - _2 = discriminant((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz)); - 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>)) as Foo).1: Baz)); - 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>)) as Bar).0: Baz)); - switchInt(move _7) -> [0: bb18, 1: bb24, otherwise: bb17]; - } - - bb17: { - goto -> bb1; - } - - bb18: { - _5 = discriminant((((*(_1.0: &Baz, Baz>)) as Bar).1: Baz)); - 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>)) as Bar).1: Baz)); - 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>)) as Bar).0: Baz) as Bar).0: T); - _65 = Pin::<&T> { pointer: move _69 }; - StorageLive(_66); - _70 = &(((((*(_1.0: &Baz, Baz>)) as Bar).0: Baz) as Bar).1: U); - _66 = Pin::<&U> { pointer: move _70 }; - StorageLive(_67); - _71 = &(((((*(_1.0: &Baz, Baz>)) as Bar).1: Baz) as Bar).0: T); - _67 = Pin::<&T> { pointer: move _71 }; - StorageLive(_68); - _72 = &(((((*(_1.0: &Baz, Baz>)) as Bar).1: Baz) 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>)) as Bar).0: Baz) as Bar).0: T); - _57 = Pin::<&T> { pointer: move _61 }; - StorageLive(_58); - _62 = &(((((*(_1.0: &Baz, Baz>)) as Bar).0: Baz) as Bar).1: U); - _58 = Pin::<&U> { pointer: move _62 }; - StorageLive(_59); - _63 = &(((((*(_1.0: &Baz, Baz>)) as Bar).1: Baz) as Foo).0: T); - _59 = Pin::<&T> { pointer: move _63 }; - StorageLive(_60); - _64 = &(((((*(_1.0: &Baz, Baz>)) as Bar).1: Baz) 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>)) as Bar).0: Baz) as Foo).0: T); - _49 = Pin::<&T> { pointer: move _53 }; - StorageLive(_50); - _54 = &(((((*(_1.0: &Baz, Baz>)) as Bar).0: Baz) as Foo).1: U); - _50 = Pin::<&U> { pointer: move _54 }; - StorageLive(_51); - _55 = &(((((*(_1.0: &Baz, Baz>)) as Bar).1: Baz) as Bar).0: T); - _51 = Pin::<&T> { pointer: move _55 }; - StorageLive(_52); - _56 = &(((((*(_1.0: &Baz, Baz>)) as Bar).1: Baz) 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>)) as Bar).0: Baz) as Foo).0: T); - _41 = Pin::<&T> { pointer: move _45 }; - StorageLive(_42); - _46 = &(((((*(_1.0: &Baz, Baz>)) as Bar).0: Baz) as Foo).1: U); - _42 = Pin::<&U> { pointer: move _46 }; - StorageLive(_43); - _47 = &(((((*(_1.0: &Baz, Baz>)) as Bar).1: Baz) as Foo).0: T); - _43 = Pin::<&T> { pointer: move _47 }; - StorageLive(_44); - _48 = &(((((*(_1.0: &Baz, Baz>)) as Bar).1: Baz) 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>)) as Foo).0: Baz) as Bar).0: T); - _33 = Pin::<&T> { pointer: move _37 }; - StorageLive(_34); - _38 = &(((((*(_1.0: &Baz, Baz>)) as Foo).0: Baz) as Bar).1: U); - _34 = Pin::<&U> { pointer: move _38 }; - StorageLive(_35); - _39 = &(((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz) as Bar).0: T); - _35 = Pin::<&T> { pointer: move _39 }; - StorageLive(_36); - _40 = &(((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz) 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>)) as Foo).0: Baz) as Bar).0: T); - _25 = Pin::<&T> { pointer: move _29 }; - StorageLive(_26); - _30 = &(((((*(_1.0: &Baz, Baz>)) as Foo).0: Baz) as Bar).1: U); - _26 = Pin::<&U> { pointer: move _30 }; - StorageLive(_27); - _31 = &(((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz) as Foo).0: T); - _27 = Pin::<&T> { pointer: move _31 }; - StorageLive(_28); - _32 = &(((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz) 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>)) as Foo).0: Baz) as Foo).0: T); - _17 = Pin::<&T> { pointer: move _21 }; - StorageLive(_18); - _22 = &(((((*(_1.0: &Baz, Baz>)) as Foo).0: Baz) as Foo).1: U); - _18 = Pin::<&U> { pointer: move _22 }; - StorageLive(_19); - _23 = &(((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz) as Bar).0: T); - _19 = Pin::<&T> { pointer: move _23 }; - StorageLive(_20); - _24 = &(((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz) 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>)) as Foo).0: Baz) as Foo).0: T); - _9 = Pin::<&T> { pointer: move _13 }; - StorageLive(_10); - _14 = &(((((*(_1.0: &Baz, Baz>)) as Foo).0: Baz) as Foo).1: U); - _10 = Pin::<&U> { pointer: move _14 }; - StorageLive(_11); - _15 = &(((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz) as Foo).0: T); - _11 = Pin::<&T> { pointer: move _15 }; - StorageLive(_12); - _16 = &(((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz) as Foo).1: U); - _12 = Pin::<&U> { pointer: move _16 }; - _0 = const (); - StorageDead(_12); - StorageDead(_11); - StorageDead(_10); - StorageDead(_9); - goto -> bb37; - } - - bb37: { - return; - } -} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_mut.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_mut.built.after.mir deleted file mode 100644 index 43c523cbf5717..0000000000000 --- a/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_mut.built.after.mir +++ /dev/null @@ -1,422 +0,0 @@ -// MIR for `baz_baz_mut` after built - -fn baz_baz_mut(_1: Pin<&mut Baz, Baz>>) -> () { - 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>))); - switchInt(move _8) -> [0: bb2, 1: bb16, otherwise: bb1]; - } - - bb1: { - FakeRead(ForMatchedPlace(None), _1); - unreachable; - } - - bb2: { - _4 = discriminant((((*(_1.0: &mut Baz, Baz>)) as Foo).0: Baz)); - switchInt(move _4) -> [0: bb4, 1: bb10, otherwise: bb3]; - } - - bb3: { - goto -> bb1; - } - - bb4: { - _2 = discriminant((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz)); - 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>)) as Foo).1: Baz)); - 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>)) as Bar).0: Baz)); - switchInt(move _7) -> [0: bb18, 1: bb24, otherwise: bb17]; - } - - bb17: { - goto -> bb1; - } - - bb18: { - _5 = discriminant((((*(_1.0: &mut Baz, Baz>)) as Bar).1: Baz)); - 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>)) as Bar).1: Baz)); - 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>)) as Bar).0: Baz) as Bar).0: T); - _65 = Pin::<&mut T> { pointer: move _69 }; - StorageLive(_66); - _70 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).0: Baz) as Bar).1: U); - _66 = Pin::<&mut U> { pointer: move _70 }; - StorageLive(_67); - _71 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).1: Baz) as Bar).0: T); - _67 = Pin::<&mut T> { pointer: move _71 }; - StorageLive(_68); - _72 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).1: Baz) 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>)) as Bar).0: Baz) as Bar).0: T); - _57 = Pin::<&mut T> { pointer: move _61 }; - StorageLive(_58); - _62 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).0: Baz) as Bar).1: U); - _58 = Pin::<&mut U> { pointer: move _62 }; - StorageLive(_59); - _63 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).1: Baz) as Foo).0: T); - _59 = Pin::<&mut T> { pointer: move _63 }; - StorageLive(_60); - _64 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).1: Baz) 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>)) as Bar).0: Baz) as Foo).0: T); - _49 = Pin::<&mut T> { pointer: move _53 }; - StorageLive(_50); - _54 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).0: Baz) as Foo).1: U); - _50 = Pin::<&mut U> { pointer: move _54 }; - StorageLive(_51); - _55 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).1: Baz) as Bar).0: T); - _51 = Pin::<&mut T> { pointer: move _55 }; - StorageLive(_52); - _56 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).1: Baz) 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>)) as Bar).0: Baz) as Foo).0: T); - _41 = Pin::<&mut T> { pointer: move _45 }; - StorageLive(_42); - _46 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).0: Baz) as Foo).1: U); - _42 = Pin::<&mut U> { pointer: move _46 }; - StorageLive(_43); - _47 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).1: Baz) as Foo).0: T); - _43 = Pin::<&mut T> { pointer: move _47 }; - StorageLive(_44); - _48 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).1: Baz) 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>)) as Foo).0: Baz) as Bar).0: T); - _33 = Pin::<&mut T> { pointer: move _37 }; - StorageLive(_34); - _38 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).0: Baz) as Bar).1: U); - _34 = Pin::<&mut U> { pointer: move _38 }; - StorageLive(_35); - _39 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz) as Bar).0: T); - _35 = Pin::<&mut T> { pointer: move _39 }; - StorageLive(_36); - _40 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz) 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>)) as Foo).0: Baz) as Bar).0: T); - _25 = Pin::<&mut T> { pointer: move _29 }; - StorageLive(_26); - _30 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).0: Baz) as Bar).1: U); - _26 = Pin::<&mut U> { pointer: move _30 }; - StorageLive(_27); - _31 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz) as Foo).0: T); - _27 = Pin::<&mut T> { pointer: move _31 }; - StorageLive(_28); - _32 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz) 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>)) as Foo).0: Baz) as Foo).0: T); - _17 = Pin::<&mut T> { pointer: move _21 }; - StorageLive(_18); - _22 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).0: Baz) as Foo).1: U); - _18 = Pin::<&mut U> { pointer: move _22 }; - StorageLive(_19); - _23 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz) as Bar).0: T); - _19 = Pin::<&mut T> { pointer: move _23 }; - StorageLive(_20); - _24 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz) 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>)) as Foo).0: Baz) as Foo).0: T); - _9 = Pin::<&mut T> { pointer: move _13 }; - StorageLive(_10); - _14 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).0: Baz) as Foo).1: U); - _10 = Pin::<&mut U> { pointer: move _14 }; - StorageLive(_11); - _15 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz) as Foo).0: T); - _11 = Pin::<&mut T> { pointer: move _15 }; - StorageLive(_12); - _16 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz) 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; - } -} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_const.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_const.built.after.mir deleted file mode 100644 index 5538449cc43cc..0000000000000 --- a/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_const.built.after.mir +++ /dev/null @@ -1,76 +0,0 @@ -// MIR for `baz_const` after built - -fn baz_const(_1: Pin<&Baz>) -> () { - 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))); - 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)) as Bar).0: T); - _7 = Pin::<&T> { pointer: move _9 }; - StorageLive(_8); - _10 = &(((*(_1.0: &Baz)) 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)) as Foo).0: T); - _3 = Pin::<&T> { pointer: move _5 }; - StorageLive(_4); - _6 = &(((*(_1.0: &Baz)) as Foo).1: U); - _4 = Pin::<&U> { pointer: move _6 }; - _0 = const (); - StorageDead(_4); - StorageDead(_3); - goto -> bb7; - } - - bb7: { - return; - } -} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_mut.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_mut.built.after.mir deleted file mode 100644 index 4ae472cba3a58..0000000000000 --- a/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_mut.built.after.mir +++ /dev/null @@ -1,76 +0,0 @@ -// MIR for `baz_mut` after built - -fn baz_mut(_1: Pin<&mut Baz>) -> () { - 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))); - 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)) as Bar).0: T); - _7 = Pin::<&mut T> { pointer: move _9 }; - StorageLive(_8); - _10 = &mut (((*(_1.0: &mut Baz)) 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)) as Foo).0: T); - _3 = Pin::<&mut T> { pointer: move _5 }; - StorageLive(_4); - _6 = &mut (((*(_1.0: &mut Baz)) as Foo).1: U); - _4 = Pin::<&mut U> { pointer: move _6 }; - _0 = const (); - StorageDead(_4); - StorageDead(_3); - goto -> bb7; - } - - bb7: { - return; - } -} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_const.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_const.built.after.mir deleted file mode 100644 index 8b397ffd18142..0000000000000 --- a/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_const.built.after.mir +++ /dev/null @@ -1,47 +0,0 @@ -// MIR for `foo_bar_const` after built - -fn foo_bar_const(_1: Pin<&Foo, Bar>>) -> () { - 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>)).0: Bar).0: T); - _2 = Pin::<&T> { pointer: move _6 }; - StorageLive(_3); - _7 = &(((*(_1.0: &Foo, Bar>)).0: Bar).1: U); - _3 = Pin::<&U> { pointer: move _7 }; - StorageLive(_4); - _8 = &(((*(_1.0: &Foo, Bar>)).1: Bar).0: T); - _4 = Pin::<&T> { pointer: move _8 }; - StorageLive(_5); - _9 = &(((*(_1.0: &Foo, Bar>)).1: Bar).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; - } -} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_mut.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_mut.built.after.mir deleted file mode 100644 index 2e8128bb9d1e4..0000000000000 --- a/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_mut.built.after.mir +++ /dev/null @@ -1,47 +0,0 @@ -// MIR for `foo_bar_mut` after built - -fn foo_bar_mut(_1: Pin<&mut Foo, Bar>>) -> () { - 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>)).0: Bar).0: T); - _2 = Pin::<&mut T> { pointer: move _6 }; - StorageLive(_3); - _7 = &mut (((*(_1.0: &mut Foo, Bar>)).0: Bar).1: U); - _3 = Pin::<&mut U> { pointer: move _7 }; - StorageLive(_4); - _8 = &mut (((*(_1.0: &mut Foo, Bar>)).1: Bar).0: T); - _4 = Pin::<&mut T> { pointer: move _8 }; - StorageLive(_5); - _9 = &mut (((*(_1.0: &mut Foo, Bar>)).1: Bar).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; - } -} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_const.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_const.built.after.mir deleted file mode 100644 index b77b341d4ef76..0000000000000 --- a/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_const.built.after.mir +++ /dev/null @@ -1,33 +0,0 @@ -// MIR for `foo_const` after built - -fn foo_const(_1: Pin<&Foo>) -> () { - 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)).0: T); - _2 = Pin::<&T> { pointer: move _4 }; - StorageLive(_3); - _5 = &((*(_1.0: &Foo)).1: U); - _3 = Pin::<&U> { pointer: move _5 }; - _0 = const (); - StorageDead(_3); - StorageDead(_2); - return; - } - - bb1: { - FakeRead(ForMatchedPlace(None), _1); - unreachable; - } -} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_mut.built.after.mir b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_mut.built.after.mir deleted file mode 100644 index c7b88d239f87a..0000000000000 --- a/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_mut.built.after.mir +++ /dev/null @@ -1,33 +0,0 @@ -// MIR for `foo_mut` after built - -fn foo_mut(_1: Pin<&mut Foo>) -> () { - 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)).0: T); - _2 = Pin::<&mut T> { pointer: move _4 }; - StorageLive(_3); - _5 = &mut ((*(_1.0: &mut Foo)).1: U); - _3 = Pin::<&mut U> { pointer: move _5 }; - _0 = const (); - StorageDead(_3); - StorageDead(_2); - return; - } - - bb1: { - FakeRead(ForMatchedPlace(None), _1); - unreachable; - } -} diff --git a/tests/mir-opt/pin-ergonomics/project_pattern_match.rs b/tests/mir-opt/pin-ergonomics/project_pattern_match.rs deleted file mode 100644 index 8808111f303b3..0000000000000 --- a/tests/mir-opt/pin-ergonomics/project_pattern_match.rs +++ /dev/null @@ -1,95 +0,0 @@ -// 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 { - x: T, - y: U, -} - -struct Bar(T, U); - -enum Baz { - Foo(T, U), - Bar { x: T, y: U }, -} - -// EMIT_MIR project_pattern_match.foo_mut.built.after.mir -fn foo_mut(foo: &pin mut Foo) { - let Foo { x, y } = foo; -} - -// EMIT_MIR project_pattern_match.foo_const.built.after.mir -fn foo_const(foo: &pin const Foo) { - let Foo { x, y } = foo; -} - -// EMIT_MIR project_pattern_match.bar_mut.built.after.mir -fn bar_mut(bar: &pin mut Bar) { - let Bar(x, y) = bar; -} - -// EMIT_MIR project_pattern_match.bar_const.built.after.mir -fn bar_const(bar: &pin const Bar) { - let Bar(x, y) = bar; -} - -// EMIT_MIR project_pattern_match.foo_bar_mut.built.after.mir -fn foo_bar_mut(foo: &pin mut Foo, Bar>) { - 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(foo: &pin const Foo, Bar>) { - let Foo { x: Bar(x, y), y: Bar(z, w) } = foo; -} - -// EMIT_MIR project_pattern_match.baz_mut.built.after.mir -fn baz_mut(baz: &pin mut Baz) { - match baz { - Baz::Foo(x, y) => {} - Baz::Bar { x, y } => {} - } -} - -// EMIT_MIR project_pattern_match.baz_const.built.after.mir -fn baz_const(baz: &pin const Baz) { - 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(baz: &pin mut Baz, Baz>) { - 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(baz: &pin const Baz, Baz>) { - 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() {} diff --git a/tests/ui/pin-ergonomics/pattern-matching.normal.stderr b/tests/ui/pin-ergonomics/pattern-matching.normal.stderr index 7aaa51e81ed90..5e91fae18cca5 100644 --- a/tests/ui/pin-ergonomics/pattern-matching.normal.stderr +++ b/tests/ui/pin-ergonomics/pattern-matching.normal.stderr @@ -1,8 +1,8 @@ error[E0308]: mismatched types - --> $DIR/pattern-matching.rs:35:9 + --> $DIR/pattern-matching.rs:41:9 | -LL | let Foo { x, y } = foo; - | ^^^^^^^^^^^^ --- this expression has type `Pin<&mut Foo>` +LL | let Foo { x, y } = foo_mut; + | ^^^^^^^^^^^^ ------- this expression has type `Pin<&mut Foo>` | | | expected `Pin<&mut Foo>`, found `Foo<_, _>` | @@ -10,14 +10,14 @@ LL | let Foo { x, y } = foo; found struct `Foo<_, _>` help: consider dereferencing to access the inner value using the Deref trait | -LL | let Foo { x, y } = *foo; +LL | let Foo { x, y } = *foo_mut; | + error[E0308]: mismatched types - --> $DIR/pattern-matching.rs:42:9 + --> $DIR/pattern-matching.rs:46:9 | -LL | let Foo { x, y } = foo; - | ^^^^^^^^^^^^ --- this expression has type `Pin<&Foo>` +LL | let Foo { x, y } = foo_const; + | ^^^^^^^^^^^^ --------- this expression has type `Pin<&Foo>` | | | expected `Pin<&Foo>`, found `Foo<_, _>` | @@ -25,289 +25,184 @@ LL | let Foo { x, y } = foo; found struct `Foo<_, _>` help: consider dereferencing to access the inner value using the Deref trait | -LL | let Foo { x, y } = *foo; +LL | let Foo { x, y } = *foo_const; | + error[E0308]: mismatched types - --> $DIR/pattern-matching.rs:49:9 + --> $DIR/pattern-matching.rs:54:9 | -LL | let Bar(x, y) = bar; - | ^^^^^^^^^ --- this expression has type `Pin<&mut Bar>` +LL | let Foo { x, .. } = foo_mut; + | ^^^^^^^^^^^^^ ------- this expression has type `Pin<&mut Foo>` | | - | expected `Pin<&mut Bar>`, found `Bar<_, _>` - | - = note: expected struct `Pin<&mut Bar>` - 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>` - | | - | expected `Pin<&Bar>`, found `Bar<_, _>` - | - = note: expected struct `Pin<&Bar>` - 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>>` - | | - | expected `Pin<&mut Foo, Bar>>`, found `Foo<_, _>` + | expected `Pin<&mut Foo>`, found `Foo<_, _>` | - = note: expected struct `Pin<&mut Foo, Bar>>` + = note: expected struct `Pin<&mut Foo>` 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; - | + +LL | let Foo { x, .. } = *foo_mut; + | + error[E0308]: mismatched types - --> $DIR/pattern-matching.rs:72:9 + --> $DIR/pattern-matching.rs:58:9 | -LL | let Foo { x: Bar(x, y), y: Bar(z, w) } = foo; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --- this expression has type `Pin<&Foo, Bar>>` +LL | let Foo { x, .. } = foo_const; + | ^^^^^^^^^^^^^ --------- this expression has type `Pin<&Foo>` | | - | expected `Pin<&Foo, Bar>>`, found `Foo<_, _>` + | expected `Pin<&Foo>`, found `Foo<_, _>` | - = note: expected struct `Pin<&Foo, Bar>>` + = note: expected struct `Pin<&Foo>` 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>` -LL | Baz::Foo(x, y) => { - | ^^^^^^^^^^^^^^ expected `Pin<&mut Baz>`, found `Baz<_, _>` - | - = note: expected struct `Pin<&mut Baz>` - found enum `Baz<_, _>` -help: consider dereferencing to access the inner value using the Deref trait - | -LL | match *baz { - | + +LL | let Foo { x, .. } = *foo_const; + | + error[E0308]: mismatched types - --> $DIR/pattern-matching.rs:87:9 - | -LL | match baz { - | --- this expression has type `Pin<&mut Baz>` -... -LL | Baz::Bar { x, y } => { - | ^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz>`, found `Baz<_, _>` - | - = note: expected struct `Pin<&mut Baz>` - found enum `Baz<_, _>` -help: consider dereferencing to access the inner value using the Deref trait + --> $DIR/pattern-matching.rs:68:9 | -LL | match *baz { - | + - -error[E0308]: mismatched types - --> $DIR/pattern-matching.rs:97:9 - | -LL | match baz { - | --- this expression has type `Pin<&Baz>` -LL | Baz::Foo(x, y) => { - | ^^^^^^^^^^^^^^ expected `Pin<&Baz>`, found `Baz<_, _>` +LL | let NegUnpinFoo { x, y } = foo_mut; + | ^^^^^^^^^^^^^^^^^^^^ ------- this expression has type `Pin<&mut NegUnpinFoo>` + | | + | expected `Pin<&mut NegUnpinFoo>`, found `NegUnpinFoo<_, _>` | - = note: expected struct `Pin<&Baz>` - found enum `Baz<_, _>` + = note: expected struct `Pin<&mut NegUnpinFoo>` + found struct `NegUnpinFoo<_, _>` help: consider dereferencing to access the inner value using the Deref trait | -LL | match *baz { - | + +LL | let NegUnpinFoo { x, y } = *foo_mut; + | + error[E0308]: mismatched types - --> $DIR/pattern-matching.rs:102:9 + --> $DIR/pattern-matching.rs:73:9 | -LL | match baz { - | --- this expression has type `Pin<&Baz>` -... -LL | Baz::Bar { x, y } => { - | ^^^^^^^^^^^^^^^^^ expected `Pin<&Baz>`, found `Baz<_, _>` +LL | let NegUnpinFoo { x, y } = foo_const; + | ^^^^^^^^^^^^^^^^^^^^ --------- this expression has type `Pin<&NegUnpinFoo>` + | | + | expected `Pin<&NegUnpinFoo>`, found `NegUnpinFoo<_, _>` | - = note: expected struct `Pin<&Baz>` - found enum `Baz<_, _>` + = note: expected struct `Pin<&NegUnpinFoo>` + found struct `NegUnpinFoo<_, _>` help: consider dereferencing to access the inner value using the Deref trait | -LL | match *baz { - | + +LL | let NegUnpinFoo { x, y } = *foo_const; + | + error[E0308]: mismatched types - --> $DIR/pattern-matching.rs:112:9 + --> $DIR/pattern-matching.rs:85:9 | -LL | match baz { - | --- this expression has type `Pin<&mut Baz, Baz>>` -LL | Baz::Foo(Baz::Foo(x, y), Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz, Baz>>`, found `Baz<_, _>` +LL | match bar_mut { + | ------- this expression has type `Pin<&mut NegUnpinBar>` +LL | NegUnpinBar::Foo(x, y) => { + | ^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut NegUnpinBar>`, found `NegUnpinBar<_, _>` | - = note: expected struct `Pin<&mut Baz, Baz>>` - found enum `Baz<_, _>` + = note: expected struct `Pin<&mut NegUnpinBar>` + found enum `NegUnpinBar<_, _>` help: consider dereferencing to access the inner value using the Deref trait | -LL | match *baz { +LL | match *bar_mut { | + error[E0308]: mismatched types - --> $DIR/pattern-matching.rs:119:9 + --> $DIR/pattern-matching.rs:90:18 | -LL | match baz { - | --- this expression has type `Pin<&mut Baz, Baz>>` -... -LL | Baz::Foo(Baz::Bar { x, y }, Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz, Baz>>`, found `Baz<_, _>` +LL | _ if let NegUnpinBar::Bar { x, y } = bar_mut => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ ------- this expression has type `Pin<&mut NegUnpinBar>` + | | + | expected `Pin<&mut NegUnpinBar>`, found `NegUnpinBar<_, _>` | - = note: expected struct `Pin<&mut Baz, Baz>>` - found enum `Baz<_, _>` + = note: expected struct `Pin<&mut NegUnpinBar>` + found enum `NegUnpinBar<_, _>` help: consider dereferencing to access the inner value using the Deref trait | -LL | match *baz { - | + +LL | _ if let NegUnpinBar::Bar { x, y } = *bar_mut => { + | + error[E0308]: mismatched types - --> $DIR/pattern-matching.rs:126:9 + --> $DIR/pattern-matching.rs:98:9 | -LL | match baz { - | --- this expression has type `Pin<&mut Baz, Baz>>` -... -LL | Baz::Bar { x: Baz::Foo(x, y), y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz, Baz>>`, found `Baz<_, _>` +LL | match bar_const { + | --------- this expression has type `Pin<&NegUnpinBar>` +LL | NegUnpinBar::Bar { x, y } => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&NegUnpinBar>`, found `NegUnpinBar<_, _>` | - = note: expected struct `Pin<&mut Baz, Baz>>` - found enum `Baz<_, _>` + = note: expected struct `Pin<&NegUnpinBar>` + found enum `NegUnpinBar<_, _>` help: consider dereferencing to access the inner value using the Deref trait | -LL | match *baz { +LL | match *bar_const { | + error[E0308]: mismatched types - --> $DIR/pattern-matching.rs:133:9 + --> $DIR/pattern-matching.rs:103:18 | -LL | match baz { - | --- this expression has type `Pin<&mut Baz, Baz>>` -... -LL | Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz, Baz>>`, found `Baz<_, _>` +LL | _ if let NegUnpinBar::Foo(x, y) = bar_const => { + | ^^^^^^^^^^^^^^^^^^^^^^ --------- this expression has type `Pin<&NegUnpinBar>` + | | + | expected `Pin<&NegUnpinBar>`, found `NegUnpinBar<_, _>` | - = note: expected struct `Pin<&mut Baz, Baz>>` - found enum `Baz<_, _>` + = note: expected struct `Pin<&NegUnpinBar>` + found enum `NegUnpinBar<_, _>` help: consider dereferencing to access the inner value using the Deref trait | -LL | match *baz { - | + +LL | _ if let NegUnpinBar::Foo(x, y) = *bar_const => { + | + error[E0308]: mismatched types - --> $DIR/pattern-matching.rs:145:9 + --> $DIR/pattern-matching.rs:116:9 | -LL | match baz { - | --- this expression has type `Pin<&Baz, Baz>>` -LL | Baz::Foo(foo, _) if let Baz::Foo(x, y) = foo => { - | ^^^^^^^^^^^^^^^^ expected `Pin<&Baz, Baz>>`, found `Baz<_, _>` +LL | let (NegUnpinFoo { x, y },) = foo_mut; + | ^^^^^^^^^^^^^^^^^^^^^^^ ------- this expression has type `Pin<&mut (NegUnpinFoo,)>` + | | + | expected `Pin<&mut (NegUnpinFoo,)>`, found `(_,)` | - = note: expected struct `Pin<&Baz, Baz>>` - found enum `Baz<_, _>` + = note: expected struct `Pin<&mut (NegUnpinFoo,)>` + found tuple `(_,)` help: consider dereferencing to access the inner value using the Deref trait | -LL | match *baz { - | + +LL | let (NegUnpinFoo { x, y },) = *foo_mut; + | + error[E0308]: mismatched types - --> $DIR/pattern-matching.rs:150:9 + --> $DIR/pattern-matching.rs:120:9 | -LL | match baz { - | --- this expression has type `Pin<&Baz, Baz>>` -... -LL | Baz::Bar { x: _, y: bar } if let Baz::Bar { x, y } = bar => { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz, Baz>>`, found `Baz<_, _>` +LL | let (NegUnpinFoo { x, y },) = foo_const; + | ^^^^^^^^^^^^^^^^^^^^^^^ --------- this expression has type `Pin<&(NegUnpinFoo,)>` + | | + | expected `Pin<&(NegUnpinFoo,)>`, found `(_,)` | - = note: expected struct `Pin<&Baz, Baz>>` - found enum `Baz<_, _>` + = note: expected struct `Pin<&(NegUnpinFoo,)>` + found tuple `(_,)` help: consider dereferencing to access the inner value using the Deref trait | -LL | match *baz { - | + +LL | let (NegUnpinFoo { x, y },) = *foo_const; + | + -error[E0308]: mismatched types - --> $DIR/pattern-matching.rs:155:9 - | -LL | match baz { - | --- this expression has type `Pin<&Baz, Baz>>` -... -LL | Baz::Foo(Baz::Foo(x, y), Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz, Baz>>`, found `Baz<_, _>` - | - = note: expected struct `Pin<&Baz, Baz>>` - found enum `Baz<_, _>` -help: consider dereferencing to access the inner value using the Deref trait +error[E0529]: expected an array or slice, found `Pin<&mut [NegUnpinFoo; 1]>` + --> $DIR/pattern-matching.rs:130:9 | -LL | match *baz { - | + +LL | let [NegUnpinFoo { x, y }] = foo_mut; + | ^^^^^^^^^^^^^^^^^^^^^^ pattern cannot match with input type `Pin<&mut [NegUnpinFoo; 1]>` -error[E0308]: mismatched types - --> $DIR/pattern-matching.rs:162:9 - | -LL | match baz { - | --- this expression has type `Pin<&Baz, Baz>>` -... -LL | Baz::Foo(Baz::Bar { x, y }, Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz, Baz>>`, found `Baz<_, _>` - | - = note: expected struct `Pin<&Baz, Baz>>` - found enum `Baz<_, _>` -help: consider dereferencing to access the inner value using the Deref trait +error[E0529]: expected an array or slice, found `Pin<&[NegUnpinFoo; 1]>` + --> $DIR/pattern-matching.rs:134:9 | -LL | match *baz { - | + +LL | let [NegUnpinFoo { x, y }] = foo_const; + | ^^^^^^^^^^^^^^^^^^^^^^ pattern cannot match with input type `Pin<&[NegUnpinFoo; 1]>` -error[E0308]: mismatched types - --> $DIR/pattern-matching.rs:169:9 - | -LL | match baz { - | --- this expression has type `Pin<&Baz, Baz>>` -... -LL | Baz::Bar { x: Baz::Foo(x, y), y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz, Baz>>`, found `Baz<_, _>` +error[E0529]: expected an array or slice, found `Pin<&mut [NegUnpinFoo]>` + --> $DIR/pattern-matching.rs:144:12 | - = note: expected struct `Pin<&Baz, Baz>>` - found enum `Baz<_, _>` -help: consider dereferencing to access the inner value using the Deref trait - | -LL | match *baz { - | + +LL | if let [NegUnpinFoo { x, y }] = foo_mut { + | ^^^^^^^^^^^^^^^^^^^^^^ pattern cannot match with input type `Pin<&mut [NegUnpinFoo]>` -error[E0308]: mismatched types - --> $DIR/pattern-matching.rs:176:9 +error[E0529]: expected an array or slice, found `Pin<&[NegUnpinFoo]>` + --> $DIR/pattern-matching.rs:149:12 | -LL | match baz { - | --- this expression has type `Pin<&Baz, Baz>>` -... -LL | Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz, Baz>>`, found `Baz<_, _>` - | - = note: expected struct `Pin<&Baz, Baz>>` - found enum `Baz<_, _>` -help: consider dereferencing to access the inner value using the Deref trait - | -LL | match *baz { - | + +LL | if let [NegUnpinFoo { x, y }] = foo_const { + | ^^^^^^^^^^^^^^^^^^^^^^ pattern cannot match with input type `Pin<&[NegUnpinFoo]>` -error: aborting due to 20 previous errors +error: aborting due to 16 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0308, E0529. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/pin-ergonomics/pattern-matching.rs b/tests/ui/pin-ergonomics/pattern-matching.rs index e480ebfc00626..42cb86d7fdc6f 100644 --- a/tests/ui/pin-ergonomics/pattern-matching.rs +++ b/tests/ui/pin-ergonomics/pattern-matching.rs @@ -2,27 +2,32 @@ //@ edition:2024 //@[pin_ergonomics] check-pass #![cfg_attr(pin_ergonomics, feature(pin_ergonomics))] -#![feature(if_let_guard)] +#![feature(if_let_guard, negative_impls)] #![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. +// This test verifies that a `&pin mut T` can be projected to a pinned +// reference field `&pin mut T.U` when `T: !Unpin` or when `U: Unpin`. struct Foo { x: T, y: U, } -struct Bar(T, U); +struct NegUnpinFoo { + x: T, + y: U, +} -enum Baz { +enum NegUnpinBar { Foo(T, U), Bar { x: T, y: U }, } +impl !Unpin for NegUnpinFoo {} +impl !Unpin for NegUnpinBar {} + trait IsPinMut {} trait IsPinConst {} impl IsPinMut for Pin<&mut T> {} @@ -31,155 +36,120 @@ impl IsPinConst for Pin<&T> {} fn assert_pin_mut(_: T) {} fn assert_pin_const(_: T) {} -fn foo_mut(foo: Pin<&mut Foo>) { - let Foo { x, y } = foo; +// Pinned references can be projected to pinned references of `Unpin` fields +fn unpin2unpin(foo_mut: Pin<&mut Foo>, foo_const: Pin<&Foo>) { + let Foo { x, y } = foo_mut; //[normal]~^ ERROR mismatched types assert_pin_mut(x); assert_pin_mut(y); -} -fn foo_const(foo: Pin<&Foo>) { - let Foo { x, y } = foo; + let Foo { x, y } = foo_const; //[normal]~^ ERROR mismatched types assert_pin_const(x); assert_pin_const(y); } -fn bar_mut(bar: Pin<&mut Bar>) { - let Bar(x, y) = bar; +// Pinned references can be only projected to pinned references of `Unpin` fields +fn unpin2partial_unpin(foo_mut: Pin<&mut Foo>, foo_const: Pin<&Foo>) { + let Foo { x, .. } = foo_mut; //[normal]~^ ERROR mismatched types assert_pin_mut(x); - assert_pin_mut(y); -} -fn bar_const(bar: Pin<&Bar>) { - let Bar(x, y) = bar; + let Foo { x, .. } = foo_const; //[normal]~^ ERROR mismatched types assert_pin_const(x); - assert_pin_const(y); } -fn foo_bar_mut(foo: Pin<&mut Foo, Bar>>) { - let Foo { x: Bar(x, y), y: Bar(z, w) } = foo; +// Pinned references of `!Unpin` types can be projected to pinned references +fn neg_unpin2not_unpin( + foo_mut: Pin<&mut NegUnpinFoo>, + foo_const: Pin<&NegUnpinFoo>, +) { + let NegUnpinFoo { x, y } = foo_mut; //[normal]~^ ERROR mismatched types assert_pin_mut(x); assert_pin_mut(y); - assert_pin_mut(z); - assert_pin_mut(w); -} -fn foo_bar_const(foo: Pin<&Foo, Bar>>) { - let Foo { x: Bar(x, y), y: Bar(z, w) } = foo; + let NegUnpinFoo { x, y } = foo_const; //[normal]~^ ERROR mismatched types assert_pin_const(x); assert_pin_const(y); - assert_pin_const(z); - assert_pin_const(w); } -fn baz_mut(baz: Pin<&mut Baz>) { - match baz { - Baz::Foo(x, y) => { +// Pinned references of `!Unpin` types can be projected to pinned references of `Unpin` fields +fn neg_unpin2unpin( + bar_mut: Pin<&mut NegUnpinBar>, + bar_const: Pin<&NegUnpinBar>, +) { + match bar_mut { + NegUnpinBar::Foo(x, y) => { //[normal]~^ ERROR mismatched types assert_pin_mut(x); assert_pin_mut(y); } - Baz::Bar { x, y } => { + _ if let NegUnpinBar::Bar { x, y } = bar_mut => { //[normal]~^ ERROR mismatched types assert_pin_mut(x); assert_pin_mut(y); } + _ => {} } -} - -fn baz_const(baz: Pin<&Baz>) { - match baz { - Baz::Foo(x, y) => { + match bar_const { + NegUnpinBar::Bar { x, y } => { //[normal]~^ ERROR mismatched types assert_pin_const(x); assert_pin_const(y); } - Baz::Bar { x, y } => { + _ if let NegUnpinBar::Foo(x, y) = bar_const => { //[normal]~^ ERROR mismatched types assert_pin_const(x); assert_pin_const(y); } + _ => {} } } -fn baz_baz_mut(baz: Pin<&mut Baz, Baz>>) { - 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 neg_unpin_tuple( + foo_mut: Pin<&mut (NegUnpinFoo,)>, + foo_const: Pin<&(NegUnpinFoo,)>, +) { + let (NegUnpinFoo { x, y },) = foo_mut; + //[normal]~^ ERROR mismatched types + assert_pin_mut(x); + assert_pin_mut(y); + let (NegUnpinFoo { x, y },) = foo_const; + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_pin_const(y); } -fn baz_baz_const(baz: Pin<&Baz, Baz>>) { - 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 neg_unpin_array( + foo_mut: Pin<&mut [NegUnpinFoo; 1]>, + foo_const: Pin<&[NegUnpinFoo; 1]>, +) { + let [NegUnpinFoo { x, y }] = foo_mut; + //[normal]~^ ERROR expected an array or slice, found `Pin<&mut [NegUnpinFoo; 1]>` + assert_pin_mut(x); + assert_pin_mut(y); + let [NegUnpinFoo { x, y }] = foo_const; + //[normal]~^ ERROR expected an array or slice, found `Pin<&[NegUnpinFoo; 1]>` + assert_pin_const(x); + assert_pin_const(y); +} + +fn neg_unpin_slice( + foo_mut: Pin<&mut [NegUnpinFoo]>, + foo_const: Pin<&[NegUnpinFoo]>, +) { + if let [NegUnpinFoo { x, y }] = foo_mut { + //[normal]~^ ERROR expected an array or slice, found `Pin<&mut [NegUnpinFoo]>` + assert_pin_mut(x); + assert_pin_mut(y); + } + if let [NegUnpinFoo { x, y }] = foo_const { + //[normal]~^ ERROR expected an array or slice, found `Pin<&[NegUnpinFoo]>` + assert_pin_const(x); + assert_pin_const(y); } } diff --git a/tests/ui/pin-ergonomics/projection-unpin-checks.rs b/tests/ui/pin-ergonomics/projection-unpin-checks.rs new file mode 100644 index 0000000000000..3a7c4f04c6903 --- /dev/null +++ b/tests/ui/pin-ergonomics/projection-unpin-checks.rs @@ -0,0 +1,132 @@ +//@ edition:2024 +#![feature(pin_ergonomics, negative_impls)] +#![allow(incomplete_features)] + +// This test verifies that a `&pin mut T` cannot be projected to a pinned +// reference field `&pin mut T.U` if neither `T: !Unpin` nor `U: Unpin`. + +struct Foo(T); +struct NotUnpinFoo(T, std::marker::PhantomPinned); +struct NegUnpinFoo(T); + +impl !Unpin for NegUnpinFoo {} + +fn unpin2not_unpin(foo_mut: &pin mut Foo, foo_const: &pin const Foo) { + let Foo(_x) = foo_mut; //~ ERROR the trait bound `Foo: !Unpin` is not satisfied [E0277] + let Foo(_x) = foo_const; //~ ERROR the trait bound `Foo: !Unpin` is not satisfied [E0277] + let Foo(_x) = (|| foo_mut)(); //~ ERROR the trait bound `Foo: !Unpin` is not satisfied [E0277] + let Foo(_x) = (|| foo_const)(); //~ ERROR the trait bound `Foo: !Unpin` is not satisfied [E0277] + let &mut _foo_mut = foo_mut; //~ ERROR mismatched types + let &_foo_const = foo_const; //~ ERROR mismatched types + // FIXME(pin_ergonomics): add these tests since `&pin` pattern is ready + // let &pin mut _foo_mut = foo_mut; // error + // let &pin mut _foo_const = foo_const; // error +} + +fn unpin2unpin(foo_mut: &pin mut Foo, foo_const: &pin const Foo) { + let Foo(_x) = foo_mut; // ok + let Foo(_x) = foo_const; // ok + let Foo(_x) = (|| foo_mut)(); // ok + let Foo(_x) = (|| foo_const)(); // ok + let &mut _foo_mut = foo_mut; //~ ERROR mismatched types + let &_foo_const = foo_const; //~ ERROR mismatched types + // FIXME(pin_ergonomics): add these tests since `&pin` pattern is ready + // let &pin mut _foo_mut = foo_mut; // ok + // let &pin mut _foo_const = foo_const; // ok +} + +fn not_unpin2not_unpin(foo_mut: &pin mut NotUnpinFoo, foo_const: &pin const NotUnpinFoo) { + let NotUnpinFoo(_x, _) = foo_mut; //~ ERROR the trait bound `NotUnpinFoo: !Unpin` is not satisfied [E0277] + let NotUnpinFoo(_x, _) = foo_const; //~ ERROR the trait bound `NotUnpinFoo: !Unpin` is not satisfied [E0277] + let NotUnpinFoo(_x, _) = (|| foo_mut)(); //~ ERROR the trait bound `NotUnpinFoo: !Unpin` is not satisfied [E0277] + let NotUnpinFoo(_x, _) = (|| foo_const)(); //~ ERROR the trait bound `NotUnpinFoo: !Unpin` is not satisfied [E0277] + let &mut _foo_mut = foo_mut; //~ ERROR mismatched types + let &_foo_const = foo_const; //~ ERROR mismatched types + // FIXME(pin_ergonomics): add these tests since `&pin` pattern is ready + // let &pin mut _foo_mut = foo_mut; // error + // let &pin mut _foo_const = foo_const; // error +} + +fn not_unpin2unpin( + foo_mut: &pin mut NotUnpinFoo, + foo_const: &pin const NotUnpinFoo, +) { + let NotUnpinFoo(_x, _) = foo_mut; // ok + let NotUnpinFoo(_x, _) = foo_const; // ok + let NotUnpinFoo(_x, _) = (|| foo_mut)(); // ok + let NotUnpinFoo(_x, _) = (|| foo_const)(); // ok + let &mut _foo_mut = foo_mut; //~ ERROR mismatched types + let &_foo_const = foo_const; //~ ERROR mismatched types + // FIXME(pin_ergonomics): add these tests since `&pin` pattern is ready + // let &pin mut _foo_mut = foo_mut; // ok + // let &pin mut _foo_const = foo_const; // ok +} + +fn neg_unpin2not_unpin(foo_mut: &pin mut NegUnpinFoo, foo_const: &pin const NegUnpinFoo) { + let NegUnpinFoo(_x) = foo_mut; // ok + let NegUnpinFoo(_x) = foo_const; // ok + let NegUnpinFoo(_x) = (|| foo_mut)(); // ok + let NegUnpinFoo(_x) = (|| foo_const)(); // ok + let &mut _foo_mut = foo_mut; //~ ERROR mismatched types + let &_foo_const = foo_const; //~ ERROR mismatched types + // FIXME(pin_ergonomics): add these tests since `&pin` pattern is ready + // let &pin mut _foo_mut = foo_mut; // ok + // let &pin mut _foo_const = foo_const; // ok +} + +fn neg_unpin2unpin( + foo_mut: &pin mut NegUnpinFoo, + foo_const: &pin const NegUnpinFoo, +) { + let NegUnpinFoo(_x) = foo_mut; // ok + let NegUnpinFoo(_x) = foo_const; // ok + let NegUnpinFoo(_x) = (|| foo_mut)(); // ok + let NegUnpinFoo(_x) = (|| foo_const)(); // ok + let &mut _foo_mut = foo_mut; //~ ERROR mismatched types + let &_foo_const = foo_const; //~ ERROR mismatched types + // FIXME(pin_ergonomics): add these tests since `&pin` pattern is ready + // let &pin mut _foo_mut = foo_mut; // ok + // let &pin mut _foo_const = foo_const; // ok +} + +fn tuple_ref_mut_pat_and_pin_mut_of_tuple_mut_ty<'a, T>( + (&mut x,): &'a pin mut (&'a mut NegUnpinFoo,), + //~^ ERROR the trait bound `&'a mut NegUnpinFoo: !Unpin` is not satisfied in `(&'a mut NegUnpinFoo,)` [E0277] +) -> &'a pin mut NegUnpinFoo { + x +} + +fn tuple_ref_mut_pat_and_pin_mut_of_mut_tuple_ty<'a, T>( + (&mut x,): &'a pin mut &'a mut (NegUnpinFoo,), + //~^ ERROR mismatched type + //~| ERROR the trait bound `&'a mut (NegUnpinFoo,): !Unpin` is not satisfied [E0277] +) -> &'a pin mut NegUnpinFoo { + x +} + +fn ref_mut_tuple_pat_and_pin_mut_of_tuple_mut_ty<'a, T>( + &mut (x,): &'a pin mut (&'a mut NegUnpinFoo,), //~ ERROR mismatched type +) -> &'a pin mut NegUnpinFoo { + x +} + +fn ref_mut_tuple_pat_and_pin_mut_of_mut_tuple_ty<'a, T>( + &mut (x,): &'a pin mut &'a mut (NegUnpinFoo,), //~ ERROR mismatched type +) -> &'a pin mut NegUnpinFoo { + x +} + +fn tuple_pat_and_pin_mut_of_tuple_mut_ty<'a, T>( + (x,): &'a pin mut (&'a mut NegUnpinFoo,), +) -> &'a pin mut &'a mut NegUnpinFoo { + x // ok +} + +fn tuple_pat_and_pin_mut_of_mut_tuple_ty<'a, T>( + (x,): &'a pin mut &'a mut (NegUnpinFoo,), + //~^ ERROR the trait bound `&'a mut (NegUnpinFoo,): !Unpin` is not satisfied [E0277] +) -> &'a pin mut NegUnpinFoo { + x +} + +fn main() {} diff --git a/tests/ui/pin-ergonomics/projection-unpin-checks.stderr b/tests/ui/pin-ergonomics/projection-unpin-checks.stderr new file mode 100644 index 0000000000000..c79e1e11b0771 --- /dev/null +++ b/tests/ui/pin-ergonomics/projection-unpin-checks.stderr @@ -0,0 +1,333 @@ +error[E0277]: the trait bound `Foo: !Unpin` is not satisfied + --> $DIR/projection-unpin-checks.rs:15:9 + | +LL | let Foo(_x) = foo_mut; + | ^^^^^^^ the trait bound `Foo: !Unpin` is not satisfied + +error[E0277]: the trait bound `Foo: !Unpin` is not satisfied + --> $DIR/projection-unpin-checks.rs:16:9 + | +LL | let Foo(_x) = foo_const; + | ^^^^^^^ the trait bound `Foo: !Unpin` is not satisfied + +error[E0277]: the trait bound `Foo: !Unpin` is not satisfied + --> $DIR/projection-unpin-checks.rs:17:9 + | +LL | let Foo(_x) = (|| foo_mut)(); + | ^^^^^^^ the trait bound `Foo: !Unpin` is not satisfied + +error[E0277]: the trait bound `Foo: !Unpin` is not satisfied + --> $DIR/projection-unpin-checks.rs:18:9 + | +LL | let Foo(_x) = (|| foo_const)(); + | ^^^^^^^ the trait bound `Foo: !Unpin` is not satisfied + +error[E0308]: mismatched types + --> $DIR/projection-unpin-checks.rs:19:9 + | +LL | let &mut _foo_mut = foo_mut; + | ^^^^^^^^^^^^^ ------- this expression has type `Pin<&mut Foo>` + | | + | expected `Pin<&mut Foo>`, found `&mut _` + | + = note: expected struct `Pin<&mut Foo>` + found mutable reference `&mut _` +help: you might have meant to use field `pointer` whose type is `&mut Foo` + | +LL | let &mut _foo_mut = foo_mut.pointer; + | ++++++++ +help: to declare a mutable variable use + | +LL - let &mut _foo_mut = foo_mut; +LL + let mut _foo_mut = foo_mut; + | + +error[E0308]: mismatched types + --> $DIR/projection-unpin-checks.rs:20:9 + | +LL | let &_foo_const = foo_const; + | ^^^^^^^^^^^ --------- this expression has type `Pin<&Foo>` + | | + | expected `Pin<&Foo>`, found `&_` + | + = note: expected struct `Pin<&Foo>` + found reference `&_` +help: you might have meant to use field `pointer` whose type is `&Foo` + | +LL | let &_foo_const = foo_const.pointer; + | ++++++++ + +error[E0308]: mismatched types + --> $DIR/projection-unpin-checks.rs:31:9 + | +LL | let &mut _foo_mut = foo_mut; + | ^^^^^^^^^^^^^ ------- this expression has type `Pin<&mut Foo>` + | | + | expected `Pin<&mut Foo>`, found `&mut _` + | + = note: expected struct `Pin<&mut Foo>` + found mutable reference `&mut _` +help: you might have meant to use field `pointer` whose type is `&mut Foo` + | +LL | let &mut _foo_mut = foo_mut.pointer; + | ++++++++ +help: to declare a mutable variable use + | +LL - let &mut _foo_mut = foo_mut; +LL + let mut _foo_mut = foo_mut; + | + +error[E0308]: mismatched types + --> $DIR/projection-unpin-checks.rs:32:9 + | +LL | let &_foo_const = foo_const; + | ^^^^^^^^^^^ --------- this expression has type `Pin<&Foo>` + | | + | expected `Pin<&Foo>`, found `&_` + | + = note: expected struct `Pin<&Foo>` + found reference `&_` +help: you might have meant to use field `pointer` whose type is `&Foo` + | +LL | let &_foo_const = foo_const.pointer; + | ++++++++ + +error[E0277]: the trait bound `NotUnpinFoo: !Unpin` is not satisfied + --> $DIR/projection-unpin-checks.rs:39:9 + | +LL | let NotUnpinFoo(_x, _) = foo_mut; + | ^^^^^^^^^^^^^^^^^^ the trait bound `NotUnpinFoo: !Unpin` is not satisfied + +error[E0277]: the trait bound `NotUnpinFoo: !Unpin` is not satisfied + --> $DIR/projection-unpin-checks.rs:40:9 + | +LL | let NotUnpinFoo(_x, _) = foo_const; + | ^^^^^^^^^^^^^^^^^^ the trait bound `NotUnpinFoo: !Unpin` is not satisfied + +error[E0277]: the trait bound `NotUnpinFoo: !Unpin` is not satisfied + --> $DIR/projection-unpin-checks.rs:41:9 + | +LL | let NotUnpinFoo(_x, _) = (|| foo_mut)(); + | ^^^^^^^^^^^^^^^^^^ the trait bound `NotUnpinFoo: !Unpin` is not satisfied + +error[E0277]: the trait bound `NotUnpinFoo: !Unpin` is not satisfied + --> $DIR/projection-unpin-checks.rs:42:9 + | +LL | let NotUnpinFoo(_x, _) = (|| foo_const)(); + | ^^^^^^^^^^^^^^^^^^ the trait bound `NotUnpinFoo: !Unpin` is not satisfied + +error[E0308]: mismatched types + --> $DIR/projection-unpin-checks.rs:43:9 + | +LL | let &mut _foo_mut = foo_mut; + | ^^^^^^^^^^^^^ ------- this expression has type `Pin<&mut NotUnpinFoo>` + | | + | expected `Pin<&mut NotUnpinFoo>`, found `&mut _` + | + = note: expected struct `Pin<&mut NotUnpinFoo>` + found mutable reference `&mut _` +help: you might have meant to use field `pointer` whose type is `&mut NotUnpinFoo` + | +LL | let &mut _foo_mut = foo_mut.pointer; + | ++++++++ +help: to declare a mutable variable use + | +LL - let &mut _foo_mut = foo_mut; +LL + let mut _foo_mut = foo_mut; + | + +error[E0308]: mismatched types + --> $DIR/projection-unpin-checks.rs:44:9 + | +LL | let &_foo_const = foo_const; + | ^^^^^^^^^^^ --------- this expression has type `Pin<&NotUnpinFoo>` + | | + | expected `Pin<&NotUnpinFoo>`, found `&_` + | + = note: expected struct `Pin<&NotUnpinFoo>` + found reference `&_` +help: you might have meant to use field `pointer` whose type is `&NotUnpinFoo` + | +LL | let &_foo_const = foo_const.pointer; + | ++++++++ + +error[E0308]: mismatched types + --> $DIR/projection-unpin-checks.rs:58:9 + | +LL | let &mut _foo_mut = foo_mut; + | ^^^^^^^^^^^^^ ------- this expression has type `Pin<&mut NotUnpinFoo>` + | | + | expected `Pin<&mut NotUnpinFoo>`, found `&mut _` + | + = note: expected struct `Pin<&mut NotUnpinFoo>` + found mutable reference `&mut _` +help: you might have meant to use field `pointer` whose type is `&mut NotUnpinFoo` + | +LL | let &mut _foo_mut = foo_mut.pointer; + | ++++++++ +help: to declare a mutable variable use + | +LL - let &mut _foo_mut = foo_mut; +LL + let mut _foo_mut = foo_mut; + | + +error[E0308]: mismatched types + --> $DIR/projection-unpin-checks.rs:59:9 + | +LL | let &_foo_const = foo_const; + | ^^^^^^^^^^^ --------- this expression has type `Pin<&NotUnpinFoo>` + | | + | expected `Pin<&NotUnpinFoo>`, found `&_` + | + = note: expected struct `Pin<&NotUnpinFoo>` + found reference `&_` +help: you might have meant to use field `pointer` whose type is `&NotUnpinFoo` + | +LL | let &_foo_const = foo_const.pointer; + | ++++++++ + +error[E0308]: mismatched types + --> $DIR/projection-unpin-checks.rs:70:9 + | +LL | let &mut _foo_mut = foo_mut; + | ^^^^^^^^^^^^^ ------- this expression has type `Pin<&mut NegUnpinFoo>` + | | + | expected `Pin<&mut NegUnpinFoo>`, found `&mut _` + | + = note: expected struct `Pin<&mut NegUnpinFoo>` + found mutable reference `&mut _` +help: you might have meant to use field `pointer` whose type is `&mut NegUnpinFoo` + | +LL | let &mut _foo_mut = foo_mut.pointer; + | ++++++++ +help: to declare a mutable variable use + | +LL - let &mut _foo_mut = foo_mut; +LL + let mut _foo_mut = foo_mut; + | + +error[E0308]: mismatched types + --> $DIR/projection-unpin-checks.rs:71:9 + | +LL | let &_foo_const = foo_const; + | ^^^^^^^^^^^ --------- this expression has type `Pin<&NegUnpinFoo>` + | | + | expected `Pin<&NegUnpinFoo>`, found `&_` + | + = note: expected struct `Pin<&NegUnpinFoo>` + found reference `&_` +help: you might have meant to use field `pointer` whose type is `&NegUnpinFoo` + | +LL | let &_foo_const = foo_const.pointer; + | ++++++++ + +error[E0308]: mismatched types + --> $DIR/projection-unpin-checks.rs:85:9 + | +LL | let &mut _foo_mut = foo_mut; + | ^^^^^^^^^^^^^ ------- this expression has type `Pin<&mut NegUnpinFoo>` + | | + | expected `Pin<&mut NegUnpinFoo>`, found `&mut _` + | + = note: expected struct `Pin<&mut NegUnpinFoo>` + found mutable reference `&mut _` +help: you might have meant to use field `pointer` whose type is `&mut NegUnpinFoo` + | +LL | let &mut _foo_mut = foo_mut.pointer; + | ++++++++ +help: to declare a mutable variable use + | +LL - let &mut _foo_mut = foo_mut; +LL + let mut _foo_mut = foo_mut; + | + +error[E0308]: mismatched types + --> $DIR/projection-unpin-checks.rs:86:9 + | +LL | let &_foo_const = foo_const; + | ^^^^^^^^^^^ --------- this expression has type `Pin<&NegUnpinFoo>` + | | + | expected `Pin<&NegUnpinFoo>`, found `&_` + | + = note: expected struct `Pin<&NegUnpinFoo>` + found reference `&_` +help: you might have meant to use field `pointer` whose type is `&NegUnpinFoo` + | +LL | let &_foo_const = foo_const.pointer; + | ++++++++ + +error[E0277]: the trait bound `&'a mut NegUnpinFoo: !Unpin` is not satisfied in `(&'a mut NegUnpinFoo,)` + --> $DIR/projection-unpin-checks.rs:93:5 + | +LL | (&mut x,): &'a pin mut (&'a mut NegUnpinFoo,), + | ^^^^^^^^^ within `(&'a mut NegUnpinFoo,)`, the trait bound `&'a mut NegUnpinFoo: !Unpin` is not satisfied + | + = note: required because it appears within the type `(&'a mut NegUnpinFoo,)` + +error[E0308]: mismatched types + --> $DIR/projection-unpin-checks.rs:100:6 + | +LL | (&mut x,): &'a pin mut &'a mut (NegUnpinFoo,), + | ^^^^^^ ------------------------------------- expected due to this + | | + | expected `NegUnpinFoo`, found `&mut _` + | + = note: expected struct `NegUnpinFoo` + found mutable reference `&mut _` +note: to declare a mutable binding use: `mut x` + --> $DIR/projection-unpin-checks.rs:100:6 + | +LL | (&mut x,): &'a pin mut &'a mut (NegUnpinFoo,), + | ^^^^^^ +help: consider removing `&mut` from the pattern + | +LL - (&mut x,): &'a pin mut &'a mut (NegUnpinFoo,), +LL + (x,): &'a pin mut &'a mut (NegUnpinFoo,), + | + +error[E0277]: the trait bound `&'a mut (NegUnpinFoo,): !Unpin` is not satisfied + --> $DIR/projection-unpin-checks.rs:100:5 + | +LL | (&mut x,): &'a pin mut &'a mut (NegUnpinFoo,), + | ^^^^^^^^^ the trait bound `&'a mut (NegUnpinFoo,): !Unpin` is not satisfied + +error[E0308]: mismatched types + --> $DIR/projection-unpin-checks.rs:108:5 + | +LL | &mut (x,): &'a pin mut (&'a mut NegUnpinFoo,), + | ^^^^^^^^^ ------------------------------------- expected due to this + | | + | expected `Pin<&mut (&mut NegUnpinFoo,)>`, found `&mut _` + | + = note: expected struct `Pin<&'a mut (&'a mut NegUnpinFoo,)>` + found mutable reference `&mut _` +help: you might have meant to use field `pointer` whose type is `&'a mut (&'a mut NegUnpinFoo,)` + | +LL | &mut (x,): &'a pin mut (&'a mut NegUnpinFoo,).pointer, + | ++++++++ + +error[E0308]: mismatched types + --> $DIR/projection-unpin-checks.rs:114:5 + | +LL | &mut (x,): &'a pin mut &'a mut (NegUnpinFoo,), + | ^^^^^^^^^ ------------------------------------- expected due to this + | | + | expected `Pin<&mut &mut (NegUnpinFoo,)>`, found `&mut _` + | + = note: expected struct `Pin<&'a mut &'a mut (NegUnpinFoo,)>` + found mutable reference `&mut _` +help: you might have meant to use field `pointer` whose type is `&'a mut &'a mut (NegUnpinFoo,)` + | +LL | &mut (x,): &'a pin mut &'a mut (NegUnpinFoo,).pointer, + | ++++++++ + +error[E0277]: the trait bound `&'a mut (NegUnpinFoo,): !Unpin` is not satisfied + --> $DIR/projection-unpin-checks.rs:126:5 + | +LL | (x,): &'a pin mut &'a mut (NegUnpinFoo,), + | ^^^^ the trait bound `&'a mut (NegUnpinFoo,): !Unpin` is not satisfied + +error: aborting due to 26 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`.