From c9ca4f8154561609041c7839632dc7645f846a88 Mon Sep 17 00:00:00 2001 From: Frank King Date: Sun, 13 Apr 2025 22:57:37 +0800 Subject: [PATCH 1/2] Implement pin-project in pattern matching for `&pin mut|const T` --- .../src/diagnostics/mutability_errors.rs | 2 +- compiler/rustc_borrowck/src/lib.rs | 5 +- compiler/rustc_borrowck/src/type_check/mod.rs | 7 +- compiler/rustc_codegen_cranelift/src/base.rs | 2 +- .../src/intrinsics/mod.rs | 6 +- .../src/intrinsics/simd.rs | 2 +- compiler/rustc_codegen_cranelift/src/num.rs | 4 +- .../rustc_codegen_cranelift/src/unsize.rs | 2 +- .../src/value_and_place.rs | 2 +- .../rustc_codegen_cranelift/src/vtable.rs | 3 +- compiler/rustc_codegen_llvm/src/abi.rs | 2 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 2 +- .../rustc_codegen_ssa/src/mir/debuginfo.rs | 4 +- compiler/rustc_codegen_ssa/src/mir/operand.rs | 4 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 2 +- .../src/const_eval/eval_queries.rs | 2 +- .../src/interpret/intrinsics.rs | 6 +- .../src/interpret/operator.rs | 2 +- .../rustc_const_eval/src/interpret/place.rs | 7 +- .../src/util/check_validity_requirement.rs | 2 +- compiler/rustc_hir_analysis/src/autoderef.rs | 41 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 2 +- .../rustc_hir_typeck/src/expr_use_visitor.rs | 4 +- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 2 +- compiler/rustc_hir_typeck/src/pat.rs | 55 ++- compiler/rustc_hir_typeck/src/place_op.rs | 4 +- compiler/rustc_hir_typeck/src/writeback.rs | 4 + compiler/rustc_middle/src/mir/statement.rs | 2 +- compiler/rustc_middle/src/thir.rs | 2 + compiler/rustc_middle/src/ty/adt.rs | 11 + compiler/rustc_middle/src/ty/sty.rs | 16 +- .../rustc_middle/src/ty/typeck_results.rs | 18 +- compiler/rustc_middle/src/ty/util.rs | 22 + .../src/builder/matches/match_pair.rs | 3 +- .../src/builder/matches/mod.rs | 62 ++- .../src/thir/pattern/check_match.rs | 4 +- .../rustc_mir_build/src/thir/pattern/mod.rs | 7 +- compiler/rustc_mir_build/src/thir/print.rs | 3 +- .../rustc_mir_transform/src/check_pointers.rs | 2 +- .../src/dataflow_const_prop.rs | 2 +- compiler/rustc_mir_transform/src/gvn.rs | 10 +- .../src/mentioned_items.rs | 4 +- compiler/rustc_mir_transform/src/validate.rs | 11 +- .../src/partitioning/autodiff.rs | 2 +- .../rustc_pattern_analysis/src/constructor.rs | 26 +- compiler/rustc_pattern_analysis/src/rustc.rs | 53 ++- .../rustc_pattern_analysis/src/rustc/print.rs | 8 +- .../rustc_pattern_analysis/src/usefulness.rs | 2 +- compiler/rustc_symbol_mangling/src/v0.rs | 5 +- .../clippy_lints/src/operators/cmp_owned.rs | 2 +- .../clippy/clippy_utils/src/eager_or_lazy.rs | 7 +- .../clippy_utils/src/qualify_min_const_fn.rs | 2 +- .../src/borrow_tracker/stacked_borrows/mod.rs | 2 +- .../src/borrow_tracker/tree_borrows/mod.rs | 2 +- src/tools/miri/src/intrinsics/simd.rs | 2 +- .../miri/src/shims/unix/foreign_items.rs | 2 +- .../diagnostics/match_check/pat_analysis.rs | 10 +- ...ct_pattern_match.bar_const.built.after.mir | 31 ++ ...ject_pattern_match.bar_mut.built.after.mir | 31 ++ ...attern_match.baz_baz_const.built.after.mir | 390 ++++++++++++++++++ ..._pattern_match.baz_baz_mut.built.after.mir | 390 ++++++++++++++++++ ...ct_pattern_match.baz_const.built.after.mir | 72 ++++ ...ject_pattern_match.baz_mut.built.after.mir | 72 ++++ ...attern_match.foo_bar_const.built.after.mir | 43 ++ ..._pattern_match.foo_bar_mut.built.after.mir | 43 ++ ...ct_pattern_match.foo_const.built.after.mir | 31 ++ ...ject_pattern_match.foo_mut.built.after.mir | 31 ++ .../pin-ergonomics/project_pattern_match.rs | 95 +++++ .../project-pattern-match.normal.stderr | 313 ++++++++++++++ .../pin-ergonomics/project-pattern-match.rs | 192 +++++++++ tests/ui/thir-print/thir-tree-match.stdout | 1 + 72 files changed, 2092 insertions(+), 129 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/async-await/pin-ergonomics/project-pattern-match.normal.stderr create mode 100644 tests/ui/async-await/pin-ergonomics/project-pattern-match.rs diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 56cc432758511..2d86eb06d9def 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1588,7 +1588,7 @@ fn suggest_ampmut<'tcx>( } else { // otherwise, suggest that the user annotates the binding; we provide the // type of the local. - let ty = decl_ty.builtin_deref(true).unwrap(); + let ty = decl_ty.builtin_deref(true, tcx).unwrap(); Some(AmpMutSugg { has_sugg: false, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 3b66142eb2cec..d5420c82c201b 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2472,7 +2472,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // Check the kind of deref to decide match base_ty.kind() { - ty::Ref(_, _, mutbl) => { + _ if let Some((_, _, _, mutbl)) = + base_ty.is_ref_or_pin_ref(self.infcx.tcx) => + { + // FIXME(pin_ergonomics): handle `&pin mut|const T` match mutbl { // Shared borrowed data is never mutable hir::Mutability::Not => Err(place), diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 3c00b819a96bb..597bc480abeeb 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1761,7 +1761,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } else if let Some(static_def_id) = constant.check_static_ptr(tcx) { let unnormalized_ty = tcx.type_of(static_def_id).instantiate_identity(); let normalized_ty = self.normalize(unnormalized_ty, locations); - let literal_ty = constant.const_.ty().builtin_deref(true).unwrap(); + let literal_ty = constant.const_.ty().builtin_deref(true, tcx).unwrap(); if let Err(terr) = self.eq_types(literal_ty, normalized_ty, locations, ConstraintCategory::Boring) @@ -2360,7 +2360,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { debug!("add_reborrow_constraint - base_ty = {:?}", base_ty); match base_ty.kind() { - ty::Ref(ref_region, _, mutbl) => { + _ if let Some((ref_region, _, _, mutbl)) = + base_ty.is_ref_or_pin_ref(tcx) => + { + // FIXME(pin_ergonomics): handle `&pin mut|const T` constraints.outlives_constraints.push(OutlivesConstraint { sup: ref_region.as_var(), sub: borrow_region.as_var(), diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index adaa754491e56..0483a23826b81 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -729,7 +729,7 @@ fn codegen_stmt<'tcx>( let to_ty = fx.monomorphize(to_ty); fn is_wide_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { - ty.builtin_deref(true).is_some_and(|pointee_ty| { + ty.builtin_deref(true, fx.tcx).is_some_and(|pointee_ty| { fx.tcx .type_has_metadata(pointee_ty, ty::TypingEnv::fully_monomorphized()) }) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index d3f47ad726334..1a897d9075721 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -583,7 +583,7 @@ fn codegen_regular_intrinsic_call<'tcx>( intrinsic_args!(fx, args => (base, offset); intrinsic); let offset = offset.load_scalar(fx); - let pointee_ty = base.layout().ty.builtin_deref(true).unwrap(); + let pointee_ty = base.layout().ty.builtin_deref(true, fx.tcx).unwrap(); let pointee_size = fx.layout_of(pointee_ty).size.bytes(); let ptr_diff = if pointee_size != 1 { fx.bcx.ins().imul_imm(offset, pointee_size as i64) @@ -609,7 +609,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = val.load_scalar(fx); let count = count.load_scalar(fx); - let pointee_ty = dst.layout().ty.builtin_deref(true).unwrap(); + let pointee_ty = dst.layout().ty.builtin_deref(true, fx.tcx).unwrap(); let pointee_size = fx.layout_of(pointee_ty).size.bytes(); let count = if pointee_size != 1 { fx.bcx.ins().imul_imm(count, pointee_size as i64) @@ -717,7 +717,7 @@ fn codegen_regular_intrinsic_call<'tcx>( // Cranelift treats loads as volatile by default // FIXME correctly handle unaligned_volatile_load - let inner_layout = fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap()); + let inner_layout = fx.layout_of(ptr.layout().ty.builtin_deref(true, fx.tcx).unwrap()); let val = CValue::by_ref(Pointer::new(ptr.load_scalar(fx)), inner_layout); ret.write_cvalue(fx, val); } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index dd6d8dbb6f5e0..4d483616db467 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -897,7 +897,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( intrinsic_args!(fx, args => (ptr, offset); intrinsic); let (lane_count, ptr_lane_ty) = ptr.layout().ty.simd_size_and_type(fx.tcx); - let pointee_ty = ptr_lane_ty.builtin_deref(true).unwrap(); + let pointee_ty = ptr_lane_ty.builtin_deref(true, fx.tcx).unwrap(); let pointee_size = fx.layout_of(pointee_ty).size.bytes(); let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); let ret_lane_layout = fx.layout_of(ret_lane_ty); diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs index 2a4d1e3ae571d..f961b42c8b6f2 100644 --- a/compiler/rustc_codegen_cranelift/src/num.rs +++ b/compiler/rustc_codegen_cranelift/src/num.rs @@ -398,7 +398,7 @@ pub(crate) fn codegen_ptr_binop<'tcx>( let is_thin_ptr = in_lhs .layout() .ty - .builtin_deref(true) + .builtin_deref(true, fx.tcx) .map(|ty| !fx.tcx.type_has_metadata(ty, ty::TypingEnv::fully_monomorphized())) .unwrap_or(true); @@ -411,7 +411,7 @@ pub(crate) fn codegen_ptr_binop<'tcx>( codegen_compare_bin_op(fx, bin_op, false, lhs, rhs) } BinOp::Offset => { - let pointee_ty = in_lhs.layout().ty.builtin_deref(true).unwrap(); + let pointee_ty = in_lhs.layout().ty.builtin_deref(true, fx.tcx).unwrap(); let (base, offset) = (in_lhs, in_rhs.load_scalar(fx)); let pointee_size = fx.layout_of(pointee_ty).size.bytes(); let ptr_diff = fx.bcx.ins().imul_imm(offset, pointee_size as i64); diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index f8bbb21492015..a8d6f23967a51 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -138,7 +138,7 @@ pub(crate) fn coerce_unsized_into<'tcx>( let dst_ty = dst.layout().ty; let mut coerce_ptr = || { let (base, info) = - if fx.layout_of(src.layout().ty.builtin_deref(true).unwrap()).is_unsized() { + if fx.layout_of(src.layout().ty.builtin_deref(true, fx.tcx).unwrap()).is_unsized() { let (old_base, old_info) = src.load_scalar_pair(fx); unsize_ptr(fx, old_base, src.layout(), dst.layout(), Some(old_info)) } else { diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index f8a19589fdd72..6eacf4c71754c 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -831,7 +831,7 @@ impl<'tcx> CPlace<'tcx> { } pub(crate) fn place_deref(self, fx: &mut FunctionCx<'_, '_, 'tcx>) -> CPlace<'tcx> { - let inner_layout = fx.layout_of(self.layout().ty.builtin_deref(true).unwrap()); + let inner_layout = fx.layout_of(self.layout().ty.builtin_deref(true, fx.tcx).unwrap()); if fx.tcx.type_has_metadata(inner_layout.ty, ty::TypingEnv::fully_monomorphized()) { let (addr, extra) = self.to_cvalue(fx).load_scalar_pair(fx); CPlace::for_ptr_with_extra(Pointer::new(addr), extra, inner_layout) diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index 9d9e0462a9b72..691853a972afa 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -59,7 +59,8 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( if let ty::Ref(_, ty, _) = arg.layout().ty.kind() { if ty.is_dyn_star() { - let inner_layout = fx.layout_of(arg.layout().ty.builtin_deref(true).unwrap()); + let inner_layout = + fx.layout_of(arg.layout().ty.builtin_deref(true, fx.tcx).unwrap()); let dyn_star = CPlace::for_ptr(Pointer::new(arg.load_scalar(fx)), inner_layout); let ptr = dyn_star.place_field(fx, FieldIdx::ZERO).to_ptr(); let vtable = diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 8294e29d07df6..02e5ba423e2d9 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -626,7 +626,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { let element_type_index = unsafe { llvm::LLVMRustGetElementTypeArgIndex(callsite) }; if element_type_index >= 0 { let arg_ty = self.args[element_type_index as usize].layout.ty; - let pointee_ty = arg_ty.builtin_deref(true).expect("Must be pointer argument"); + let pointee_ty = arg_ty.builtin_deref(true, bx.tcx).expect("Must be pointer argument"); let element_type_attr = unsafe { llvm::LLVMRustCreateElementTypeAttr(bx.llcx, bx.layout_of(pointee_ty).llvm_type(bx)) }; diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index d1d6bcebd33ab..8d563ae202d40 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -2532,7 +2532,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( if name == sym::simd_arith_offset { // This also checks that the first operand is a ptr type. - let pointee = in_elem.builtin_deref(true).unwrap_or_else(|| { + let pointee = in_elem.builtin_deref(true, bx.tcx).unwrap_or_else(|| { span_bug!(span, "must be called with a vector of pointer types as first argument") }); let layout = bx.layout_of(pointee); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index d184ce3d61dea..ccd3ce2f01430 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1106,7 +1106,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Make sure that we've actually unwrapped the rcvr down // to a pointer or ref to `dyn* Trait`. - if !op.layout.ty.builtin_deref(true).unwrap().is_dyn_star() { + if !op.layout.ty.builtin_deref(true, bx.tcx()).unwrap().is_dyn_star() { span_bug!(span, "can't codegen a virtual call on {:#?}", op); } let place = op.deref(bx.cx()); diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 5924c8991ad64..89830098c654c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -130,7 +130,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx> { fn deref(&self, bx: &mut Bx) -> Self { bx.cx().layout_of( - self.ty.builtin_deref(true).unwrap_or_else(|| bug!("cannot deref `{}`", self.ty)), + self.ty + .builtin_deref(true, bx.tcx()) + .unwrap_or_else(|| bug!("cannot deref `{}`", self.ty)), ) } diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index eade9e52de95a..bc32a03dd46e9 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -291,7 +291,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let projected_ty = self .layout .ty - .builtin_deref(true) + .builtin_deref(true, cx.tcx()) .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self)); let layout = cx.layout_of(projected_ty); @@ -701,7 +701,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue { let unsized_ty = indirect_dest .layout .ty - .builtin_deref(true) + .builtin_deref(true, bx.tcx()) .unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest)); let OperandValue::Ref(PlaceValue { llval: llptr, llextra: Some(llextra), .. }) = self diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 5c14fe5cd10b7..9cb66d3d92bee 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -966,7 +966,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::BinOp::BitXor => bx.xor(lhs, rhs), mir::BinOp::Offset => { let pointee_type = lhs_ty - .builtin_deref(true) + .builtin_deref(true, bx.tcx()) .unwrap_or_else(|| bug!("deref of non-pointer {:?}", lhs_ty)); let pointee_layout = bx.cx().layout_of(pointee_type); if pointee_layout.is_zst() { diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index ce8eceebdf8d2..cb72a05d2e976 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -216,7 +216,7 @@ pub(super) fn op_to_const<'tcx>( // This codepath solely exists for `valtree_to_const_value` to not need to generate // a `ConstValue::Indirect` for wide references, so it is tightly restricted to just // that case. - let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap(); // `false` = no raw ptrs + let pointee_ty = imm.layout.ty.builtin_deref(false, *ecx.tcx).unwrap(); // `false` = no raw ptrs debug_assert!( matches!( ecx.tcx.struct_tail_for_codegen(pointee_ty, ecx.typing_env()).kind(), diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 4ca317e3a1e53..8c7a4f1c1da60 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -636,7 +636,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { nonoverlapping: bool, ) -> InterpResult<'tcx> { let count = self.read_target_usize(count)?; - let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap())?; + let layout = self.layout_of(src.layout.ty.builtin_deref(true, *self.tcx).unwrap())?; let (size, align) = (layout.size, layout.align.abi); let size = self.compute_size_in_bytes(size, count).ok_or_else(|| { @@ -696,7 +696,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { count: &OpTy<'tcx, >::Provenance>, name: &'static str, ) -> InterpResult<'tcx> { - let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap())?; + let layout = self.layout_of(dst.layout.ty.builtin_deref(true, *self.tcx).unwrap())?; let dst = self.read_pointer(dst)?; let byte = self.read_scalar(byte)?.to_u8()?; @@ -735,7 +735,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { lhs: &OpTy<'tcx, >::Provenance>, rhs: &OpTy<'tcx, >::Provenance>, ) -> InterpResult<'tcx, Scalar> { - let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap())?; + let layout = self.layout_of(lhs.layout.ty.builtin_deref(true, *self.tcx).unwrap())?; assert!(layout.is_sized()); let get_bytes = |this: &InterpCx<'tcx, M>, diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 899670aeb62da..810b8ceef5ec2 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -313,7 +313,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Pointer ops that are always supported. Offset => { let ptr = left.to_scalar().to_pointer(self)?; - let pointee_ty = left.layout.ty.builtin_deref(true).unwrap(); + let pointee_ty = left.layout.ty.builtin_deref(true, *self.tcx).unwrap(); let pointee_layout = self.layout_of(pointee_ty)?; assert!(pointee_layout.is_sized()); diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index f5d3de7b1b270..29e67ab06f0e6 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -419,8 +419,11 @@ where &self, val: &ImmTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { - let pointee_type = - val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type"); + let pointee_type = val + .layout + .ty + .builtin_deref(true, *self.tcx) + .expect("`ref_to_mplace` called on non-ptr type"); let layout = self.layout_of(pointee_type)?; let (ptr, meta) = val.to_scalar_and_meta(); diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index d7e97f32bae92..1bc00f9266d28 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -126,7 +126,7 @@ fn check_validity_requirement_lax<'tcx>( } // Special magic check for references and boxes (i.e., special pointer types). - if let Some(pointee) = this.ty.builtin_deref(false) { + if let Some(pointee) = this.ty.builtin_deref(false, cx.tcx()) { let pointee = cx.layout_of(pointee)?; // We need to ensure that the LLVM attributes `aligned` and `dereferenceable(size)` are satisfied. if pointee.align.abi.bytes() > 1 { diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index 99e495d926690..972e2aa0d2c4f 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -77,27 +77,28 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { // be better to skip this clause and use the Overloaded case only, since &T // and &mut T implement Receiver. But built-in derefs apply equally to Receiver // and Deref, and this has benefits for const and the emitted MIR. - let (kind, new_ty) = - if let Some(ty) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) { - debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty)); - // NOTE: we may still need to normalize the built-in deref in case - // we have some type like `&::Assoc`, since users of - // autoderef expect this type to have been structurally normalized. - if self.infcx.next_trait_solver() - && let ty::Alias(..) = ty.kind() - { - let (normalized_ty, obligations) = self.structurally_normalize_ty(ty)?; - self.state.obligations.extend(obligations); - (AutoderefKind::Builtin, normalized_ty) - } else { - (AutoderefKind::Builtin, ty) - } - } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) { - // The overloaded deref check already normalizes the pointee type. - (AutoderefKind::Overloaded, ty) + let (kind, new_ty) = if let Some(ty) = + self.state.cur_ty.builtin_deref(self.include_raw_pointers, self.infcx.tcx) + { + debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty)); + // NOTE: we may still need to normalize the built-in deref in case + // we have some type like `&::Assoc`, since users of + // autoderef expect this type to have been structurally normalized. + if self.infcx.next_trait_solver() + && let ty::Alias(..) = ty.kind() + { + let (normalized_ty, obligations) = self.structurally_normalize_ty(ty)?; + self.state.obligations.extend(obligations); + (AutoderefKind::Builtin, normalized_ty) } else { - return None; - }; + (AutoderefKind::Builtin, ty) + } + } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) { + // The overloaded deref check already normalizes the pointee type. + (AutoderefKind::Overloaded, ty) + } else { + return None; + }; self.state.steps.push((self.state.cur_ty, kind)); debug!( diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 33d5a86beb3b0..2b84eebe7d803 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1808,7 +1808,7 @@ fn check_method_receiver<'tcx>( match receiver_validity_err { ReceiverValidityError::DoesNotDeref if arbitrary_self_types_level.is_some() => { let hint = match receiver_ty - .builtin_deref(false) + .builtin_deref(false, tcx) .unwrap_or(receiver_ty) .ty_adt_def() .and_then(|adt_def| tcx.get_diagnostic_name(adt_def.did())) diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index f5e0f01e4c573..40f7cc0db356d 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -1265,7 +1265,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx match self .cx .try_structurally_resolve_type(pat.span, base_ty) - .builtin_deref(false) + .builtin_deref(false, self.cx.tcx()) { Some(ty) => Ok(ty), None => { @@ -1555,7 +1555,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx let deref_ty = match self .cx .try_structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), base_curr_ty) - .builtin_deref(true) + .builtin_deref(true, self.cx.tcx()) { Some(ty) => ty, None => { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 87d92b3fbde8d..4858010cb5dab 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -703,7 +703,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ret_ty = method.sig.output(); // method returns &T, but the type as visible to user is T, so deref - ret_ty.builtin_deref(true).unwrap() + ret_ty.builtin_deref(true, self.tcx).unwrap() } pub(crate) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool { diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index e5e4fc7f8b77f..eb4668f9c194e 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; 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; @@ -91,6 +91,7 @@ struct TopInfo<'tcx> { #[derive(Copy, Clone)] struct PatInfo<'tcx> { + pinnedness: Pinnedness, binding_mode: ByRef, max_ref_mutbl: MutblCap, top_info: TopInfo<'tcx>, @@ -369,6 +370,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let top_info = TopInfo { expected, origin_expr, span, hir_id: pat.hir_id }; let pat_info = PatInfo { + pinnedness: Pinnedness::Not, binding_mode: ByRef::No, max_ref_mutbl: MutblCap::Mut, top_info, @@ -474,6 +476,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span_bug!(pat.span, "Pattern mutability cap violated!"); } + // If the expected type is `Unpin`, then remove the pinnedness in `pat_info`. + let pat_info = if pat_info.pinnedness == Pinnedness::Pinned + && expected.is_unpin(self.tcx, self.typing_env(self.param_env)) + { + PatInfo { pinnedness: Pinnedness::Not, ..pat_info } + } else { + pat_info + }; + // Resolve type if needed. let expected = if let AdjustMode::Peel { .. } = adjust_mode && pat.default_binding_modes @@ -486,11 +497,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let pat_info = PatInfo { current_depth: old_pat_info.current_depth + 1, ..old_pat_info }; match pat.kind { - // Peel off a `&` or `&mut` from the scrutinee type. See the examples in - // `tests/ui/rfcs/rfc-2005-default-binding-mode`. + // Peel off a `&`, `&mut`, `&pin const` or `&pin mut` from the scrutinee type. + // See the examples in `tests/ui/rfcs/rfc-2005-default-binding-mode` + // and `tests/ui/async-await/pin-ergonomics/project-pattern-match`. _ if let AdjustMode::Peel { .. } = adjust_mode && pat.default_binding_modes - && let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() => + && let Some((_, pinnedness, inner_ty, inner_mutability)) = + expected.is_ref_or_pin_ref(self.tcx) => { debug!("inspecting {:?}", expected); @@ -514,6 +527,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ByRef::Yes(Mutability::Not) => Mutability::Not, }); + let pinnedness = if pinnedness == Pinnedness::Pinned + || pat_info.pinnedness == Pinnedness::Pinned + { + Pinnedness::Pinned + } else { + Pinnedness::Not + }; + 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()); @@ -524,7 +545,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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, max_ref_mutbl, ..old_pat_info }; + let new_pat_info = + PatInfo { pinnedness, binding_mode, max_ref_mutbl, ..old_pat_info }; // Recurse with the new expected type. self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, new_pat_info) } @@ -956,7 +978,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { - let PatInfo { binding_mode: def_br, top_info: ti, .. } = pat_info; + let PatInfo { pinnedness, binding_mode: def_br, top_info: ti, .. } = pat_info; // Determine the binding mode... let bm = match user_bind_annot { @@ -1029,7 +1051,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // ...and store it in a side table: - self.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm); + { + let mut typeck_results = self.typeck_results.borrow_mut(); + typeck_results.pat_binding_modes_mut().insert(pat.hir_id, bm); + if pinnedness == Pinnedness::Pinned { + typeck_results.pinned_pat_bindings_mut().insert(pat.hir_id); + } + } debug!("check_pat_ident: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); @@ -1049,6 +1077,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ByRef::No => expected, // As above, `T <: typeof(x)` is required, but we use equality, see (note_1). }; + // Wrapping the type into `Pin` if the pattern is pinned + let eq_ty = if pinnedness == Pinnedness::Pinned { + Ty::new_adt( + self.tcx, + self.tcx.adt_def(self.tcx.require_lang_item(hir::LangItem::Pin, Some(pat.span))), + self.tcx.mk_args(&[eq_ty.into()]), + ) + } else { + eq_ty + }; + // We have a concrete type for the local, so we do not need to taint it and hide follow up errors *using* the local. let _ = self.demand_eqtype_pat(pat.span, eq_ty, local_ty, &ti); @@ -1256,7 +1295,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { inner: &Pat<'_>, ) -> Result<(), ErrorGuaranteed> { if let PatKind::Binding(..) = inner.kind - && let Some(pointee_ty) = self.shallow_resolve(expected).builtin_deref(true) + && let Some(pointee_ty) = self.shallow_resolve(expected).builtin_deref(true, self.tcx) && let ty::Dynamic(..) = pointee_ty.kind() { // This is "x = dyn SomeTrait" being reduced from diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index 4fc903cf68b88..42ac4ca90d019 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -23,7 +23,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { oprnd_expr: &'tcx hir::Expr<'tcx>, oprnd_ty: Ty<'tcx>, ) -> Option> { - if let Some(ty) = oprnd_ty.builtin_deref(true) { + if let Some(ty) = oprnd_ty.builtin_deref(true, self.tcx) { return Some(ty); } @@ -356,7 +356,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .typeck_results .borrow() .expr_ty_adjusted(base_expr) - .builtin_deref(false) + .builtin_deref(false, self.tcx) .expect("place op takes something that is not a ref"); let arg_ty = match op { diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 6ba7435cb790d..cca84dca50010 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -319,7 +319,11 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { hir::PatKind::Binding(..) => { let typeck_results = self.fcx.typeck_results.borrow(); let bm = typeck_results.extract_binding_mode(self.tcx().sess, p.hir_id, p.span); + let pinnedness = typeck_results.pat_binding_pinnedness(p.hir_id); self.typeck_results.pat_binding_modes_mut().insert(p.hir_id, bm); + if pinnedness == ty::Pinnedness::Pinned { + self.typeck_results.pinned_pat_bindings_mut().insert(p.hir_id); + } } hir::PatKind::Struct(_, fields, _) => { for field in fields { diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index d59b6df44ed5d..1a81f057a902d 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -176,7 +176,7 @@ impl<'tcx> PlaceTy<'tcx> { } let answer = match *elem { ProjectionElem::Deref => { - let ty = self.ty.builtin_deref(true).unwrap_or_else(|| { + let ty = self.ty.builtin_deref(true, tcx).unwrap_or_else(|| { bug!("deref projection of non-dereferenceable ty {:?}", self) }); PlaceTy::from_ty(ty) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index c168142fb1ecd..35f4568fabb2b 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -762,6 +762,8 @@ pub enum PatKind<'tcx> { Binding { name: Symbol, #[type_visitable(ignore)] + pinnedness: ty::Pinnedness, + #[type_visitable(ignore)] mode: BindingMode, #[type_visitable(ignore)] var: LocalVarId, diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index d92b4f9c06beb..a90e13d461342 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 } @@ -307,6 +309,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 } } @@ -422,6 +427,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 301ae60457434..0a3fe1fc52ef6 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1274,6 +1274,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() @@ -1423,9 +1430,14 @@ impl<'tcx> Ty<'tcx> { /// /// The parameter `explicit` indicates if this is an *explicit* dereference. /// Some types -- notably raw ptrs -- can only be dereferenced explicitly. - pub fn builtin_deref(self, explicit: bool) -> Option> { + pub fn builtin_deref(self, explicit: bool, tcx: TyCtxt<'tcx>) -> Option> { match *self.kind() { _ if let Some(boxed) = self.boxed_ty() => Some(boxed), + _ if let Some(pinned) = self.pinned_ty() + && let Ref(_, ty, _) = *pinned.kind() => + { + tcx.features().pin_ergonomics().then_some(ty) + } Ref(_, ty, _) => Some(ty), RawPtr(ty, _) if explicit => Some(ty), _ => None, @@ -1765,7 +1777,7 @@ impl<'tcx> Ty<'tcx> { /// Panics if `self` is not dereferencable. #[track_caller] pub fn pointee_metadata_ty_or_projection(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - let Some(pointee_ty) = self.builtin_deref(true) else { + let Some(pointee_ty) = self.builtin_deref(true, tcx) else { bug!("Type {self:?} is not a pointer or reference type") }; if pointee_ty.is_trivially_sized(tcx) { diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 4c5c669771fb5..569dabcbd22d8 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -24,7 +24,7 @@ use crate::mir::FakeReadCause; use crate::traits::ObligationCause; use crate::ty::{ self, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, GenericArgKind, GenericArgs, - GenericArgsRef, Ty, UserArgs, tls, + GenericArgsRef, Pinnedness, Ty, UserArgs, tls, }; #[derive(TyEncodable, TyDecodable, Debug, HashStable)] @@ -73,6 +73,9 @@ pub struct TypeckResults<'tcx> { /// Stores the actual binding mode for all instances of [`BindingMode`]. pat_binding_modes: ItemLocalMap, + /// Stores the pinned pattern bindings. + pinned_pat_bindings: ItemLocalSet, + /// Top-level patterns incompatible with Rust 2024's match ergonomics. These will be translated /// to a form valid in all Editions, either as a lint diagnostic or hard error. rust_2024_migration_desugared_pats: ItemLocalMap, @@ -226,6 +229,7 @@ impl<'tcx> TypeckResults<'tcx> { node_args: Default::default(), adjustments: Default::default(), pat_binding_modes: Default::default(), + pinned_pat_bindings: Default::default(), pat_adjustments: Default::default(), rust_2024_migration_desugared_pats: Default::default(), skipped_ref_pats: Default::default(), @@ -412,6 +416,18 @@ impl<'tcx> TypeckResults<'tcx> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_binding_modes } } + pub fn pat_binding_pinnedness(&self, id: HirId) -> Pinnedness { + if self.pinned_pat_bindings().contains(id) { Pinnedness::Pinned } else { Pinnedness::Not } + } + + pub fn pinned_pat_bindings(&self) -> LocalSetInContext<'_> { + LocalSetInContext { hir_owner: self.hir_owner, data: &self.pinned_pat_bindings } + } + + pub fn pinned_pat_bindings_mut(&mut self) -> LocalSetInContextMut<'_> { + LocalSetInContextMut { hir_owner: self.hir_owner, data: &mut self.pinned_pat_bindings } + } + pub fn pat_adjustments( &self, ) -> LocalTableInContext<'_, Vec>> { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 08cee1101d0a9..8aeb09ba7476f 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1545,6 +1545,28 @@ impl<'tcx> Ty<'tcx> { ty } + /// Destructs a reference type `&'a [mut] T` or a pinned reference type + /// `&'a pin const|mut T` into `'a` the region, `[pin]` the pinnedness, + /// `T` the inner type, and `mut|const` the mutability. + pub fn is_ref_or_pin_ref( + self, + tcx: TyCtxt<'tcx>, + ) -> Option<(ty::Region<'tcx>, ty::Pinnedness, Ty<'tcx>, ty::Mutability)> { + match self.kind() { + &ty::Ref(region, inner_ty, mutbl) => { + Some((region, ty::Pinnedness::Not, inner_ty, mutbl)) + } + ty::Adt(adt, args) + if adt.is_pin() + && let &ty::Ref(region, inner_ty, mutbl) = args.type_at(0).kind() + && tcx.features().pin_ergonomics() => + { + Some((region, ty::Pinnedness::Pinned, inner_ty, mutbl)) + } + _ => None, + } + } + // FIXME(compiler-errors): Think about removing this. #[inline] pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex { 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 d66b38c5b005c..210891ecbdebd 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -159,7 +159,7 @@ impl<'tcx> MatchPairTree<'tcx> { None } - PatKind::Binding { mode, var, ref subpattern, .. } => { + PatKind::Binding { mode, var, ref subpattern, pinnedness, .. } => { // In order to please the borrow checker, when lowering a pattern // like `x @ subpat` we must establish any bindings in `subpat` // before establishing the binding for `x`. @@ -198,6 +198,7 @@ impl<'tcx> MatchPairTree<'tcx> { source, var_id: var, binding_mode: mode, + pinnedness, }); } diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 977d4f3e931b5..21efca43c3f00 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -5,20 +5,20 @@ //! 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, 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}; use rustc_middle::middle::region; use rustc_middle::mir::{self, *}; use rustc_middle::thir::{self, *}; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty}; +use rustc_middle::{bug, span_bug}; use rustc_span::{BytePos, Pos, Span, Symbol, sym}; use tracing::{debug, instrument}; @@ -1230,6 +1230,7 @@ struct Binding<'tcx> { source: Place<'tcx>, var_id: LocalVarId, binding_mode: BindingMode, + pinnedness: ty::Pinnedness, } /// Indicates that the type of `source` must be a subtype of the @@ -2715,6 +2716,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let rvalue = Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source); + let rvalue = match binding.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,13 +2765,58 @@ 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) + let rvalue = + Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source); + match binding.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/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 78583a402fe9a..2a187bb0e0eb7 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -974,7 +974,7 @@ fn report_unreachable_pattern<'p, 'tcx>( if cx.is_uninhabited(ty) { lint.matches_no_values_ty = ty; false // No need to dig further. - } else if matches!(subpat.ctor(), Constructor::Ref | Constructor::UnionField) { + } else if matches!(subpat.ctor(), Constructor::Ref(_) | Constructor::UnionField) { false // Don't explore further since they are not by-value. } else { true @@ -1195,7 +1195,7 @@ fn report_arm_reachability<'p, 'tcx>( fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool { match pat.ctor() { Constructor::Wildcard => true, - Constructor::Struct | Constructor::Ref => { + Constructor::Struct | Constructor::Ref(_) => { pat.iter_fields().all(|ipat| pat_is_catchall(&ipat.pat)) } _ => false, diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 8f058efdfacdb..77ef5499b8ceb 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -349,6 +349,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { .get(pat.hir_id) .expect("missing binding mode"); + let pinnedness = self.typeck_results.pat_binding_pinnedness(pat.hir_id); + if let Some(s) = &mut self.rust_2024_migration { s.visit_binding(pat.span, mode, explicit_ba, ident); } @@ -357,8 +359,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // 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; + if let Some((_, _, rty, _)) = ty.is_ref_or_pin_ref(self.tcx) { + ty = rty; } else { bug!("`ref {}` has wrong type {}", ident, ty); } @@ -366,6 +368,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { PatKind::Binding { mode, + pinnedness, name: ident.name, var: LocalVarId(id), ty: var_ty, diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 37248941e2c45..248f35708ec69 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -678,9 +678,10 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_pat(subpattern, depth_lvl + 3); print_indented!(self, "}", depth_lvl + 1); } - PatKind::Binding { name, mode, var, ty, subpattern, is_primary } => { + PatKind::Binding { name, pinnedness, mode, var, ty, subpattern, is_primary } => { print_indented!(self, "Binding {", depth_lvl + 1); print_indented!(self, format!("name: {:?}", name), depth_lvl + 2); + print_indented!(self, format!("pinnedness: {:?}", pinnedness), depth_lvl + 2); print_indented!(self, format!("mode: {:?}", mode), depth_lvl + 2); print_indented!(self, format!("var: {:?}", var), depth_lvl + 2); print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 2); diff --git a/compiler/rustc_mir_transform/src/check_pointers.rs b/compiler/rustc_mir_transform/src/check_pointers.rs index 2d04b62193585..52c647307aa87 100644 --- a/compiler/rustc_mir_transform/src/check_pointers.rs +++ b/compiler/rustc_mir_transform/src/check_pointers.rs @@ -195,7 +195,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PointerFinder<'a, 'tcx> { } let pointee_ty = - pointer_ty.builtin_deref(true).expect("no builtin_deref for an raw pointer"); + pointer_ty.builtin_deref(true, self.tcx).expect("no builtin_deref for an raw pointer"); // Ideally we'd support this in the future, but for now we are limited to sized types. if !pointee_ty.is_sized(self.tcx, self.typing_env) { trace!("Raw pointer, but pointee is not known to be sized: {:?}", pointer_ty); diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 90173da17f0fc..19c5d99752d00 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -391,7 +391,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { if let Some(target_len) = self.map.find_len(target.as_ref()) && let operand_ty = operand.ty(self.local_decls, self.tcx) - && let Some(operand_ty) = operand_ty.builtin_deref(true) + && let Some(operand_ty) = operand_ty.builtin_deref(true, self.tcx) && let ty::Array(_, len) = operand_ty.kind() && let Some(len) = Const::Ty(self.tcx.types.usize, *len) .try_eval_scalar_int(self.tcx, self.typing_env) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 8b8d1efbbd2e0..3bdcce5e35224 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -643,7 +643,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { ProjectionElem::Deref => { let ty = place.ty(self.local_decls, self.tcx).ty; if let Some(Mutability::Not) = ty.ref_mutability() - && let Some(pointee_ty) = ty.builtin_deref(true) + && let Some(pointee_ty) = ty.builtin_deref(true, self.tcx) && pointee_ty.is_freeze(self.tcx, self.typing_env()) { // An immutable borrow `_x` always points to the same value for the @@ -1171,8 +1171,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { to, .. }, - ) if let ty::Slice(..) = to.builtin_deref(true).unwrap().kind() - && let ty::Array(_, len) = from.builtin_deref(true).unwrap().kind() => + ) if let ty::Slice(..) = to.builtin_deref(true, self.tcx).unwrap().kind() + && let ty::Array(_, len) = from.builtin_deref(true, self.tcx).unwrap().kind() => { return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len))); } @@ -1503,9 +1503,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // We have an unsizing cast, which assigns the length to wide pointer metadata. if let Value::Cast { kind, from, to, .. } = self.get(inner) && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) = kind - && let Some(from) = from.builtin_deref(true) + && let Some(from) = from.builtin_deref(true, self.tcx) && let ty::Array(_, len) = from.kind() - && let Some(to) = to.builtin_deref(true) + && let Some(to) = to.builtin_deref(true, self.tcx) && let ty::Slice(..) = to.kind() { return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len))); diff --git a/compiler/rustc_mir_transform/src/mentioned_items.rs b/compiler/rustc_mir_transform/src/mentioned_items.rs index 9fd8d81d64a26..28f1354590647 100644 --- a/compiler/rustc_mir_transform/src/mentioned_items.rs +++ b/compiler/rustc_mir_transform/src/mentioned_items.rs @@ -83,8 +83,8 @@ impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> { // add everything that may involve a vtable. let source_ty = operand.ty(self.body, self.tcx); let may_involve_vtable = match ( - source_ty.builtin_deref(true).map(|t| t.kind()), - target_ty.builtin_deref(true).map(|t| t.kind()), + source_ty.builtin_deref(true, self.tcx).map(|t| t.kind()), + target_ty.builtin_deref(true, self.tcx).map(|t| t.kind()), ) { // &str/&[T] unsizing (Some(ty::Array(..)), Some(ty::Str | ty::Slice(..))) => false, diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 66fe3ef4141f5..fa63d157a1a1c 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1431,7 +1431,12 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } if let Rvalue::CopyForDeref(place) = rvalue { - if place.ty(&self.body.local_decls, self.tcx).ty.builtin_deref(true).is_none() { + if place + .ty(&self.body.local_decls, self.tcx) + .ty + .builtin_deref(true, self.tcx) + .is_none() + { self.fail( location, "`CopyForDeref` should only be used for dereferenceable types", @@ -1468,7 +1473,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { CopyNonOverlapping { src, dst, count }, )) => { let src_ty = src.ty(&self.body.local_decls, self.tcx); - let op_src_ty = if let Some(src_deref) = src_ty.builtin_deref(true) { + let op_src_ty = if let Some(src_deref) = src_ty.builtin_deref(true, self.tcx) { src_deref } else { self.fail( @@ -1478,7 +1483,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { return; }; let dst_ty = dst.ty(&self.body.local_decls, self.tcx); - let op_dst_ty = if let Some(dst_deref) = dst_ty.builtin_deref(true) { + let op_dst_ty = if let Some(dst_deref) = dst_ty.builtin_deref(true, self.tcx) { dst_deref } else { self.fail( diff --git a/compiler/rustc_monomorphize/src/partitioning/autodiff.rs b/compiler/rustc_monomorphize/src/partitioning/autodiff.rs index 22d593b80b895..d0e7f3fc21368 100644 --- a/compiler/rustc_monomorphize/src/partitioning/autodiff.rs +++ b/compiler/rustc_monomorphize/src/partitioning/autodiff.rs @@ -20,7 +20,7 @@ fn adjust_activity_to_abi<'tcx>(tcx: TyCtxt<'tcx>, fn_ty: Ty<'tcx>, da: &mut Vec let mut new_activities = vec![]; let mut new_positions = vec![]; for (i, ty) in sig.inputs().iter().enumerate() { - if let Some(inner_ty) = ty.builtin_deref(true) { + if let Some(inner_ty) = ty.builtin_deref(true, tcx) { if inner_ty.is_slice() { // Now we need to figure out the size of each slice element in memory to allow // safety checks and usability improvements in the backend. diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index 4ce868f014f42..50da2a7aaaf42 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -183,6 +183,7 @@ use std::iter::once; use rustc_apfloat::ieee::{DoubleS, HalfS, IeeeFloat, QuadS, SingleS}; use rustc_index::IndexVec; use rustc_index::bit_set::{DenseBitSet, GrowableBitSet}; +use rustc_middle::ty::Pinnedness; use smallvec::SmallVec; use self::Constructor::*; @@ -679,8 +680,8 @@ pub enum Constructor { Struct, /// Enum variants. Variant(Cx::VariantIdx), - /// References - Ref, + /// References or pinned reference + Ref(Pinnedness), /// Array and slice patterns. Slice(Slice), /// Union field accesses. @@ -730,7 +731,7 @@ impl Clone for Constructor { match self { Constructor::Struct => Constructor::Struct, Constructor::Variant(idx) => Constructor::Variant(*idx), - Constructor::Ref => Constructor::Ref, + Constructor::Ref(pinnedness) => Constructor::Ref(*pinnedness), Constructor::Slice(slice) => Constructor::Slice(*slice), Constructor::UnionField => Constructor::UnionField, Constructor::Bool(b) => Constructor::Bool(*b), @@ -808,7 +809,7 @@ impl Constructor { (Missing { .. } | NonExhaustive | Hidden, _) => false, (Struct, Struct) => true, - (Ref, Ref) => true, + (Ref(self_pin), Ref(other_pin)) => self_pin == other_pin, (UnionField, UnionField) => true, (Variant(self_id), Variant(other_id)) => self_id == other_id, (Bool(self_b), Bool(other_b)) => self_b == other_b, @@ -901,9 +902,12 @@ impl Constructor { // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should // be careful to detect strings here. However a string literal pattern will never // be reported as a non-exhaustiveness witness, so we can ignore this issue. - Ref => { + Ref(Pinnedness::Not) => { write!(f, "&{:?}", fields.next().unwrap())?; } + Ref(Pinnedness::Pinned) => { + write!(f, "&pin {:?}", fields.next().unwrap())?; + } Slice(slice) => { write!(f, "[")?; match slice.kind { @@ -972,8 +976,8 @@ 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`. - Ref, + /// The type is `&T` or `&pin T`. + Ref(Pinnedness), /// The type is a union. Union, /// Booleans. @@ -1057,11 +1061,11 @@ impl ConstructorSet { missing.push(Struct); } } - ConstructorSet::Ref => { + ConstructorSet::Ref(pinnedness) => { if !seen.is_empty() { - present.push(Ref); + present.push(Ref(*pinnedness)); } else { - missing.push(Ref); + missing.push(Ref(*pinnedness)); } } ConstructorSet::Union => { @@ -1179,7 +1183,7 @@ impl ConstructorSet { match self { ConstructorSet::Bool | ConstructorSet::Integers { .. } - | ConstructorSet::Ref + | ConstructorSet::Ref(_) | ConstructorSet::Union | ConstructorSet::Unlistable => false, ConstructorSet::NoConstructors => true, diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 7c12f69f14c1a..c4ff6024bac62 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -239,6 +239,11 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { // 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)); @@ -258,8 +263,10 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } _ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"), }, - Ref => match ty.kind() { - ty::Ref(_, rty, _) => reveal_and_alloc(cx, once(*rty)), + Ref(expected_pinnedness) => match ty.is_ref_or_pin_ref(self.tcx) { + Some((_, pinnedness, rty, _)) if pinnedness == *expected_pinnedness => { + reveal_and_alloc(cx, once(rty)) + } _ => bug!("Unexpected type for `Ref` constructor: {ty:?}"), }, Slice(slice) => match *ty.kind() { @@ -296,7 +303,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } _ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"), }, - Ref => 1, + Ref(_) => 1, Slice(slice) => slice.arity(), Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Str(..) | Opaque(..) | Never | NonExhaustive | Hidden | Missing @@ -373,6 +380,13 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { subtype_is_empty: cx.is_uninhabited(*sub_ty), } } + ty::Adt(adt, args) + if adt.is_pin() + && args.type_at(0).is_ref() + && self.tcx.features().pin_ergonomics() => + { + ConstructorSet::Ref(ty::Pinnedness::Pinned) + } ty::Adt(def, args) if def.is_enum() => { let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(ty); if def.variants().is_empty() && !is_declared_nonexhaustive { @@ -415,7 +429,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { ty::Adt(..) | ty::Tuple(..) => { ConstructorSet::Struct { empty: cx.is_uninhabited(ty.inner()) } } - ty::Ref(..) => ConstructorSet::Ref, + ty::Ref(..) => ConstructorSet::Ref(ty::Pinnedness::Not), ty::Never => ConstructorSet::NoConstructors, // This type is one for which we cannot list constructors, like `str` or `f64`. // FIXME(Nadrieril): which of these are actually allowed? @@ -484,7 +498,15 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { ctor = match ty.kind() { // This is a box pattern. ty::Adt(adt, ..) if adt.is_box() => Struct, - ty::Ref(..) => Ref, + // This is a pin ref pattern. + ty::Adt(adt, args) + if adt.is_pin() + && args.type_at(0).is_ref() + && self.tcx.features().pin_ergonomics() => + { + Ref(ty::Pinnedness::Pinned) + } + ty::Ref(..) => Ref(ty::Pinnedness::Not), _ => span_bug!( pat.span, "pattern has unexpected type: pat: {:?}, ty: {:?}", @@ -509,7 +531,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { .map(|ipat| self.lower_pat(&ipat.pattern).at_index(ipat.field.index())) .collect(); } - ty::Adt(adt, _) if adt.is_box() => { + ty::Adt(adt, args) + if adt.is_box() + || adt.is_pin() + && args.type_at(0).is_ref() + && self.tcx.features().pin_ergonomics() => + { // 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. // FIXME(Nadrieril): A `Box` can in theory be matched either with `Box(_, @@ -528,7 +555,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } else { fields = vec![]; } - ctor = Struct; + if adt.is_pin() { + debug_assert!(args.type_at(0).is_ref()); + ctor = Ref(ty::Pinnedness::Pinned); + } else { + ctor = Struct; + } arity = 1; } ty::Adt(adt, _) => { @@ -639,7 +671,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { // Note: `t` is `str`, not `&str`. let ty = self.reveal_opaque_ty(*t); let subpattern = DeconstructedPat::new(Str(*value), Vec::new(), 0, ty, pat); - ctor = Ref; + ctor = Ref(ty::Pinnedness::Not); fields = vec![subpattern.at_index(0)]; arity = 1; } @@ -869,9 +901,10 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { .unwrap(); s } - Ref => { + Ref(_) => { let mut s = String::new(); - print::write_ref_like(&mut s, pat.ty().inner(), &print(&pat.fields[0])).unwrap(); + print::write_ref_like(&mut s, self.tcx, pat.ty().inner(), &print(&pat.fields[0])) + .unwrap(); s } Slice(slice) => { diff --git a/compiler/rustc_pattern_analysis/src/rustc/print.rs b/compiler/rustc_pattern_analysis/src/rustc/print.rs index 7649f72f8681b..3d8b2d845a31f 100644 --- a/compiler/rustc_pattern_analysis/src/rustc/print.rs +++ b/compiler/rustc_pattern_analysis/src/rustc/print.rs @@ -127,13 +127,17 @@ pub(crate) fn write_struct_like<'tcx>( pub(crate) fn write_ref_like<'tcx>( f: &mut impl fmt::Write, + tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, subpattern: &str, ) -> fmt::Result { - match ty.kind() { - ty::Ref(_, _, mutbl) => { + match ty.is_ref_or_pin_ref(tcx) { + Some((_, ty::Pinnedness::Not, _, mutbl)) => { write!(f, "&{}", mutbl.prefix_str())?; } + Some((_, ty::Pinnedness::Pinned, _, mutbl)) => { + write!(f, "&pin {} ", mutbl.ptr_str())?; + } _ => bug!("{ty} is a bad ref pattern type"), } write!(f, "{subpattern}") diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 11ebbea07fa4e..fd0fad776c481 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -866,7 +866,7 @@ impl PlaceValidity { /// inside `&` and union fields where validity is reset to `MaybeInvalid`. fn specialize(self, ctor: &Constructor) -> Self { // We preserve validity except when we go inside a reference or a union field. - if matches!(ctor, Constructor::Ref | Constructor::UnionField) { + if matches!(ctor, Constructor::Ref(_) | Constructor::UnionField) { // Validity of `x: &T` does not imply validity of `*x: T`. MaybeInvalid } else { diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index f310aa6550025..5f72a8a71ad3d 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -721,8 +721,9 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { hir::Mutability::Mut => "Q", }); - let pointee_ty = - ct_ty.builtin_deref(true).expect("tried to dereference on non-ptr type"); + let pointee_ty = ct_ty + .builtin_deref(true, self.tcx) + .expect("tried to dereference on non-ptr type"); let dereferenced_const = ty::Const::new_value(self.tcx, valtree, pointee_ty); dereferenced_const.print(self)?; } diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs index cf6b8992973a7..9b3f1dea743a5 100644 --- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs +++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs @@ -67,7 +67,7 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) let without_deref = symmetric_partial_eq(cx, arg_ty, other_ty).unwrap_or_default(); let with_deref = arg_ty - .builtin_deref(true) + .builtin_deref(true, cx.tcx) .and_then(|ty| symmetric_partial_eq(cx, ty, other_ty)) .unwrap_or_default(); 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 4543a20cc2cd4..e9505c0eb5750 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, self.cx.tcx) + .is_none() => { self.eagerness |= NoChange; }, diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 5d0401010db6a..13e1c77163836 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -141,7 +141,7 @@ fn check_rvalue<'tcx>( _, ) => Err((span, "function pointer casts are not allowed in const fn".into())), Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize, _), op, cast_ty) => { - let Some(pointee_ty) = cast_ty.builtin_deref(true) else { + let Some(pointee_ty) = cast_ty.builtin_deref(true, cx.tcx) else { // We cannot allow this for now. return Err((span, "unsizing casts are only allowed for references right now".into())); }; diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 18a5a0612bb06..dbce919519e82 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -127,7 +127,7 @@ impl NewPermission { fn from_box_ty<'tcx>(ty: Ty<'tcx>, kind: RetagKind, cx: &crate::MiriInterpCx<'tcx>) -> Self { // `ty` is not the `Box` but the field of the Box with this pointer (due to allocator handling). - let pointee = ty.builtin_deref(true).unwrap(); + let pointee = ty.builtin_deref(true, *cx.tcx).unwrap(); if pointee.is_unpin(*cx.tcx, cx.typing_env()) { // A regular box. On `FnEntry` this is `noalias`, but not `dereferenceable` (hence only // a weak protector). diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index f39a606513d5c..6f771d8b2029a 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -164,7 +164,7 @@ impl<'tcx> NewPermission { cx: &crate::MiriInterpCx<'tcx>, zero_size: bool, ) -> Option { - let pointee = ty.builtin_deref(true).unwrap(); + let pointee = ty.builtin_deref(true, *cx.tcx).unwrap(); pointee.is_unpin(*cx.tcx, cx.typing_env()).then_some(()).map(|()| { // Regular `Unpin` box, give it `noalias` but only a weak protector // because it is valid to deallocate it within the function. diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs index de5da6ec898a4..c520e58031b51 100644 --- a/src/tools/miri/src/intrinsics/simd.rs +++ b/src/tools/miri/src/intrinsics/simd.rs @@ -275,7 +275,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Op::WrappingOffset => { let ptr = left.to_scalar().to_pointer(this)?; let offset_count = right.to_scalar().to_target_isize(this)?; - let pointee_ty = left.layout.ty.builtin_deref(true).unwrap(); + let pointee_ty = left.layout.ty.builtin_deref(true, *this.tcx).unwrap(); let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap(); let offset_bytes = offset_count.wrapping_mul(pointee_size); diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 5e6259c35744b..3edd9d762f4ae 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -469,7 +469,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Figure out how large a pthread TLS key actually is. // To this end, deref the argument type. This is `libc::pthread_key_t`. let key_type = key.layout.ty - .builtin_deref(true) + .builtin_deref(true, *this.tcx) .ok_or_else(|| err_ub_format!( "wrong signature used for `pthread_key_create`: first argument must be a raw pointer." ))?; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index 91eb59fb3140f..23a67d1cd20bb 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -165,7 +165,7 @@ impl<'db> MatchCheckCtx<'db> { ctor = match pat.ty.kind(Interner) { // This is a box pattern. TyKind::Adt(adt, _) if is_box(self.db, adt.0) => Struct, - TyKind::Ref(..) => Ref, + TyKind::Ref(..) => Ref(rustc_ast_ir::Pinnedness::Not), _ => { never!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, &pat.ty); Wildcard @@ -299,7 +299,7 @@ impl<'db> MatchCheckCtx<'db> { // be careful to reconstruct the correct constant pattern here. However a string // literal pattern will never be reported as a non-exhaustiveness witness, so we // ignore this issue. - Ref => PatKind::Deref { subpattern: subpatterns.next().unwrap() }, + Ref(_) => PatKind::Deref { subpattern: subpatterns.next().unwrap() }, Slice(_) => unimplemented!(), &Str(void) => match void {}, Wildcard | NonExhaustive | Hidden | PrivateUninhabited => PatKind::Wild, @@ -349,7 +349,7 @@ impl PatCx for MatchCheckCtx<'_> { 0 } }, - Ref => 1, + Ref(_) => 1, Slice(..) => unimplemented!(), Never | Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Str(..) | Opaque(..) | NonExhaustive | PrivateUninhabited @@ -404,7 +404,7 @@ impl PatCx for MatchCheckCtx<'_> { single(ty.clone()) } }, - Ref => match ty.kind(Interner) { + Ref(_) => match ty.kind(Interner) { TyKind::Ref(.., rty) => single(rty.clone()), ty_kind => { never!("Unexpected type for `{:?}` constructor: {:?}", ctor, ty_kind); @@ -474,7 +474,7 @@ impl PatCx for MatchCheckCtx<'_> { TyKind::Adt(..) | TyKind::Tuple(..) => { ConstructorSet::Struct { empty: cx.is_uninhabited(ty) } } - TyKind::Ref(..) => ConstructorSet::Ref, + TyKind::Ref(..) => ConstructorSet::Ref(rustc_ast_ir::Pinnedness::Not), TyKind::Never => ConstructorSet::NoConstructors, // This type is one for which we cannot list constructors, like `str` or `f64`. _ => ConstructorSet::Unlistable, 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..d99480556ae0f --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.bar_const.built.after.mir @@ -0,0 +1,31 @@ +// 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: &U; + let mut _4: &T; + scope 1 { + debug x => _2; + debug y => _3; + } + + bb0: { + PlaceMention(_1); + StorageLive(_2); + _4 = &((*_1).0: T); + _2 = Pin::<&T> { __pointer: move _4 }; + StorageLive(_3); + _3 = &((*_1).1: U); + _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..f2d2e36fc1d00 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.bar_mut.built.after.mir @@ -0,0 +1,31 @@ +// 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: &mut U; + let mut _4: &mut T; + scope 1 { + debug x => _2; + debug y => _3; + } + + bb0: { + PlaceMention(_1); + StorageLive(_2); + _4 = &mut ((*_1).0: T); + _2 = Pin::<&mut T> { __pointer: move _4 }; + StorageLive(_3); + _3 = &mut ((*_1).1: U); + _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..03c6c0d9d1041 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_const.built.after.mir @@ -0,0 +1,390 @@ +// 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: &U; + let _11: std::pin::Pin<&T>; + let _12: &U; + let mut _13: &T; + let mut _14: &T; + let _15: std::pin::Pin<&T>; + let _16: &U; + let _17: std::pin::Pin<&T>; + let _18: &U; + let mut _19: &T; + let mut _20: &T; + let _21: std::pin::Pin<&T>; + let _22: &U; + let _23: std::pin::Pin<&T>; + let _24: &U; + let mut _25: &T; + let mut _26: &T; + let _27: std::pin::Pin<&T>; + let _28: &U; + let _29: std::pin::Pin<&T>; + let _30: &U; + let mut _31: &T; + let mut _32: &T; + let _33: std::pin::Pin<&T>; + let _34: &U; + let _35: std::pin::Pin<&T>; + let _36: &U; + let mut _37: &T; + let mut _38: &T; + let _39: std::pin::Pin<&T>; + let _40: &U; + let _41: std::pin::Pin<&T>; + let _42: &U; + let mut _43: &T; + let mut _44: &T; + let _45: std::pin::Pin<&T>; + let _46: &U; + let _47: std::pin::Pin<&T>; + let _48: &U; + let mut _49: &T; + let mut _50: &T; + let _51: std::pin::Pin<&T>; + let _52: &U; + let _53: std::pin::Pin<&T>; + let _54: &U; + let mut _55: &T; + let mut _56: &T; + scope 1 { + debug x => _9; + debug y => _10; + debug z => _11; + debug w => _12; + } + scope 2 { + debug x => _15; + debug y => _16; + debug z => _17; + debug w => _18; + } + scope 3 { + debug x => _21; + debug y => _22; + debug z => _23; + debug w => _24; + } + scope 4 { + debug x => _27; + debug y => _28; + debug z => _29; + debug w => _30; + } + scope 5 { + debug x => _33; + debug y => _34; + debug z => _35; + debug w => _36; + } + scope 6 { + debug x => _39; + debug y => _40; + debug z => _41; + debug w => _42; + } + scope 7 { + debug x => _45; + debug y => _46; + debug z => _47; + debug w => _48; + } + scope 8 { + debug x => _51; + debug y => _52; + debug z => _53; + debug w => _54; + } + + bb0: { + PlaceMention(_1); + _8 = discriminant((*_1)); + switchInt(move _8) -> [0: bb2, 1: bb16, otherwise: bb1]; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb2: { + _4 = discriminant((((*_1) as Foo).0: Baz)); + switchInt(move _4) -> [0: bb4, 1: bb10, otherwise: bb3]; + } + + bb3: { + goto -> bb1; + } + + bb4: { + _2 = discriminant((((*_1) 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) 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) as Bar).0: Baz)); + switchInt(move _7) -> [0: bb18, 1: bb24, otherwise: bb17]; + } + + bb17: { + goto -> bb1; + } + + bb18: { + _5 = discriminant((((*_1) 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) 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(_51); + _55 = &(((((*_1) as Bar).0: Baz) as Bar).0: T); + _51 = Pin::<&T> { __pointer: move _55 }; + StorageLive(_52); + _52 = &(((((*_1) as Bar).0: Baz) as Bar).1: U); + StorageLive(_53); + _56 = &(((((*_1) as Bar).1: Baz) as Bar).0: T); + _53 = Pin::<&T> { __pointer: move _56 }; + StorageLive(_54); + _54 = &(((((*_1) as Bar).1: Baz) as Bar).1: U); + _0 = const (); + StorageDead(_54); + StorageDead(_53); + StorageDead(_52); + StorageDead(_51); + goto -> bb37; + } + + bb29: { + goto -> bb25; + } + + bb30: { + StorageLive(_45); + _49 = &(((((*_1) as Bar).0: Baz) as Bar).0: T); + _45 = Pin::<&T> { __pointer: move _49 }; + StorageLive(_46); + _46 = &(((((*_1) as Bar).0: Baz) as Bar).1: U); + StorageLive(_47); + _50 = &(((((*_1) as Bar).1: Baz) as Foo).0: T); + _47 = Pin::<&T> { __pointer: move _50 }; + StorageLive(_48); + _48 = &(((((*_1) as Bar).1: Baz) as Foo).1: U); + _0 = const (); + StorageDead(_48); + StorageDead(_47); + StorageDead(_46); + StorageDead(_45); + goto -> bb37; + } + + bb31: { + StorageLive(_39); + _43 = &(((((*_1) as Bar).0: Baz) as Foo).0: T); + _39 = Pin::<&T> { __pointer: move _43 }; + StorageLive(_40); + _40 = &(((((*_1) as Bar).0: Baz) as Foo).1: U); + StorageLive(_41); + _44 = &(((((*_1) as Bar).1: Baz) as Bar).0: T); + _41 = Pin::<&T> { __pointer: move _44 }; + StorageLive(_42); + _42 = &(((((*_1) as Bar).1: Baz) as Bar).1: U); + _0 = const (); + StorageDead(_42); + StorageDead(_41); + StorageDead(_40); + StorageDead(_39); + goto -> bb37; + } + + bb32: { + StorageLive(_33); + _37 = &(((((*_1) as Bar).0: Baz) as Foo).0: T); + _33 = Pin::<&T> { __pointer: move _37 }; + StorageLive(_34); + _34 = &(((((*_1) as Bar).0: Baz) as Foo).1: U); + StorageLive(_35); + _38 = &(((((*_1) as Bar).1: Baz) as Foo).0: T); + _35 = Pin::<&T> { __pointer: move _38 }; + StorageLive(_36); + _36 = &(((((*_1) as Bar).1: Baz) as Foo).1: U); + _0 = const (); + StorageDead(_36); + StorageDead(_35); + StorageDead(_34); + StorageDead(_33); + goto -> bb37; + } + + bb33: { + StorageLive(_27); + _31 = &(((((*_1) as Foo).0: Baz) as Bar).0: T); + _27 = Pin::<&T> { __pointer: move _31 }; + StorageLive(_28); + _28 = &(((((*_1) as Foo).0: Baz) as Bar).1: U); + StorageLive(_29); + _32 = &(((((*_1) as Foo).1: Baz) as Bar).0: T); + _29 = Pin::<&T> { __pointer: move _32 }; + StorageLive(_30); + _30 = &(((((*_1) as Foo).1: Baz) as Bar).1: U); + _0 = const (); + StorageDead(_30); + StorageDead(_29); + StorageDead(_28); + StorageDead(_27); + goto -> bb37; + } + + bb34: { + StorageLive(_21); + _25 = &(((((*_1) as Foo).0: Baz) as Bar).0: T); + _21 = Pin::<&T> { __pointer: move _25 }; + StorageLive(_22); + _22 = &(((((*_1) as Foo).0: Baz) as Bar).1: U); + StorageLive(_23); + _26 = &(((((*_1) as Foo).1: Baz) as Foo).0: T); + _23 = Pin::<&T> { __pointer: move _26 }; + StorageLive(_24); + _24 = &(((((*_1) as Foo).1: Baz) as Foo).1: U); + _0 = const (); + StorageDead(_24); + StorageDead(_23); + StorageDead(_22); + StorageDead(_21); + goto -> bb37; + } + + bb35: { + StorageLive(_15); + _19 = &(((((*_1) as Foo).0: Baz) as Foo).0: T); + _15 = Pin::<&T> { __pointer: move _19 }; + StorageLive(_16); + _16 = &(((((*_1) as Foo).0: Baz) as Foo).1: U); + StorageLive(_17); + _20 = &(((((*_1) as Foo).1: Baz) as Bar).0: T); + _17 = Pin::<&T> { __pointer: move _20 }; + StorageLive(_18); + _18 = &(((((*_1) as Foo).1: Baz) as Bar).1: U); + _0 = const (); + StorageDead(_18); + StorageDead(_17); + StorageDead(_16); + StorageDead(_15); + goto -> bb37; + } + + bb36: { + StorageLive(_9); + _13 = &(((((*_1) as Foo).0: Baz) as Foo).0: T); + _9 = Pin::<&T> { __pointer: move _13 }; + StorageLive(_10); + _10 = &(((((*_1) as Foo).0: Baz) as Foo).1: U); + StorageLive(_11); + _14 = &(((((*_1) as Foo).1: Baz) as Foo).0: T); + _11 = Pin::<&T> { __pointer: move _14 }; + StorageLive(_12); + _12 = &(((((*_1) as Foo).1: Baz) as Foo).1: U); + _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..7627c7f047a88 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_baz_mut.built.after.mir @@ -0,0 +1,390 @@ +// 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: &mut U; + let _11: std::pin::Pin<&mut T>; + let _12: &mut U; + let mut _13: &mut T; + let mut _14: &mut T; + let _15: std::pin::Pin<&mut T>; + let _16: &mut U; + let _17: std::pin::Pin<&mut T>; + let _18: &mut U; + let mut _19: &mut T; + let mut _20: &mut T; + let _21: std::pin::Pin<&mut T>; + let _22: &mut U; + let _23: std::pin::Pin<&mut T>; + let _24: &mut U; + let mut _25: &mut T; + let mut _26: &mut T; + let _27: std::pin::Pin<&mut T>; + let _28: &mut U; + let _29: std::pin::Pin<&mut T>; + let _30: &mut U; + let mut _31: &mut T; + let mut _32: &mut T; + let _33: std::pin::Pin<&mut T>; + let _34: &mut U; + let _35: std::pin::Pin<&mut T>; + let _36: &mut U; + let mut _37: &mut T; + let mut _38: &mut T; + let _39: std::pin::Pin<&mut T>; + let _40: &mut U; + let _41: std::pin::Pin<&mut T>; + let _42: &mut U; + let mut _43: &mut T; + let mut _44: &mut T; + let _45: std::pin::Pin<&mut T>; + let _46: &mut U; + let _47: std::pin::Pin<&mut T>; + let _48: &mut U; + let mut _49: &mut T; + let mut _50: &mut T; + let _51: std::pin::Pin<&mut T>; + let _52: &mut U; + let _53: std::pin::Pin<&mut T>; + let _54: &mut U; + let mut _55: &mut T; + let mut _56: &mut T; + scope 1 { + debug x => _9; + debug y => _10; + debug z => _11; + debug w => _12; + } + scope 2 { + debug x => _15; + debug y => _16; + debug z => _17; + debug w => _18; + } + scope 3 { + debug x => _21; + debug y => _22; + debug z => _23; + debug w => _24; + } + scope 4 { + debug x => _27; + debug y => _28; + debug z => _29; + debug w => _30; + } + scope 5 { + debug x => _33; + debug y => _34; + debug z => _35; + debug w => _36; + } + scope 6 { + debug x => _39; + debug y => _40; + debug z => _41; + debug w => _42; + } + scope 7 { + debug x => _45; + debug y => _46; + debug z => _47; + debug w => _48; + } + scope 8 { + debug x => _51; + debug y => _52; + debug z => _53; + debug w => _54; + } + + bb0: { + PlaceMention(_1); + _8 = discriminant((*_1)); + switchInt(move _8) -> [0: bb2, 1: bb16, otherwise: bb1]; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb2: { + _4 = discriminant((((*_1) as Foo).0: Baz)); + switchInt(move _4) -> [0: bb4, 1: bb10, otherwise: bb3]; + } + + bb3: { + goto -> bb1; + } + + bb4: { + _2 = discriminant((((*_1) 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) 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) as Bar).0: Baz)); + switchInt(move _7) -> [0: bb18, 1: bb24, otherwise: bb17]; + } + + bb17: { + goto -> bb1; + } + + bb18: { + _5 = discriminant((((*_1) 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) 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(_51); + _55 = &mut (((((*_1) as Bar).0: Baz) as Bar).0: T); + _51 = Pin::<&mut T> { __pointer: move _55 }; + StorageLive(_52); + _52 = &mut (((((*_1) as Bar).0: Baz) as Bar).1: U); + StorageLive(_53); + _56 = &mut (((((*_1) as Bar).1: Baz) as Bar).0: T); + _53 = Pin::<&mut T> { __pointer: move _56 }; + StorageLive(_54); + _54 = &mut (((((*_1) as Bar).1: Baz) as Bar).1: U); + _0 = const (); + StorageDead(_54); + StorageDead(_53); + StorageDead(_52); + StorageDead(_51); + goto -> bb37; + } + + bb29: { + goto -> bb25; + } + + bb30: { + StorageLive(_45); + _49 = &mut (((((*_1) as Bar).0: Baz) as Bar).0: T); + _45 = Pin::<&mut T> { __pointer: move _49 }; + StorageLive(_46); + _46 = &mut (((((*_1) as Bar).0: Baz) as Bar).1: U); + StorageLive(_47); + _50 = &mut (((((*_1) as Bar).1: Baz) as Foo).0: T); + _47 = Pin::<&mut T> { __pointer: move _50 }; + StorageLive(_48); + _48 = &mut (((((*_1) as Bar).1: Baz) as Foo).1: U); + _0 = const (); + StorageDead(_48); + StorageDead(_47); + StorageDead(_46); + StorageDead(_45); + goto -> bb37; + } + + bb31: { + StorageLive(_39); + _43 = &mut (((((*_1) as Bar).0: Baz) as Foo).0: T); + _39 = Pin::<&mut T> { __pointer: move _43 }; + StorageLive(_40); + _40 = &mut (((((*_1) as Bar).0: Baz) as Foo).1: U); + StorageLive(_41); + _44 = &mut (((((*_1) as Bar).1: Baz) as Bar).0: T); + _41 = Pin::<&mut T> { __pointer: move _44 }; + StorageLive(_42); + _42 = &mut (((((*_1) as Bar).1: Baz) as Bar).1: U); + _0 = const (); + StorageDead(_42); + StorageDead(_41); + StorageDead(_40); + StorageDead(_39); + goto -> bb37; + } + + bb32: { + StorageLive(_33); + _37 = &mut (((((*_1) as Bar).0: Baz) as Foo).0: T); + _33 = Pin::<&mut T> { __pointer: move _37 }; + StorageLive(_34); + _34 = &mut (((((*_1) as Bar).0: Baz) as Foo).1: U); + StorageLive(_35); + _38 = &mut (((((*_1) as Bar).1: Baz) as Foo).0: T); + _35 = Pin::<&mut T> { __pointer: move _38 }; + StorageLive(_36); + _36 = &mut (((((*_1) as Bar).1: Baz) as Foo).1: U); + _0 = const (); + StorageDead(_36); + StorageDead(_35); + StorageDead(_34); + StorageDead(_33); + goto -> bb37; + } + + bb33: { + StorageLive(_27); + _31 = &mut (((((*_1) as Foo).0: Baz) as Bar).0: T); + _27 = Pin::<&mut T> { __pointer: move _31 }; + StorageLive(_28); + _28 = &mut (((((*_1) as Foo).0: Baz) as Bar).1: U); + StorageLive(_29); + _32 = &mut (((((*_1) as Foo).1: Baz) as Bar).0: T); + _29 = Pin::<&mut T> { __pointer: move _32 }; + StorageLive(_30); + _30 = &mut (((((*_1) as Foo).1: Baz) as Bar).1: U); + _0 = const (); + StorageDead(_30); + StorageDead(_29); + StorageDead(_28); + StorageDead(_27); + goto -> bb37; + } + + bb34: { + StorageLive(_21); + _25 = &mut (((((*_1) as Foo).0: Baz) as Bar).0: T); + _21 = Pin::<&mut T> { __pointer: move _25 }; + StorageLive(_22); + _22 = &mut (((((*_1) as Foo).0: Baz) as Bar).1: U); + StorageLive(_23); + _26 = &mut (((((*_1) as Foo).1: Baz) as Foo).0: T); + _23 = Pin::<&mut T> { __pointer: move _26 }; + StorageLive(_24); + _24 = &mut (((((*_1) as Foo).1: Baz) as Foo).1: U); + _0 = const (); + StorageDead(_24); + StorageDead(_23); + StorageDead(_22); + StorageDead(_21); + goto -> bb37; + } + + bb35: { + StorageLive(_15); + _19 = &mut (((((*_1) as Foo).0: Baz) as Foo).0: T); + _15 = Pin::<&mut T> { __pointer: move _19 }; + StorageLive(_16); + _16 = &mut (((((*_1) as Foo).0: Baz) as Foo).1: U); + StorageLive(_17); + _20 = &mut (((((*_1) as Foo).1: Baz) as Bar).0: T); + _17 = Pin::<&mut T> { __pointer: move _20 }; + StorageLive(_18); + _18 = &mut (((((*_1) as Foo).1: Baz) as Bar).1: U); + _0 = const (); + StorageDead(_18); + StorageDead(_17); + StorageDead(_16); + StorageDead(_15); + goto -> bb37; + } + + bb36: { + StorageLive(_9); + _13 = &mut (((((*_1) as Foo).0: Baz) as Foo).0: T); + _9 = Pin::<&mut T> { __pointer: move _13 }; + StorageLive(_10); + _10 = &mut (((((*_1) as Foo).0: Baz) as Foo).1: U); + StorageLive(_11); + _14 = &mut (((((*_1) as Foo).1: Baz) as Foo).0: T); + _11 = Pin::<&mut T> { __pointer: move _14 }; + StorageLive(_12); + _12 = &mut (((((*_1) as Foo).1: Baz) as Foo).1: U); + _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..2de14b4d14e13 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_const.built.after.mir @@ -0,0 +1,72 @@ +// 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: &U; + let mut _5: &T; + let _6: std::pin::Pin<&T>; + let _7: &U; + let mut _8: &T; + scope 1 { + debug x => _3; + debug y => _4; + } + scope 2 { + debug x => _6; + debug y => _7; + } + + bb0: { + PlaceMention(_1); + _2 = discriminant((*_1)); + 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(_6); + _8 = &(((*_1) as Bar).0: T); + _6 = Pin::<&T> { __pointer: move _8 }; + StorageLive(_7); + _7 = &(((*_1) as Bar).1: U); + _0 = const (); + StorageDead(_7); + StorageDead(_6); + goto -> bb7; + } + + bb5: { + goto -> bb1; + } + + bb6: { + StorageLive(_3); + _5 = &(((*_1) as Foo).0: T); + _3 = Pin::<&T> { __pointer: move _5 }; + StorageLive(_4); + _4 = &(((*_1) as Foo).1: U); + _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..9377d3a1dbc0f --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.baz_mut.built.after.mir @@ -0,0 +1,72 @@ +// 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: &mut U; + let mut _5: &mut T; + let _6: std::pin::Pin<&mut T>; + let _7: &mut U; + let mut _8: &mut T; + scope 1 { + debug x => _3; + debug y => _4; + } + scope 2 { + debug x => _6; + debug y => _7; + } + + bb0: { + PlaceMention(_1); + _2 = discriminant((*_1)); + 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(_6); + _8 = &mut (((*_1) as Bar).0: T); + _6 = Pin::<&mut T> { __pointer: move _8 }; + StorageLive(_7); + _7 = &mut (((*_1) as Bar).1: U); + _0 = const (); + StorageDead(_7); + StorageDead(_6); + goto -> bb7; + } + + bb5: { + goto -> bb1; + } + + bb6: { + StorageLive(_3); + _5 = &mut (((*_1) as Foo).0: T); + _3 = Pin::<&mut T> { __pointer: move _5 }; + StorageLive(_4); + _4 = &mut (((*_1) as Foo).1: U); + _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..363d6a7e98748 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_const.built.after.mir @@ -0,0 +1,43 @@ +// 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: &U; + let _4: std::pin::Pin<&T>; + let _5: &U; + let mut _6: &T; + let mut _7: &T; + scope 1 { + debug x => _2; + debug y => _3; + debug z => _4; + debug w => _5; + } + + bb0: { + PlaceMention(_1); + StorageLive(_2); + _6 = &(((*_1).0: Bar).0: T); + _2 = Pin::<&T> { __pointer: move _6 }; + StorageLive(_3); + _3 = &(((*_1).0: Bar).1: U); + StorageLive(_4); + _7 = &(((*_1).1: Bar).0: T); + _4 = Pin::<&T> { __pointer: move _7 }; + StorageLive(_5); + _5 = &(((*_1).1: Bar).1: U); + _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..c5871a2fb4a26 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_bar_mut.built.after.mir @@ -0,0 +1,43 @@ +// 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: &mut U; + let _4: std::pin::Pin<&mut T>; + let _5: &mut U; + let mut _6: &mut T; + let mut _7: &mut T; + scope 1 { + debug x => _2; + debug y => _3; + debug z => _4; + debug w => _5; + } + + bb0: { + PlaceMention(_1); + StorageLive(_2); + _6 = &mut (((*_1).0: Bar).0: T); + _2 = Pin::<&mut T> { __pointer: move _6 }; + StorageLive(_3); + _3 = &mut (((*_1).0: Bar).1: U); + StorageLive(_4); + _7 = &mut (((*_1).1: Bar).0: T); + _4 = Pin::<&mut T> { __pointer: move _7 }; + StorageLive(_5); + _5 = &mut (((*_1).1: Bar).1: U); + _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..95d62aacfb778 --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_const.built.after.mir @@ -0,0 +1,31 @@ +// 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: &U; + let mut _4: &T; + scope 1 { + debug x => _2; + debug y => _3; + } + + bb0: { + PlaceMention(_1); + StorageLive(_2); + _4 = &((*_1).0: T); + _2 = Pin::<&T> { __pointer: move _4 }; + StorageLive(_3); + _3 = &((*_1).1: U); + _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..043e7a9bbd51e --- /dev/null +++ b/tests/mir-opt/pin-ergonomics/project_pattern_match.foo_mut.built.after.mir @@ -0,0 +1,31 @@ +// 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: &mut U; + let mut _4: &mut T; + scope 1 { + debug x => _2; + debug y => _3; + } + + bb0: { + PlaceMention(_1); + StorageLive(_2); + _4 = &mut ((*_1).0: T); + _2 = Pin::<&mut T> { __pointer: move _4 }; + StorageLive(_3); + _3 = &mut ((*_1).1: U); + _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/async-await/pin-ergonomics/project-pattern-match.normal.stderr b/tests/ui/async-await/pin-ergonomics/project-pattern-match.normal.stderr new file mode 100644 index 0000000000000..04284fbd68063 --- /dev/null +++ b/tests/ui/async-await/pin-ergonomics/project-pattern-match.normal.stderr @@ -0,0 +1,313 @@ +error[E0308]: mismatched types + --> $DIR/project-pattern-match.rs:41: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/project-pattern-match.rs:48: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/project-pattern-match.rs:55: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/project-pattern-match.rs:62: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/project-pattern-match.rs:69: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/project-pattern-match.rs:78: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/project-pattern-match.rs:88: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/project-pattern-match.rs:93: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/project-pattern-match.rs:103: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/project-pattern-match.rs:108: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/project-pattern-match.rs:118: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/project-pattern-match.rs:125: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/project-pattern-match.rs:132: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/project-pattern-match.rs:139: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/project-pattern-match.rs:151: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/project-pattern-match.rs:156: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/project-pattern-match.rs:161: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/project-pattern-match.rs:168: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/project-pattern-match.rs:175: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/project-pattern-match.rs:182: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/async-await/pin-ergonomics/project-pattern-match.rs b/tests/ui/async-await/pin-ergonomics/project-pattern-match.rs new file mode 100644 index 0000000000000..8f290e55a8dc0 --- /dev/null +++ b/tests/ui/async-await/pin-ergonomics/project-pattern-match.rs @@ -0,0 +1,192 @@ +//@ revisions: pin_project normal +//@ edition:2024 +//@[pin_project] check-pass +#![cfg_attr(pin_project, 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 {} +trait IsRefMut {} +trait IsRef {} +impl IsPinMut for Pin<&mut T> {} +impl IsPinConst for Pin<&T> {} +impl IsRefMut for &mut T {} +impl IsRef for &T {} + +fn assert_pin_mut(_: T) {} +fn assert_pin_const(_: T) {} +fn assert_ref_mut(_: T) {} +fn assert_ref(_: T) {} + +fn foo_mut(foo: Pin<&mut Foo>) { + let Foo { x, y } = foo; + //[normal]~^ ERROR mismatched types + assert_pin_mut(x); + assert_ref_mut(y); +} + +fn foo_const(foo: Pin<&Foo>) { + let Foo { x, y } = foo; + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_ref(y); +} + +fn bar_mut(bar: Pin<&mut Bar>) { + let Bar(x, y) = bar; + //[normal]~^ ERROR mismatched types + assert_pin_mut(x); + assert_ref_mut(y); +} + +fn bar_const(bar: Pin<&Bar>) { + let Bar(x, y) = bar; + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_ref(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_ref_mut(y); + assert_pin_mut(z); + assert_ref_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_ref(y); + assert_pin_const(z); + assert_ref(w); +} + +fn baz_mut(baz: Pin<&mut Baz>) { + match baz { + Baz::Foo(x, y) => { + //[normal]~^ ERROR mismatched types + assert_pin_mut(x); + assert_ref_mut(y); + } + Baz::Bar { x, y } => { + //[normal]~^ ERROR mismatched types + assert_pin_mut(x); + assert_ref_mut(y); + } + } +} + +fn baz_const(baz: Pin<&Baz>) { + match baz { + Baz::Foo(x, y) => { + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_ref(y); + } + Baz::Bar { x, y } => { + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_ref(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_ref_mut(y); + assert_pin_mut(z); + assert_ref_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_ref_mut(y); + assert_pin_mut(z); + assert_ref_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_ref_mut(y); + assert_pin_mut(z); + assert_ref_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_ref_mut(y); + assert_pin_mut(z); + assert_ref_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_ref(y); + } + Baz::Bar { x: _, y: bar } if let Baz::Bar { x, y } = bar => { + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_ref(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_ref(y); + assert_pin_const(z); + assert_ref(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_ref(y); + assert_pin_const(z); + assert_ref(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_ref(y); + assert_pin_const(z); + assert_ref(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_ref(y); + assert_pin_const(z); + assert_ref(w); + } + } +} + +fn main() {} diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout index 910582ae4d9e9..282459103bb12 100644 --- a/tests/ui/thir-print/thir-tree-match.stdout +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -12,6 +12,7 @@ params: [ kind: PatKind { Binding { name: "foo" + pinnedness: Not mode: BindingMode(No, Not) var: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).2)) ty: Foo From 16ddefaf9f43b3bd88360e4978f10eff8326f2ca Mon Sep 17 00:00:00 2001 From: Frank King Date: Thu, 1 May 2025 22:39:34 +0800 Subject: [PATCH 2/2] Project pinned references to pinned fields --- 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 | 4 +- compiler/rustc_borrowck/src/lib.rs | 15 +- compiler/rustc_borrowck/src/type_check/mod.rs | 6 +- compiler/rustc_codegen_llvm/src/abi.rs | 2 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 2 +- .../rustc_codegen_ssa/src/mir/debuginfo.rs | 4 +- compiler/rustc_codegen_ssa/src/mir/operand.rs | 4 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 2 +- .../src/const_eval/eval_queries.rs | 2 +- .../src/interpret/intrinsics.rs | 6 +- .../src/interpret/operator.rs | 2 +- .../rustc_const_eval/src/interpret/place.rs | 7 +- .../src/util/check_validity_requirement.rs | 2 +- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_hir_analysis/src/autoderef.rs | 41 +- .../rustc_hir_analysis/src/check/region.rs | 2 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 7 +- .../rustc_hir_typeck/src/expr_use_visitor.rs | 57 ++- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 2 +- compiler/rustc_hir_typeck/src/pat.rs | 153 ++++---- compiler/rustc_hir_typeck/src/place_op.rs | 4 +- compiler/rustc_hir_typeck/src/writeback.rs | 11 +- compiler/rustc_lint/src/static_mut_refs.rs | 2 +- compiler/rustc_middle/src/mir/statement.rs | 2 +- compiler/rustc_middle/src/thir.rs | 7 +- compiler/rustc_middle/src/thir/visit.rs | 1 + compiler/rustc_middle/src/ty/adjustment.rs | 3 + compiler/rustc_middle/src/ty/sty.rs | 9 +- .../rustc_middle/src/ty/typeck_results.rs | 20 +- compiler/rustc_middle/src/ty/util.rs | 22 -- .../src/builder/matches/match_pair.rs | 18 +- .../src/builder/matches/mod.rs | 15 +- .../rustc_mir_build/src/check_unsafety.rs | 3 +- .../src/thir/pattern/check_match.rs | 10 +- .../src/thir/pattern/migration.rs | 2 +- .../rustc_mir_build/src/thir/pattern/mod.rs | 25 +- compiler/rustc_mir_build/src/thir/print.rs | 9 +- .../rustc_mir_transform/src/check_pointers.rs | 2 +- .../src/dataflow_const_prop.rs | 2 +- compiler/rustc_mir_transform/src/gvn.rs | 10 +- .../src/mentioned_items.rs | 4 +- compiler/rustc_mir_transform/src/validate.rs | 11 +- .../src/partitioning/autodiff.rs | 2 +- compiler/rustc_parse/src/parser/mod.rs | 10 +- compiler/rustc_parse/src/parser/pat.rs | 11 +- .../rustc_pattern_analysis/src/constructor.rs | 39 +- compiler/rustc_pattern_analysis/src/rustc.rs | 50 +-- .../rustc_pattern_analysis/src/rustc/print.rs | 23 +- .../rustc_pattern_analysis/src/usefulness.rs | 2 +- compiler/rustc_symbol_mangling/src/v0.rs | 5 +- .../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_lints/src/operators/cmp_owned.rs | 2 +- .../clippy/clippy_lints/src/question_mark.rs | 8 +- .../clippy/clippy_lints/src/utils/author.rs | 4 + .../clippy/clippy_utils/src/eager_or_lazy.rs | 2 +- src/tools/clippy/clippy_utils/src/lib.rs | 4 +- .../clippy_utils/src/qualify_min_const_fn.rs | 2 +- .../diagnostics/match_check/pat_analysis.rs | 2 +- src/tools/rustfmt/src/patterns.rs | 2 +- ...ct_pattern_match.bar_const.built.after.mir | 10 +- ...ject_pattern_match.bar_mut.built.after.mir | 10 +- ...attern_match.baz_baz_const.built.after.mir | 352 ++++++++++-------- ..._pattern_match.baz_baz_mut.built.after.mir | 352 ++++++++++-------- ...ct_pattern_match.baz_const.built.after.mir | 34 +- ...ject_pattern_match.baz_mut.built.after.mir | 34 +- ...attern_match.foo_bar_const.built.after.mir | 22 +- ..._pattern_match.foo_bar_mut.built.after.mir | 22 +- ...ct_pattern_match.foo_const.built.after.mir | 10 +- ...ject_pattern_match.foo_mut.built.after.mir | 10 +- .../project-pattern-match.normal.stderr | 40 +- .../pin-ergonomics/project-pattern-match.rs | 66 ++-- 81 files changed, 937 insertions(+), 764 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 1532ca77f713e..1d6236730ce47 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -719,14 +719,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 @@ -744,20 +744,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 0985ebf945bbd..ee993d13c8d69 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1624,10 +1624,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 2d86eb06d9def..0078f560249a3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1225,7 +1225,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; @@ -1588,7 +1588,7 @@ fn suggest_ampmut<'tcx>( } else { // otherwise, suggest that the user annotates the binding; we provide the // type of the local. - let ty = decl_ty.builtin_deref(true, tcx).unwrap(); + let ty = decl_ty.builtin_deref(true).unwrap(); Some(AmpMutSugg { has_sugg: false, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index d5420c82c201b..5a99364458abf 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2472,10 +2472,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // Check the kind of deref to decide match base_ty.kind() { - _ if let Some((_, _, _, mutbl)) = - base_ty.is_ref_or_pin_ref(self.infcx.tcx) => - { - // FIXME(pin_ergonomics): handle `&pin mut|const T` + _ if let &ty::Ref(_, _, mutbl) = base_ty.kind() => { match mutbl { // Shared borrowed data is never mutable hir::Mutability::Not => Err(place), @@ -2516,6 +2513,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_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 597bc480abeeb..e498f6461a26b 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1761,7 +1761,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } else if let Some(static_def_id) = constant.check_static_ptr(tcx) { let unnormalized_ty = tcx.type_of(static_def_id).instantiate_identity(); let normalized_ty = self.normalize(unnormalized_ty, locations); - let literal_ty = constant.const_.ty().builtin_deref(true, tcx).unwrap(); + let literal_ty = constant.const_.ty().builtin_deref(true).unwrap(); if let Err(terr) = self.eq_types(literal_ty, normalized_ty, locations, ConstraintCategory::Boring) @@ -2360,9 +2360,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { debug!("add_reborrow_constraint - base_ty = {:?}", base_ty); match base_ty.kind() { - _ if let Some((ref_region, _, _, mutbl)) = - base_ty.is_ref_or_pin_ref(tcx) => - { + _ if let &ty::Ref(ref_region, _, mutbl) = base_ty.kind() => { // FIXME(pin_ergonomics): handle `&pin mut|const T` constraints.outlives_constraints.push(OutlivesConstraint { sup: ref_region.as_var(), diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 02e5ba423e2d9..8294e29d07df6 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -626,7 +626,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { let element_type_index = unsafe { llvm::LLVMRustGetElementTypeArgIndex(callsite) }; if element_type_index >= 0 { let arg_ty = self.args[element_type_index as usize].layout.ty; - let pointee_ty = arg_ty.builtin_deref(true, bx.tcx).expect("Must be pointer argument"); + let pointee_ty = arg_ty.builtin_deref(true).expect("Must be pointer argument"); let element_type_attr = unsafe { llvm::LLVMRustCreateElementTypeAttr(bx.llcx, bx.layout_of(pointee_ty).llvm_type(bx)) }; diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 8d563ae202d40..d1d6bcebd33ab 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -2532,7 +2532,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( if name == sym::simd_arith_offset { // This also checks that the first operand is a ptr type. - let pointee = in_elem.builtin_deref(true, bx.tcx).unwrap_or_else(|| { + let pointee = in_elem.builtin_deref(true).unwrap_or_else(|| { span_bug!(span, "must be called with a vector of pointer types as first argument") }); let layout = bx.layout_of(pointee); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index ccd3ce2f01430..d184ce3d61dea 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1106,7 +1106,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Make sure that we've actually unwrapped the rcvr down // to a pointer or ref to `dyn* Trait`. - if !op.layout.ty.builtin_deref(true, bx.tcx()).unwrap().is_dyn_star() { + if !op.layout.ty.builtin_deref(true).unwrap().is_dyn_star() { span_bug!(span, "can't codegen a virtual call on {:#?}", op); } let place = op.deref(bx.cx()); diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 89830098c654c..5924c8991ad64 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -130,9 +130,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx> { fn deref(&self, bx: &mut Bx) -> Self { bx.cx().layout_of( - self.ty - .builtin_deref(true, bx.tcx()) - .unwrap_or_else(|| bug!("cannot deref `{}`", self.ty)), + self.ty.builtin_deref(true).unwrap_or_else(|| bug!("cannot deref `{}`", self.ty)), ) } diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index bc32a03dd46e9..eade9e52de95a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -291,7 +291,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let projected_ty = self .layout .ty - .builtin_deref(true, cx.tcx()) + .builtin_deref(true) .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self)); let layout = cx.layout_of(projected_ty); @@ -701,7 +701,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue { let unsized_ty = indirect_dest .layout .ty - .builtin_deref(true, bx.tcx()) + .builtin_deref(true) .unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest)); let OperandValue::Ref(PlaceValue { llval: llptr, llextra: Some(llextra), .. }) = self diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 9cb66d3d92bee..5c14fe5cd10b7 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -966,7 +966,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::BinOp::BitXor => bx.xor(lhs, rhs), mir::BinOp::Offset => { let pointee_type = lhs_ty - .builtin_deref(true, bx.tcx()) + .builtin_deref(true) .unwrap_or_else(|| bug!("deref of non-pointer {:?}", lhs_ty)); let pointee_layout = bx.cx().layout_of(pointee_type); if pointee_layout.is_zst() { diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index cb72a05d2e976..ce8eceebdf8d2 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -216,7 +216,7 @@ pub(super) fn op_to_const<'tcx>( // This codepath solely exists for `valtree_to_const_value` to not need to generate // a `ConstValue::Indirect` for wide references, so it is tightly restricted to just // that case. - let pointee_ty = imm.layout.ty.builtin_deref(false, *ecx.tcx).unwrap(); // `false` = no raw ptrs + let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap(); // `false` = no raw ptrs debug_assert!( matches!( ecx.tcx.struct_tail_for_codegen(pointee_ty, ecx.typing_env()).kind(), diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 8c7a4f1c1da60..4ca317e3a1e53 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -636,7 +636,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { nonoverlapping: bool, ) -> InterpResult<'tcx> { let count = self.read_target_usize(count)?; - let layout = self.layout_of(src.layout.ty.builtin_deref(true, *self.tcx).unwrap())?; + let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap())?; let (size, align) = (layout.size, layout.align.abi); let size = self.compute_size_in_bytes(size, count).ok_or_else(|| { @@ -696,7 +696,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { count: &OpTy<'tcx, >::Provenance>, name: &'static str, ) -> InterpResult<'tcx> { - let layout = self.layout_of(dst.layout.ty.builtin_deref(true, *self.tcx).unwrap())?; + let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap())?; let dst = self.read_pointer(dst)?; let byte = self.read_scalar(byte)?.to_u8()?; @@ -735,7 +735,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { lhs: &OpTy<'tcx, >::Provenance>, rhs: &OpTy<'tcx, >::Provenance>, ) -> InterpResult<'tcx, Scalar> { - let layout = self.layout_of(lhs.layout.ty.builtin_deref(true, *self.tcx).unwrap())?; + let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap())?; assert!(layout.is_sized()); let get_bytes = |this: &InterpCx<'tcx, M>, diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 810b8ceef5ec2..899670aeb62da 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -313,7 +313,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Pointer ops that are always supported. Offset => { let ptr = left.to_scalar().to_pointer(self)?; - let pointee_ty = left.layout.ty.builtin_deref(true, *self.tcx).unwrap(); + let pointee_ty = left.layout.ty.builtin_deref(true).unwrap(); let pointee_layout = self.layout_of(pointee_ty)?; assert!(pointee_layout.is_sized()); diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 29e67ab06f0e6..f5d3de7b1b270 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -419,11 +419,8 @@ where &self, val: &ImmTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { - let pointee_type = val - .layout - .ty - .builtin_deref(true, *self.tcx) - .expect("`ref_to_mplace` called on non-ptr type"); + let pointee_type = + val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type"); let layout = self.layout_of(pointee_type)?; let (ptr, meta) = val.to_scalar_and_meta(); diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 1bc00f9266d28..d7e97f32bae92 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -126,7 +126,7 @@ fn check_validity_requirement_lax<'tcx>( } // Special magic check for references and boxes (i.e., special pointer types). - if let Some(pointee) = this.ty.builtin_deref(false, cx.tcx()) { + if let Some(pointee) = this.ty.builtin_deref(false) { let pointee = cx.layout_of(pointee)?; // We need to ensure that the LLVM attributes `aligned` and `dereferenceable(size)` are satisfied. if pointee.align.abi.bytes() > 1 { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index d02c767ea677a..87424712b6d54 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/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index 972e2aa0d2c4f..99e495d926690 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -77,28 +77,27 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { // be better to skip this clause and use the Overloaded case only, since &T // and &mut T implement Receiver. But built-in derefs apply equally to Receiver // and Deref, and this has benefits for const and the emitted MIR. - let (kind, new_ty) = if let Some(ty) = - self.state.cur_ty.builtin_deref(self.include_raw_pointers, self.infcx.tcx) - { - debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty)); - // NOTE: we may still need to normalize the built-in deref in case - // we have some type like `&::Assoc`, since users of - // autoderef expect this type to have been structurally normalized. - if self.infcx.next_trait_solver() - && let ty::Alias(..) = ty.kind() - { - let (normalized_ty, obligations) = self.structurally_normalize_ty(ty)?; - self.state.obligations.extend(obligations); - (AutoderefKind::Builtin, normalized_ty) + let (kind, new_ty) = + if let Some(ty) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) { + debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty)); + // NOTE: we may still need to normalize the built-in deref in case + // we have some type like `&::Assoc`, since users of + // autoderef expect this type to have been structurally normalized. + if self.infcx.next_trait_solver() + && let ty::Alias(..) = ty.kind() + { + let (normalized_ty, obligations) = self.structurally_normalize_ty(ty)?; + self.state.obligations.extend(obligations); + (AutoderefKind::Builtin, normalized_ty) + } else { + (AutoderefKind::Builtin, ty) + } + } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) { + // The overloaded deref check already normalizes the pointee type. + (AutoderefKind::Overloaded, ty) } else { - (AutoderefKind::Builtin, ty) - } - } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) { - // The overloaded deref check already normalizes the pointee type. - (AutoderefKind::Overloaded, ty) - } else { - return None; - }; + return None; + }; self.state.steps.push((self.state.cur_ty, kind)); debug!( diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 7cb31a64e13e6..9da8ca6f7a2a5 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -659,7 +659,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_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 2b84eebe7d803..33d5a86beb3b0 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1808,7 +1808,7 @@ fn check_method_receiver<'tcx>( match receiver_validity_err { ReceiverValidityError::DoesNotDeref if arbitrary_self_types_level.is_some() => { let hint = match receiver_ty - .builtin_deref(false, tcx) + .builtin_deref(false) .unwrap_or(receiver_ty) .ty_adt_def() .and_then(|adt_def| tcx.get_diagnostic_name(adt_def.did())) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index ff4385c3bccec..17d9ca6d04587 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1882,10 +1882,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 40f7cc0db356d..c740f79250fbf 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -985,7 +985,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); } @@ -1258,25 +1258,34 @@ 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(_)) { - // 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. - match self - .cx - .try_structurally_resolve_type(pat.span, base_ty) - .builtin_deref(false, self.cx.tcx()) - { - Some(ty) => Ok(ty), - None => { - debug!("By-ref binding of non-derefable type"); - Err(self - .cx - .report_bug(pat.span, "by-ref binding of non-derefable type")) + match bm.0 { + hir::ByRef::Yes(pinnedness, _) => { + let base_ty = if pinnedness.is_pinned() { + base_ty.pinned_ty().ok_or_else(|| { + debug!("By-pin-ref binding of non-`Pin` type"); + 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. + match self + .cx + .try_structurally_resolve_type(pat.span, base_ty) + .builtin_deref(false) + { + Some(ty) => Ok(ty), + None => { + debug!("By-ref binding of non-derefable type"); + Err(self + .cx + .report_bug(pat.span, "by-ref binding of non-derefable type")) + } } } - } else { - Ok(base_ty) + _ => Ok(base_ty), } } _ => Ok(base_ty), @@ -1555,7 +1564,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx let deref_ty = match self .cx .try_structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), base_curr_ty) - .builtin_deref(true, self.cx.tcx()) + .builtin_deref(true) { Some(ty) => ty, None => { @@ -1704,6 +1713,16 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx }; self.pat_deref_temp(pat.hir_id, pat, target_ty)? } + adjustment::PatAdjust::PinDeref => { + let target_ty = match adjusts.peek() { + Some(&&next_adjust) => next_adjust.source, + // At the end of the deref chain, we get `pat`'s scrutinee. + None => self.pat_ty_unadjusted(pat)?, + }; + 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. diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 4858010cb5dab..87d92b3fbde8d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -703,7 +703,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ret_ty = method.sig.output(); // method returns &T, but the type as visible to user is T, so deref - ret_ty.builtin_deref(true, self.tcx).unwrap() + ret_ty.builtin_deref(true).unwrap() } pub(crate) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool { diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index eb4668f9c194e..585d67d865cf9 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -91,7 +91,6 @@ struct TopInfo<'tcx> { #[derive(Copy, Clone)] struct PatInfo<'tcx> { - pinnedness: Pinnedness, binding_mode: ByRef, max_ref_mutbl: MutblCap, top_info: TopInfo<'tcx>, @@ -370,7 +369,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let top_info = TopInfo { expected, origin_expr, span, hir_id: pat.hir_id }; let pat_info = PatInfo { - pinnedness: Pinnedness::Not, binding_mode: ByRef::No, max_ref_mutbl: MutblCap::Mut, top_info, @@ -411,7 +409,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, }), ); } @@ -469,22 +467,13 @@ 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() { span_bug!(pat.span, "Pattern mutability cap violated!"); } - // If the expected type is `Unpin`, then remove the pinnedness in `pat_info`. - let pat_info = if pat_info.pinnedness == Pinnedness::Pinned - && expected.is_unpin(self.tcx, self.typing_env(self.param_env)) - { - PatInfo { pinnedness: Pinnedness::Not, ..pat_info } - } else { - pat_info - }; - // Resolve type if needed. let expected = if let AdjustMode::Peel { .. } = adjust_mode && pat.default_binding_modes @@ -496,14 +485,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 `&`, `&mut`, `&pin const` or `&pin mut` from the scrutinee type. - // See the examples in `tests/ui/rfcs/rfc-2005-default-binding-mode` - // and `tests/ui/async-await/pin-ergonomics/project-pattern-match`. + // Peel off a `&`, `&mut`from the scrutinee type. + // See the examples in `tests/ui/rfcs/rfc-2005-default-binding-mode`. _ if let AdjustMode::Peel { .. } = adjust_mode && pat.default_binding_modes - && let Some((_, pinnedness, inner_ty, inner_mutability)) = - expected.is_ref_or_pin_ref(self.tcx) => + && let &ty::Ref(_, inner_ty, inner_mutability) = expected.kind() => { debug!("inspecting {:?}", expected); @@ -516,43 +519,27 @@ 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 pinnedness = if pinnedness == Pinnedness::Pinned - || pat_info.pinnedness == Pinnedness::Pinned - { - Pinnedness::Pinned - } else { - Pinnedness::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); // Use the old pat info to keep `current_depth` to its old value. - let new_pat_info = - PatInfo { pinnedness, binding_mode, max_ref_mutbl, ..old_pat_info }; + let new_pat_info = PatInfo { binding_mode, max_ref_mutbl, ..old_pat_info }; // Recurse with the new expected type. 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() + // Or `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().deref_patterns() || self.tcx.features().pin_ergonomics()) && let AdjustMode::Peel { kind: PeelKind::Implicit { until_adt } } = adjust_mode && pat.default_binding_modes // For simplicity, only apply overloaded derefs if `expected` is a known ADT. @@ -571,7 +558,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && self .type_implements_trait(deref_trait, [expected], self.param_env) .may_apply() => - { + 'deref_pattern: { + if self.tcx.features().pin_ergonomics() + && 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 {}`. + break 'deref_pattern self.check_pat_inner( + pat, + opt_path_res, + adjust_mode, + inner_ty, + new_pat_info, + ); + } debug!("scrutinee ty {expected:?} is a smart pointer, inserting overloaded deref"); // The scrutinee is a smart pointer; implicitly dereference it. This adds a // requirement that `expected: DerefPure`. @@ -978,11 +1004,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { - let PatInfo { pinnedness, binding_mode: def_br, top_info: ti, .. } = pat_info; + let PatInfo { binding_mode: def_br, top_info: ti, .. } = pat_info; // 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() @@ -1012,8 +1038,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, @@ -1029,7 +1055,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!( @@ -1051,19 +1077,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // ...and store it in a side table: - { - let mut typeck_results = self.typeck_results.borrow_mut(); - typeck_results.pat_binding_modes_mut().insert(pat.hir_id, bm); - if pinnedness == Pinnedness::Pinned { - typeck_results.pinned_pat_bindings_mut().insert(pat.hir_id); - } - } + self.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm); debug!("check_pat_ident: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); 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. @@ -1073,19 +1093,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // See (note_1) for an explanation. self.new_ref_ty(pat.span, mutbl, expected) } - // 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). - }; - - // Wrapping the type into `Pin` if the pattern is pinned - let eq_ty = if pinnedness == Pinnedness::Pinned { - Ty::new_adt( + // 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(&[eq_ty.into()]), - ) - } else { - eq_ty + 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). }; // We have a concrete type for the local, so we do not need to taint it and hide follow up errors *using* the local. @@ -1295,7 +1310,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { inner: &Pat<'_>, ) -> Result<(), ErrorGuaranteed> { if let PatKind::Binding(..) = inner.kind - && let Some(pointee_ty) = self.shallow_resolve(expected).builtin_deref(true, self.tcx) + && let Some(pointee_ty) = self.shallow_resolve(expected).builtin_deref(true) && let ty::Dynamic(..) = pointee_ty.kind() { // This is "x = dyn SomeTrait" being reduced from @@ -2547,7 +2562,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 @@ -3068,8 +3083,8 @@ 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 &= user_bind_annot + == BindingMode(ByRef::Yes(Pinnedness::Not, def_br_mutbl), Mutability::Not); "binding modifier" } else { info.bad_ref_pats = true; diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index 42ac4ca90d019..4fc903cf68b88 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -23,7 +23,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { oprnd_expr: &'tcx hir::Expr<'tcx>, oprnd_ty: Ty<'tcx>, ) -> Option> { - if let Some(ty) = oprnd_ty.builtin_deref(true, self.tcx) { + if let Some(ty) = oprnd_ty.builtin_deref(true) { return Some(ty); } @@ -356,7 +356,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .typeck_results .borrow() .expr_ty_adjusted(base_expr) - .builtin_deref(false, self.tcx) + .builtin_deref(false) .expect("place op takes something that is not a ref"); let arg_ty = match op { diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index cca84dca50010..e9e976b1d6b1b 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -317,13 +317,12 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) { match p.kind { hir::PatKind::Binding(..) => { - let typeck_results = self.fcx.typeck_results.borrow(); - let bm = typeck_results.extract_binding_mode(self.tcx().sess, p.hir_id, p.span); - let pinnedness = typeck_results.pat_binding_pinnedness(p.hir_id); + let bm = self.fcx.typeck_results.borrow().extract_binding_mode( + self.tcx().sess, + p.hir_id, + p.span, + ); self.typeck_results.pat_binding_modes_mut().insert(p.hir_id, bm); - if pinnedness == ty::Pinnedness::Pinned { - self.typeck_results.pinned_pat_bindings_mut().insert(p.hir_id); - } } hir::PatKind::Struct(_, fields, _) => { for field in fields { diff --git a/compiler/rustc_lint/src/static_mut_refs.rs b/compiler/rustc_lint/src/static_mut_refs.rs index 50021157ddab7..8f3d28ec345f2 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/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 1a81f057a902d..d59b6df44ed5d 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -176,7 +176,7 @@ impl<'tcx> PlaceTy<'tcx> { } let answer = match *elem { ProjectionElem::Deref => { - let ty = self.ty.builtin_deref(true, tcx).unwrap_or_else(|| { + let ty = self.ty.builtin_deref(true).unwrap_or_else(|| { bug!("deref projection of non-dereferenceable ty {:?}", self) }); PlaceTy::from_ty(ty) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 35f4568fabb2b..b62ca2ae7f229 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -762,8 +762,6 @@ pub enum PatKind<'tcx> { Binding { name: Symbol, #[type_visitable(ignore)] - pinnedness: ty::Pinnedness, - #[type_visitable(ignore)] mode: BindingMode, #[type_visitable(ignore)] var: LocalVarId, @@ -798,6 +796,11 @@ pub enum PatKind<'tcx> { subpattern: Box>, }, + /// `&pin const P` or `&pin mut P`. + RefPin { + subpattern: Box>, + }, + /// Deref pattern, written `box P` for now. DerefPattern { subpattern: Box>, diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index f3da2a5cc8e4e..4152b27ba633c 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -261,6 +261,7 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>( PatKind::AscribeUserType { subpattern, .. } | PatKind::Binding { subpattern: Some(subpattern), .. } | PatKind::Deref { subpattern } + | PatKind::RefPin { subpattern } | PatKind::DerefPattern { subpattern, .. } | PatKind::ExpandedConstant { subpattern, .. } => callback(subpattern), diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index a61a6c571a2cd..550e5bd639644 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -235,4 +235,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/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 0a3fe1fc52ef6..e6a20ca5a36c7 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1430,14 +1430,9 @@ impl<'tcx> Ty<'tcx> { /// /// The parameter `explicit` indicates if this is an *explicit* dereference. /// Some types -- notably raw ptrs -- can only be dereferenced explicitly. - pub fn builtin_deref(self, explicit: bool, tcx: TyCtxt<'tcx>) -> Option> { + pub fn builtin_deref(self, explicit: bool) -> Option> { match *self.kind() { _ if let Some(boxed) = self.boxed_ty() => Some(boxed), - _ if let Some(pinned) = self.pinned_ty() - && let Ref(_, ty, _) = *pinned.kind() => - { - tcx.features().pin_ergonomics().then_some(ty) - } Ref(_, ty, _) => Some(ty), RawPtr(ty, _) if explicit => Some(ty), _ => None, @@ -1777,7 +1772,7 @@ impl<'tcx> Ty<'tcx> { /// Panics if `self` is not dereferencable. #[track_caller] pub fn pointee_metadata_ty_or_projection(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - let Some(pointee_ty) = self.builtin_deref(true, tcx) else { + let Some(pointee_ty) = self.builtin_deref(true) else { bug!("Type {self:?} is not a pointer or reference type") }; if pointee_ty.is_trivially_sized(tcx) { diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 569dabcbd22d8..ca1ad08fd021e 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -24,7 +24,7 @@ use crate::mir::FakeReadCause; use crate::traits::ObligationCause; use crate::ty::{ self, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, GenericArgKind, GenericArgs, - GenericArgsRef, Pinnedness, Ty, UserArgs, tls, + GenericArgsRef, Ty, UserArgs, tls, }; #[derive(TyEncodable, TyDecodable, Debug, HashStable)] @@ -73,9 +73,6 @@ pub struct TypeckResults<'tcx> { /// Stores the actual binding mode for all instances of [`BindingMode`]. pat_binding_modes: ItemLocalMap, - /// Stores the pinned pattern bindings. - pinned_pat_bindings: ItemLocalSet, - /// Top-level patterns incompatible with Rust 2024's match ergonomics. These will be translated /// to a form valid in all Editions, either as a lint diagnostic or hard error. rust_2024_migration_desugared_pats: ItemLocalMap, @@ -229,7 +226,6 @@ impl<'tcx> TypeckResults<'tcx> { node_args: Default::default(), adjustments: Default::default(), pat_binding_modes: Default::default(), - pinned_pat_bindings: Default::default(), pat_adjustments: Default::default(), rust_2024_migration_desugared_pats: Default::default(), skipped_ref_pats: Default::default(), @@ -416,18 +412,6 @@ impl<'tcx> TypeckResults<'tcx> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_binding_modes } } - pub fn pat_binding_pinnedness(&self, id: HirId) -> Pinnedness { - if self.pinned_pat_bindings().contains(id) { Pinnedness::Pinned } else { Pinnedness::Not } - } - - pub fn pinned_pat_bindings(&self) -> LocalSetInContext<'_> { - LocalSetInContext { hir_owner: self.hir_owner, data: &self.pinned_pat_bindings } - } - - pub fn pinned_pat_bindings_mut(&mut self) -> LocalSetInContextMut<'_> { - LocalSetInContextMut { hir_owner: self.hir_owner, data: &mut self.pinned_pat_bindings } - } - pub fn pat_adjustments( &self, ) -> LocalTableInContext<'_, Vec>> { @@ -478,7 +462,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; diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 8aeb09ba7476f..08cee1101d0a9 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1545,28 +1545,6 @@ impl<'tcx> Ty<'tcx> { ty } - /// Destructs a reference type `&'a [mut] T` or a pinned reference type - /// `&'a pin const|mut T` into `'a` the region, `[pin]` the pinnedness, - /// `T` the inner type, and `mut|const` the mutability. - pub fn is_ref_or_pin_ref( - self, - tcx: TyCtxt<'tcx>, - ) -> Option<(ty::Region<'tcx>, ty::Pinnedness, Ty<'tcx>, ty::Mutability)> { - match self.kind() { - &ty::Ref(region, inner_ty, mutbl) => { - Some((region, ty::Pinnedness::Not, inner_ty, mutbl)) - } - ty::Adt(adt, args) - if adt.is_pin() - && let &ty::Ref(region, inner_ty, mutbl) = args.type_at(0).kind() - && tcx.features().pin_ergonomics() => - { - Some((region, ty::Pinnedness::Pinned, inner_ty, mutbl)) - } - _ => None, - } - } - // FIXME(compiler-errors): Think about removing this. #[inline] pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex { 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 210891ecbdebd..0b9e24610bb5e 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use rustc_abi::FieldIdx; use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; @@ -159,7 +160,7 @@ impl<'tcx> MatchPairTree<'tcx> { None } - PatKind::Binding { mode, var, ref subpattern, pinnedness, .. } => { + PatKind::Binding { mode, var, ref subpattern, .. } => { // In order to please the borrow checker, when lowering a pattern // like `x @ subpat` we must establish any bindings in `subpat` // before establishing the binding for `x`. @@ -198,7 +199,6 @@ impl<'tcx> MatchPairTree<'tcx> { source, var_id: var, binding_mode: mode, - pinnedness, }); } @@ -272,6 +272,20 @@ impl<'tcx> MatchPairTree<'tcx> { None } + PatKind::RefPin { ref subpattern } => { + 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, mutability } => { // Create a new temporary for each deref pattern. // FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls? diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 21efca43c3f00..d62c69436cdce 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -10,7 +10,7 @@ use std::borrow::Borrow; use std::mem; use std::sync::Arc; -use rustc_abi::{FIRST_VARIANT, 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, LangItem, LetStmt, LocalSource, Node}; @@ -929,6 +929,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { visit_subpat(self, subpattern, &user_tys.deref(), f); } + PatKind::RefPin { ref subpattern } => { + visit_subpat(self, subpattern, &user_tys.leaf(FieldIdx::ZERO).deref(), f); + } + PatKind::DerefPattern { ref subpattern, .. } => { visit_subpat(self, subpattern, &ProjectedUserTypesNode::None, f); } @@ -1230,7 +1234,6 @@ struct Binding<'tcx> { source: Place<'tcx>, var_id: LocalVarId, binding_mode: BindingMode, - pinnedness: ty::Pinnedness, } /// Indicates that the type of `source` must be a subtype of the @@ -2704,7 +2707,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,7 +2719,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let rvalue = Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source); - let rvalue = match binding.pinnedness { + let rvalue = match pinnedness { ty::Pinnedness::Not => rvalue, ty::Pinnedness::Pinned => { self.pin_borrowed_local(block, value_for_arm.local, rvalue, source_info) @@ -2764,10 +2767,10 @@ 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) => { + ByRef::Yes(pinnedness, mutbl) => { let rvalue = Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source); - match binding.pinnedness { + match pinnedness { ty::Pinnedness::Not => rvalue, ty::Pinnedness::Pinned => { self.pin_borrowed_local(block, local.local, rvalue, source_info) diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index adfce99a9b537..686274bf09563 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -323,6 +323,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { | PatKind::Variant { .. } | PatKind::Leaf { .. } | PatKind::Deref { .. } + | PatKind::RefPin { .. } | PatKind::DerefPattern { .. } | PatKind::Range { .. } | PatKind::Slice { .. } @@ -377,7 +378,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 2a187bb0e0eb7..ad6761590957b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -782,7 +782,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) } }); @@ -798,7 +798,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). @@ -808,7 +808,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`. @@ -974,7 +974,7 @@ fn report_unreachable_pattern<'p, 'tcx>( if cx.is_uninhabited(ty) { lint.matches_no_values_ty = ty; false // No need to dig further. - } else if matches!(subpat.ctor(), Constructor::Ref(_) | Constructor::UnionField) { + } else if matches!(subpat.ctor(), Constructor::Ref | Constructor::UnionField) { false // Don't explore further since they are not by-value. } else { true @@ -1195,7 +1195,7 @@ fn report_arm_reachability<'p, 'tcx>( fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool { match pat.ctor() { Constructor::Wildcard => true, - Constructor::Struct | Constructor::Ref(_) => { + Constructor::Struct | Constructor::Ref => { pat.iter_fields().all(|ipat| pat_is_catchall(&ipat.pat)) } _ => false, 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 77ef5499b8ceb..25eeaf3d4d0ca 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -116,6 +116,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { if mutable { hir::Mutability::Mut } else { hir::Mutability::Not }; PatKind::DerefPattern { subpattern: thir_pat, mutability } } + PatAdjust::PinDeref => PatKind::RefPin { subpattern: thir_pat }, }; Box::new(Pat { span, ty: adjust.source, kind }) }); @@ -349,8 +350,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { .get(pat.hir_id) .expect("missing binding mode"); - let pinnedness = self.typeck_results.pat_binding_pinnedness(pat.hir_id); - if let Some(s) = &mut self.rust_2024_migration { s.visit_binding(pat.span, mode, explicit_ba, ident); } @@ -358,17 +357,27 @@ 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 Some((_, _, rty, _)) = ty.is_ref_or_pin_ref(self.tcx) { - 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), } }; PatKind::Binding { mode, - pinnedness, name: ident.name, var: LocalVarId(id), ty: var_ty, diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 248f35708ec69..240bdc964272e 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -678,10 +678,9 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_pat(subpattern, depth_lvl + 3); print_indented!(self, "}", depth_lvl + 1); } - PatKind::Binding { name, pinnedness, mode, var, ty, subpattern, is_primary } => { + PatKind::Binding { name, mode, var, ty, subpattern, is_primary } => { print_indented!(self, "Binding {", depth_lvl + 1); print_indented!(self, format!("name: {:?}", name), depth_lvl + 2); - print_indented!(self, format!("pinnedness: {:?}", pinnedness), depth_lvl + 2); print_indented!(self, format!("mode: {:?}", mode), depth_lvl + 2); print_indented!(self, format!("var: {:?}", var), depth_lvl + 2); print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 2); @@ -731,6 +730,12 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_pat(subpattern, depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } + PatKind::RefPin { subpattern } => { + print_indented!(self, "PinRef { ", depth_lvl + 1); + print_indented!(self, "subpattern:", depth_lvl + 2); + self.print_pat(subpattern, depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } PatKind::DerefPattern { subpattern, .. } => { print_indented!(self, "DerefPattern { ", depth_lvl + 1); print_indented!(self, "subpattern:", depth_lvl + 2); diff --git a/compiler/rustc_mir_transform/src/check_pointers.rs b/compiler/rustc_mir_transform/src/check_pointers.rs index 52c647307aa87..2d04b62193585 100644 --- a/compiler/rustc_mir_transform/src/check_pointers.rs +++ b/compiler/rustc_mir_transform/src/check_pointers.rs @@ -195,7 +195,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PointerFinder<'a, 'tcx> { } let pointee_ty = - pointer_ty.builtin_deref(true, self.tcx).expect("no builtin_deref for an raw pointer"); + pointer_ty.builtin_deref(true).expect("no builtin_deref for an raw pointer"); // Ideally we'd support this in the future, but for now we are limited to sized types. if !pointee_ty.is_sized(self.tcx, self.typing_env) { trace!("Raw pointer, but pointee is not known to be sized: {:?}", pointer_ty); diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 19c5d99752d00..90173da17f0fc 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -391,7 +391,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { if let Some(target_len) = self.map.find_len(target.as_ref()) && let operand_ty = operand.ty(self.local_decls, self.tcx) - && let Some(operand_ty) = operand_ty.builtin_deref(true, self.tcx) + && let Some(operand_ty) = operand_ty.builtin_deref(true) && let ty::Array(_, len) = operand_ty.kind() && let Some(len) = Const::Ty(self.tcx.types.usize, *len) .try_eval_scalar_int(self.tcx, self.typing_env) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 3bdcce5e35224..8b8d1efbbd2e0 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -643,7 +643,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { ProjectionElem::Deref => { let ty = place.ty(self.local_decls, self.tcx).ty; if let Some(Mutability::Not) = ty.ref_mutability() - && let Some(pointee_ty) = ty.builtin_deref(true, self.tcx) + && let Some(pointee_ty) = ty.builtin_deref(true) && pointee_ty.is_freeze(self.tcx, self.typing_env()) { // An immutable borrow `_x` always points to the same value for the @@ -1171,8 +1171,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { to, .. }, - ) if let ty::Slice(..) = to.builtin_deref(true, self.tcx).unwrap().kind() - && let ty::Array(_, len) = from.builtin_deref(true, self.tcx).unwrap().kind() => + ) if let ty::Slice(..) = to.builtin_deref(true).unwrap().kind() + && let ty::Array(_, len) = from.builtin_deref(true).unwrap().kind() => { return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len))); } @@ -1503,9 +1503,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // We have an unsizing cast, which assigns the length to wide pointer metadata. if let Value::Cast { kind, from, to, .. } = self.get(inner) && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) = kind - && let Some(from) = from.builtin_deref(true, self.tcx) + && let Some(from) = from.builtin_deref(true) && let ty::Array(_, len) = from.kind() - && let Some(to) = to.builtin_deref(true, self.tcx) + && let Some(to) = to.builtin_deref(true) && let ty::Slice(..) = to.kind() { return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len))); diff --git a/compiler/rustc_mir_transform/src/mentioned_items.rs b/compiler/rustc_mir_transform/src/mentioned_items.rs index 28f1354590647..9fd8d81d64a26 100644 --- a/compiler/rustc_mir_transform/src/mentioned_items.rs +++ b/compiler/rustc_mir_transform/src/mentioned_items.rs @@ -83,8 +83,8 @@ impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> { // add everything that may involve a vtable. let source_ty = operand.ty(self.body, self.tcx); let may_involve_vtable = match ( - source_ty.builtin_deref(true, self.tcx).map(|t| t.kind()), - target_ty.builtin_deref(true, self.tcx).map(|t| t.kind()), + source_ty.builtin_deref(true).map(|t| t.kind()), + target_ty.builtin_deref(true).map(|t| t.kind()), ) { // &str/&[T] unsizing (Some(ty::Array(..)), Some(ty::Str | ty::Slice(..))) => false, diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index fa63d157a1a1c..66fe3ef4141f5 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1431,12 +1431,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } if let Rvalue::CopyForDeref(place) = rvalue { - if place - .ty(&self.body.local_decls, self.tcx) - .ty - .builtin_deref(true, self.tcx) - .is_none() - { + if place.ty(&self.body.local_decls, self.tcx).ty.builtin_deref(true).is_none() { self.fail( location, "`CopyForDeref` should only be used for dereferenceable types", @@ -1473,7 +1468,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { CopyNonOverlapping { src, dst, count }, )) => { let src_ty = src.ty(&self.body.local_decls, self.tcx); - let op_src_ty = if let Some(src_deref) = src_ty.builtin_deref(true, self.tcx) { + let op_src_ty = if let Some(src_deref) = src_ty.builtin_deref(true) { src_deref } else { self.fail( @@ -1483,7 +1478,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { return; }; let dst_ty = dst.ty(&self.body.local_decls, self.tcx); - let op_dst_ty = if let Some(dst_deref) = dst_ty.builtin_deref(true, self.tcx) { + let op_dst_ty = if let Some(dst_deref) = dst_ty.builtin_deref(true) { dst_deref } else { self.fail( diff --git a/compiler/rustc_monomorphize/src/partitioning/autodiff.rs b/compiler/rustc_monomorphize/src/partitioning/autodiff.rs index d0e7f3fc21368..22d593b80b895 100644 --- a/compiler/rustc_monomorphize/src/partitioning/autodiff.rs +++ b/compiler/rustc_monomorphize/src/partitioning/autodiff.rs @@ -20,7 +20,7 @@ fn adjust_activity_to_abi<'tcx>(tcx: TyCtxt<'tcx>, fn_ty: Ty<'tcx>, da: &mut Vec let mut new_activities = vec![]; let mut new_positions = vec![]; for (i, ty) in sig.inputs().iter().enumerate() { - if let Some(inner_ty) = ty.builtin_deref(true, tcx) { + if let Some(inner_ty) = ty.builtin_deref(true) { if inner_ty.is_slice() { // Now we need to figure out the size of each slice element in memory to allow // safety checks and usability improvements in the backend. diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 2221a261b4c59..3f0b0ec9c809f 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -30,8 +30,8 @@ use rustc_ast::tokenstream::{AttrsTarget, Spacing, TokenStream, TokenTree}; 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; @@ -1425,7 +1425,11 @@ 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)) { + 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 d5f469f9aa9ef..5fa2046275b86 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.into_inner().kind) diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index 50da2a7aaaf42..0169e960dc631 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -183,7 +183,6 @@ use std::iter::once; use rustc_apfloat::ieee::{DoubleS, HalfS, IeeeFloat, QuadS, SingleS}; use rustc_index::IndexVec; use rustc_index::bit_set::{DenseBitSet, GrowableBitSet}; -use rustc_middle::ty::Pinnedness; use smallvec::SmallVec; use self::Constructor::*; @@ -680,8 +679,10 @@ pub enum Constructor { Struct, /// Enum variants. Variant(Cx::VariantIdx), - /// References or pinned reference - Ref(Pinnedness), + /// References + Ref, + /// Pinned references (enabled by the `pin_ergonomics` feature) + RefPin, /// Array and slice patterns. Slice(Slice), /// Union field accesses. @@ -731,7 +732,8 @@ impl Clone for Constructor { match self { Constructor::Struct => Constructor::Struct, Constructor::Variant(idx) => Constructor::Variant(*idx), - Constructor::Ref(pinnedness) => Constructor::Ref(*pinnedness), + Constructor::Ref => Constructor::Ref, + Constructor::RefPin => Constructor::RefPin, Constructor::Slice(slice) => Constructor::Slice(*slice), Constructor::UnionField => Constructor::UnionField, Constructor::Bool(b) => Constructor::Bool(*b), @@ -809,7 +811,8 @@ impl Constructor { (Missing { .. } | NonExhaustive | Hidden, _) => false, (Struct, Struct) => true, - (Ref(self_pin), Ref(other_pin)) => self_pin == other_pin, + (Ref, Ref) => true, + (RefPin, RefPin) => true, (UnionField, UnionField) => true, (Variant(self_id), Variant(other_id)) => self_id == other_id, (Bool(self_b), Bool(other_b)) => self_b == other_b, @@ -902,10 +905,10 @@ impl Constructor { // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should // be careful to detect strings here. However a string literal pattern will never // be reported as a non-exhaustiveness witness, so we can ignore this issue. - Ref(Pinnedness::Not) => { + Ref => { write!(f, "&{:?}", fields.next().unwrap())?; } - Ref(Pinnedness::Pinned) => { + RefPin => { write!(f, "&pin {:?}", fields.next().unwrap())?; } Slice(slice) => { @@ -976,8 +979,10 @@ 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` or `&pin T`. - Ref(Pinnedness), + /// The type is `&T` + Ref, + /// The type is `&pin T` + RefPin, /// The type is a union. Union, /// Booleans. @@ -1061,11 +1066,18 @@ impl ConstructorSet { missing.push(Struct); } } - ConstructorSet::Ref(pinnedness) => { + ConstructorSet::Ref => { if !seen.is_empty() { - present.push(Ref(*pinnedness)); + present.push(Ref); } else { - missing.push(Ref(*pinnedness)); + missing.push(Ref); + } + } + ConstructorSet::RefPin => { + if !seen.is_empty() { + present.push(RefPin); + } else { + missing.push(RefPin); } } ConstructorSet::Union => { @@ -1183,7 +1195,8 @@ impl ConstructorSet { match self { ConstructorSet::Bool | ConstructorSet::Integers { .. } - | ConstructorSet::Ref(_) + | ConstructorSet::Ref + | ConstructorSet::RefPin | ConstructorSet::Union | ConstructorSet::Unlistable => false, ConstructorSet::NoConstructors => true, diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index c4ff6024bac62..327d261ca110a 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -263,12 +263,14 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } _ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"), }, - Ref(expected_pinnedness) => match ty.is_ref_or_pin_ref(self.tcx) { - Some((_, pinnedness, rty, _)) if pinnedness == *expected_pinnedness => { - reveal_and_alloc(cx, once(rty)) - } + Ref => match ty.kind() { + ty::Ref(_, rty, _) => reveal_and_alloc(cx, once(*rty)), _ => bug!("Unexpected type for `Ref` constructor: {ty:?}"), }, + RefPin => match ty.pinned_ty().map(|ty| ty.kind()) { + Some(ty::Ref(_, rty, _)) => reveal_and_alloc(cx, once(*rty)), + _ => bug!("Unexpected type for `RefPin` constructor: {ty:?}"), + }, Slice(slice) => match *ty.kind() { ty::Slice(ty) | ty::Array(ty, _) => { let arity = slice.arity(); @@ -303,7 +305,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } _ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"), }, - Ref(_) => 1, + Ref | RefPin => 1, Slice(slice) => slice.arity(), Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Str(..) | Opaque(..) | Never | NonExhaustive | Hidden | Missing @@ -385,7 +387,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { && args.type_at(0).is_ref() && self.tcx.features().pin_ergonomics() => { - ConstructorSet::Ref(ty::Pinnedness::Pinned) + ConstructorSet::RefPin } ty::Adt(def, args) if def.is_enum() => { let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(ty); @@ -429,7 +431,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { ty::Adt(..) | ty::Tuple(..) => { ConstructorSet::Struct { empty: cx.is_uninhabited(ty.inner()) } } - ty::Ref(..) => ConstructorSet::Ref(ty::Pinnedness::Not), + ty::Ref(..) => ConstructorSet::Ref, ty::Never => ConstructorSet::NoConstructors, // This type is one for which we cannot list constructors, like `str` or `f64`. // FIXME(Nadrieril): which of these are actually allowed? @@ -504,9 +506,9 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { && args.type_at(0).is_ref() && self.tcx.features().pin_ergonomics() => { - Ref(ty::Pinnedness::Pinned) + todo!() } - ty::Ref(..) => Ref(ty::Pinnedness::Not), + ty::Ref(..) => Ref, _ => span_bug!( pat.span, "pattern has unexpected type: pat: {:?}, ty: {:?}", @@ -515,6 +517,11 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { ), }; } + PatKind::RefPin { subpattern } => { + fields = vec![self.lower_pat(subpattern).at_index(0)]; + arity = 1; + ctor = RefPin; + } PatKind::DerefPattern { .. } => { // FIXME(deref_patterns): At least detect that `box _` is irrefutable. fields = vec![]; @@ -531,12 +538,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { .map(|ipat| self.lower_pat(&ipat.pattern).at_index(ipat.field.index())) .collect(); } - ty::Adt(adt, args) - if adt.is_box() - || adt.is_pin() - && args.type_at(0).is_ref() - && self.tcx.features().pin_ergonomics() => - { + ty::Adt(adt, _) 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. // FIXME(Nadrieril): A `Box` can in theory be matched either with `Box(_, @@ -555,12 +557,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } else { fields = vec![]; } - if adt.is_pin() { - debug_assert!(args.type_at(0).is_ref()); - ctor = Ref(ty::Pinnedness::Pinned); - } else { - ctor = Struct; - } + ctor = Struct; arity = 1; } ty::Adt(adt, _) => { @@ -671,7 +668,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { // Note: `t` is `str`, not `&str`. let ty = self.reveal_opaque_ty(*t); let subpattern = DeconstructedPat::new(Str(*value), Vec::new(), 0, ty, pat); - ctor = Ref(ty::Pinnedness::Not); + ctor = Ref; fields = vec![subpattern.at_index(0)]; arity = 1; } @@ -901,9 +898,14 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { .unwrap(); s } - Ref(_) => { + Ref => { + let mut s = String::new(); + print::write_ref_like(&mut s, pat.ty().inner(), &print(&pat.fields[0])).unwrap(); + s + } + RefPin => { let mut s = String::new(); - print::write_ref_like(&mut s, self.tcx, pat.ty().inner(), &print(&pat.fields[0])) + print::write_ref_pin_like(&mut s, pat.ty().inner(), &print(&pat.fields[0])) .unwrap(); s } diff --git a/compiler/rustc_pattern_analysis/src/rustc/print.rs b/compiler/rustc_pattern_analysis/src/rustc/print.rs index 3d8b2d845a31f..4126d8602431b 100644 --- a/compiler/rustc_pattern_analysis/src/rustc/print.rs +++ b/compiler/rustc_pattern_analysis/src/rustc/print.rs @@ -127,22 +127,33 @@ pub(crate) fn write_struct_like<'tcx>( pub(crate) fn write_ref_like<'tcx>( f: &mut impl fmt::Write, - tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, subpattern: &str, ) -> fmt::Result { - match ty.is_ref_or_pin_ref(tcx) { - Some((_, ty::Pinnedness::Not, _, mutbl)) => { + match ty.kind() { + ty::Ref(_, _, mutbl) => { write!(f, "&{}", mutbl.prefix_str())?; } - Some((_, ty::Pinnedness::Pinned, _, mutbl)) => { - write!(f, "&pin {} ", mutbl.ptr_str())?; - } _ => bug!("{ty} is a bad ref pattern type"), } write!(f, "{subpattern}") } +pub(crate) fn write_ref_pin_like<'tcx>( + f: &mut impl fmt::Write, + ty: Ty<'tcx>, + subpattern: &str, +) -> fmt::Result { + if let Some(ty) = ty.pinned_ty() + && let ty::Ref(_, _, mutbl) = ty.kind() + { + write!(f, "&pin {} ", mutbl.ptr_str())?; + } else { + bug!("{ty} is a bad ref pin pattern type"); + } + write!(f, "{subpattern}") +} + pub(crate) fn write_slice_like( f: &mut impl fmt::Write, prefix: &[String], diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index fd0fad776c481..6162d15e04498 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -866,7 +866,7 @@ impl PlaceValidity { /// inside `&` and union fields where validity is reset to `MaybeInvalid`. fn specialize(self, ctor: &Constructor) -> Self { // We preserve validity except when we go inside a reference or a union field. - if matches!(ctor, Constructor::Ref(_) | Constructor::UnionField) { + if matches!(ctor, Constructor::Ref | Constructor::RefPin | Constructor::UnionField) { // Validity of `x: &T` does not imply validity of `*x: T`. MaybeInvalid } else { diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 5f72a8a71ad3d..f310aa6550025 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -721,9 +721,8 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { hir::Mutability::Mut => "Q", }); - let pointee_ty = ct_ty - .builtin_deref(true, self.tcx) - .expect("tried to dereference on non-ptr type"); + let pointee_ty = + ct_ty.builtin_deref(true).expect("tried to dereference on non-ptr type"); let dereferenced_const = ty::Const::new_value(self.tcx, valtree, pointee_ty); dereferenced_const.print(self)?; } 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 989997d69f7c7..8e54020ded3bc 100644 --- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs +++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs @@ -94,7 +94,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 7e65d586110e5..398ea946ad779 100644 --- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs @@ -182,7 +182,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 9bbef8da0a466..0e37be9835ac2 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 1ee27d90d0545..5bc7a8aa24cab 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/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs index 9b3f1dea743a5..cf6b8992973a7 100644 --- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs +++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs @@ -67,7 +67,7 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) let without_deref = symmetric_partial_eq(cx, arg_ty, other_ty).unwrap_or_default(); let with_deref = arg_ty - .builtin_deref(true, cx.tcx) + .builtin_deref(true) .and_then(|ty| symmetric_partial_eq(cx, ty, other_ty)) .unwrap_or_default(); diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index a80e1f79bbc77..bad8fc415d783 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -147,7 +147,7 @@ fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) { let init_expr_str = snippet_with_applicability(cx, init_expr.span, "..", &mut applicability); // 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, @@ -166,7 +166,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` @@ -475,8 +475,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 b7dcd2ffb0eea..1d4509946c15f 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -685,10 +685,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 e9505c0eb5750..db8653ee36e7c 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -216,7 +216,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS .cx .typeck_results() .expr_ty(e) - .builtin_deref(true, self.cx.tcx) + .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 f715fc86e4e5d..9b7107e8210cb 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1177,7 +1177,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); }, _ => (), @@ -2195,7 +2195,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/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 13e1c77163836..5d0401010db6a 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -141,7 +141,7 @@ fn check_rvalue<'tcx>( _, ) => Err((span, "function pointer casts are not allowed in const fn".into())), Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize, _), op, cast_ty) => { - let Some(pointee_ty) = cast_ty.builtin_deref(true, cx.tcx) else { + let Some(pointee_ty) = cast_ty.builtin_deref(true) else { // We cannot allow this for now. return Err((span, "unsizing casts are only allowed for references right now".into())); }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index 23a67d1cd20bb..5f45993d4ae68 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -299,7 +299,7 @@ impl<'db> MatchCheckCtx<'db> { // be careful to reconstruct the correct constant pattern here. However a string // literal pattern will never be reported as a non-exhaustiveness witness, so we // ignore this issue. - Ref(_) => PatKind::Deref { subpattern: subpatterns.next().unwrap() }, + Ref => PatKind::Deref { subpattern: subpatterns.next().unwrap() }, Slice(_) => unimplemented!(), &Str(void) => match void {}, Wildcard | NonExhaustive | Hidden | PrivateUninhabited => PatKind::Wild, diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index cb3879f4be8c9..50aa99fe3d7c2 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -135,7 +135,7 @@ 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()), + 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 index d99480556ae0f..15f7446cc5912 100644 --- 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 @@ -4,8 +4,9 @@ fn bar_const(_1: Pin<&Bar>) -> () { debug bar => _1; let mut _0: (); let _2: std::pin::Pin<&T>; - let _3: &U; + let _3: std::pin::Pin<&U>; let mut _4: &T; + let mut _5: &U; scope 1 { debug x => _2; debug y => _3; @@ -14,10 +15,11 @@ fn bar_const(_1: Pin<&Bar>) -> () { bb0: { PlaceMention(_1); StorageLive(_2); - _4 = &((*_1).0: T); - _2 = Pin::<&T> { __pointer: move _4 }; + _4 = &((*(_1.0: &Bar)).0: T); + _2 = Pin::<&T> { pointer: move _4 }; StorageLive(_3); - _3 = &((*_1).1: U); + _5 = &((*(_1.0: &Bar)).1: U); + _3 = Pin::<&U> { pointer: move _5 }; _0 = const (); StorageDead(_3); StorageDead(_2); 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 index f2d2e36fc1d00..46fd15502ffb1 100644 --- 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 @@ -4,8 +4,9 @@ fn bar_mut(_1: Pin<&mut Bar>) -> () { debug bar => _1; let mut _0: (); let _2: std::pin::Pin<&mut T>; - let _3: &mut U; + 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; @@ -14,10 +15,11 @@ fn bar_mut(_1: Pin<&mut Bar>) -> () { bb0: { PlaceMention(_1); StorageLive(_2); - _4 = &mut ((*_1).0: T); - _2 = Pin::<&mut T> { __pointer: move _4 }; + _4 = &mut ((*(_1.0: &mut Bar)).0: T); + _2 = Pin::<&mut T> { pointer: move _4 }; StorageLive(_3); - _3 = &mut ((*_1).1: U); + _5 = &mut ((*(_1.0: &mut Bar)).1: U); + _3 = Pin::<&mut U> { pointer: move _5 }; _0 = const (); StorageDead(_3); StorageDead(_2); 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 index 03c6c0d9d1041..8cfaf50a5f876 100644 --- 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 @@ -11,53 +11,69 @@ fn baz_baz_const(_1: Pin<&Baz, Baz>>) -> () { let mut _7: isize; let mut _8: isize; let _9: std::pin::Pin<&T>; - let _10: &U; + let _10: std::pin::Pin<&U>; let _11: std::pin::Pin<&T>; - let _12: &U; + let _12: std::pin::Pin<&U>; let mut _13: &T; - let mut _14: &T; - let _15: std::pin::Pin<&T>; - let _16: &U; + let mut _14: &U; + let mut _15: &T; + let mut _16: &U; let _17: std::pin::Pin<&T>; - let _18: &U; - let mut _19: &T; - let mut _20: &T; - let _21: std::pin::Pin<&T>; - let _22: &U; - let _23: std::pin::Pin<&T>; - let _24: &U; - let mut _25: &T; - let mut _26: &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: &U; - let _29: std::pin::Pin<&T>; - let _30: &U; + let _28: std::pin::Pin<&U>; + let mut _29: &T; + let mut _30: &U; let mut _31: &T; - let mut _32: &T; + let mut _32: &U; let _33: std::pin::Pin<&T>; - let _34: &U; + let _34: std::pin::Pin<&U>; let _35: std::pin::Pin<&T>; - let _36: &U; + let _36: std::pin::Pin<&U>; let mut _37: &T; - let mut _38: &T; - let _39: std::pin::Pin<&T>; - let _40: &U; + let mut _38: &U; + let mut _39: &T; + let mut _40: &U; let _41: std::pin::Pin<&T>; - let _42: &U; - let mut _43: &T; - let mut _44: &T; - let _45: std::pin::Pin<&T>; - let _46: &U; - let _47: std::pin::Pin<&T>; - let _48: &U; - let mut _49: &T; - let mut _50: &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: &U; - let _53: std::pin::Pin<&T>; - let _54: &U; + let _52: std::pin::Pin<&U>; + let mut _53: &T; + let mut _54: &U; let mut _55: &T; - let mut _56: &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; @@ -65,51 +81,51 @@ fn baz_baz_const(_1: Pin<&Baz, Baz>>) -> () { debug w => _12; } scope 2 { - debug x => _15; - debug y => _16; - debug z => _17; - debug w => _18; + debug x => _17; + debug y => _18; + debug z => _19; + debug w => _20; } scope 3 { - debug x => _21; - debug y => _22; - debug z => _23; - debug w => _24; + debug x => _25; + debug y => _26; + debug z => _27; + debug w => _28; } scope 4 { - debug x => _27; - debug y => _28; - debug z => _29; - debug w => _30; - } - scope 5 { 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 => _39; - debug y => _40; - debug z => _41; - debug w => _42; + debug x => _49; + debug y => _50; + debug z => _51; + debug w => _52; } scope 7 { - debug x => _45; - debug y => _46; - debug z => _47; - debug w => _48; + debug x => _57; + debug y => _58; + debug z => _59; + debug w => _60; } scope 8 { - debug x => _51; - debug y => _52; - debug z => _53; - debug w => _54; + debug x => _65; + debug y => _66; + debug z => _67; + debug w => _68; } bb0: { PlaceMention(_1); - _8 = discriminant((*_1)); + _8 = discriminant((*(_1.0: &Baz, Baz>))); switchInt(move _8) -> [0: bb2, 1: bb16, otherwise: bb1]; } @@ -119,7 +135,7 @@ fn baz_baz_const(_1: Pin<&Baz, Baz>>) -> () { } bb2: { - _4 = discriminant((((*_1) as Foo).0: Baz)); + _4 = discriminant((((*(_1.0: &Baz, Baz>)) as Foo).0: Baz)); switchInt(move _4) -> [0: bb4, 1: bb10, otherwise: bb3]; } @@ -128,7 +144,7 @@ fn baz_baz_const(_1: Pin<&Baz, Baz>>) -> () { } bb4: { - _2 = discriminant((((*_1) as Foo).1: Baz)); + _2 = discriminant((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz)); switchInt(move _2) -> [0: bb6, 1: bb8, otherwise: bb5]; } @@ -153,7 +169,7 @@ fn baz_baz_const(_1: Pin<&Baz, Baz>>) -> () { } bb10: { - _3 = discriminant((((*_1) as Foo).1: Baz)); + _3 = discriminant((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz)); switchInt(move _3) -> [0: bb12, 1: bb14, otherwise: bb11]; } @@ -178,7 +194,7 @@ fn baz_baz_const(_1: Pin<&Baz, Baz>>) -> () { } bb16: { - _7 = discriminant((((*_1) as Bar).0: Baz)); + _7 = discriminant((((*(_1.0: &Baz, Baz>)) as Bar).0: Baz)); switchInt(move _7) -> [0: bb18, 1: bb24, otherwise: bb17]; } @@ -187,7 +203,7 @@ fn baz_baz_const(_1: Pin<&Baz, Baz>>) -> () { } bb18: { - _5 = discriminant((((*_1) as Bar).1: Baz)); + _5 = discriminant((((*(_1.0: &Baz, Baz>)) as Bar).1: Baz)); switchInt(move _5) -> [0: bb20, 1: bb22, otherwise: bb19]; } @@ -212,7 +228,7 @@ fn baz_baz_const(_1: Pin<&Baz, Baz>>) -> () { } bb24: { - _6 = discriminant((((*_1) as Bar).1: Baz)); + _6 = discriminant((((*(_1.0: &Baz, Baz>)) as Bar).1: Baz)); switchInt(move _6) -> [0: bb26, 1: bb28, otherwise: bb25]; } @@ -229,21 +245,23 @@ fn baz_baz_const(_1: Pin<&Baz, Baz>>) -> () { } bb28: { - StorageLive(_51); - _55 = &(((((*_1) as Bar).0: Baz) as Bar).0: T); - _51 = Pin::<&T> { __pointer: move _55 }; - StorageLive(_52); - _52 = &(((((*_1) as Bar).0: Baz) as Bar).1: U); - StorageLive(_53); - _56 = &(((((*_1) as Bar).1: Baz) as Bar).0: T); - _53 = Pin::<&T> { __pointer: move _56 }; - StorageLive(_54); - _54 = &(((((*_1) as Bar).1: Baz) as Bar).1: U); + 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(_54); - StorageDead(_53); - StorageDead(_52); - StorageDead(_51); + StorageDead(_68); + StorageDead(_67); + StorageDead(_66); + StorageDead(_65); goto -> bb37; } @@ -252,54 +270,81 @@ fn baz_baz_const(_1: Pin<&Baz, Baz>>) -> () { } bb30: { - StorageLive(_45); - _49 = &(((((*_1) as Bar).0: Baz) as Bar).0: T); - _45 = Pin::<&T> { __pointer: move _49 }; - StorageLive(_46); - _46 = &(((((*_1) as Bar).0: Baz) as Bar).1: U); - StorageLive(_47); - _50 = &(((((*_1) as Bar).1: Baz) as Foo).0: T); - _47 = Pin::<&T> { __pointer: move _50 }; - StorageLive(_48); - _48 = &(((((*_1) as Bar).1: Baz) as Foo).1: U); + 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(_48); - StorageDead(_47); - StorageDead(_46); - StorageDead(_45); + StorageDead(_60); + StorageDead(_59); + StorageDead(_58); + StorageDead(_57); goto -> bb37; } bb31: { - StorageLive(_39); - _43 = &(((((*_1) as Bar).0: Baz) as Foo).0: T); - _39 = Pin::<&T> { __pointer: move _43 }; - StorageLive(_40); - _40 = &(((((*_1) as Bar).0: Baz) as Foo).1: U); + 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); - _44 = &(((((*_1) as Bar).1: Baz) as Bar).0: T); - _41 = Pin::<&T> { __pointer: move _44 }; + _45 = &(((((*(_1.0: &Baz, Baz>)) as Bar).0: Baz) as Foo).0: T); + _41 = Pin::<&T> { pointer: move _45 }; StorageLive(_42); - _42 = &(((((*_1) as Bar).1: Baz) as Bar).1: U); + _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); - StorageDead(_40); - StorageDead(_39); goto -> bb37; } - bb32: { + bb33: { StorageLive(_33); - _37 = &(((((*_1) as Bar).0: Baz) as Foo).0: T); - _33 = Pin::<&T> { __pointer: move _37 }; + _37 = &(((((*(_1.0: &Baz, Baz>)) as Foo).0: Baz) as Bar).0: T); + _33 = Pin::<&T> { pointer: move _37 }; StorageLive(_34); - _34 = &(((((*_1) as Bar).0: Baz) as Foo).1: U); + _38 = &(((((*(_1.0: &Baz, Baz>)) as Foo).0: Baz) as Bar).1: U); + _34 = Pin::<&U> { pointer: move _38 }; StorageLive(_35); - _38 = &(((((*_1) as Bar).1: Baz) as Foo).0: T); - _35 = Pin::<&T> { __pointer: move _38 }; + _39 = &(((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz) as Bar).0: T); + _35 = Pin::<&T> { pointer: move _39 }; StorageLive(_36); - _36 = &(((((*_1) as Bar).1: Baz) as Foo).1: U); + _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); @@ -308,74 +353,61 @@ fn baz_baz_const(_1: Pin<&Baz, Baz>>) -> () { goto -> bb37; } - bb33: { + 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) as Foo).0: Baz) as Bar).0: T); - _27 = Pin::<&T> { __pointer: move _31 }; + _31 = &(((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz) as Foo).0: T); + _27 = Pin::<&T> { pointer: move _31 }; StorageLive(_28); - _28 = &(((((*_1) as Foo).0: Baz) as Bar).1: U); - StorageLive(_29); - _32 = &(((((*_1) as Foo).1: Baz) as Bar).0: T); - _29 = Pin::<&T> { __pointer: move _32 }; - StorageLive(_30); - _30 = &(((((*_1) as Foo).1: Baz) as Bar).1: U); + _32 = &(((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz) as Foo).1: U); + _28 = Pin::<&U> { pointer: move _32 }; _0 = const (); - StorageDead(_30); - StorageDead(_29); StorageDead(_28); StorageDead(_27); - goto -> bb37; - } - - bb34: { - StorageLive(_21); - _25 = &(((((*_1) as Foo).0: Baz) as Bar).0: T); - _21 = Pin::<&T> { __pointer: move _25 }; - StorageLive(_22); - _22 = &(((((*_1) as Foo).0: Baz) as Bar).1: U); - StorageLive(_23); - _26 = &(((((*_1) as Foo).1: Baz) as Foo).0: T); - _23 = Pin::<&T> { __pointer: move _26 }; - StorageLive(_24); - _24 = &(((((*_1) as Foo).1: Baz) as Foo).1: U); - _0 = const (); - StorageDead(_24); - StorageDead(_23); - StorageDead(_22); - StorageDead(_21); + StorageDead(_26); + StorageDead(_25); goto -> bb37; } bb35: { - StorageLive(_15); - _19 = &(((((*_1) as Foo).0: Baz) as Foo).0: T); - _15 = Pin::<&T> { __pointer: move _19 }; - StorageLive(_16); - _16 = &(((((*_1) as Foo).0: Baz) as Foo).1: U); StorageLive(_17); - _20 = &(((((*_1) as Foo).1: Baz) as Bar).0: T); - _17 = Pin::<&T> { __pointer: move _20 }; + _21 = &(((((*(_1.0: &Baz, Baz>)) as Foo).0: Baz) as Foo).0: T); + _17 = Pin::<&T> { pointer: move _21 }; StorageLive(_18); - _18 = &(((((*_1) as Foo).1: Baz) as Bar).1: U); + _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); - StorageDead(_16); - StorageDead(_15); goto -> bb37; } bb36: { StorageLive(_9); - _13 = &(((((*_1) as Foo).0: Baz) as Foo).0: T); - _9 = Pin::<&T> { __pointer: move _13 }; + _13 = &(((((*(_1.0: &Baz, Baz>)) as Foo).0: Baz) as Foo).0: T); + _9 = Pin::<&T> { pointer: move _13 }; StorageLive(_10); - _10 = &(((((*_1) as Foo).0: Baz) as Foo).1: U); + _14 = &(((((*(_1.0: &Baz, Baz>)) as Foo).0: Baz) as Foo).1: U); + _10 = Pin::<&U> { pointer: move _14 }; StorageLive(_11); - _14 = &(((((*_1) as Foo).1: Baz) as Foo).0: T); - _11 = Pin::<&T> { __pointer: move _14 }; + _15 = &(((((*(_1.0: &Baz, Baz>)) as Foo).1: Baz) as Foo).0: T); + _11 = Pin::<&T> { pointer: move _15 }; StorageLive(_12); - _12 = &(((((*_1) as Foo).1: Baz) as Foo).1: U); + _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); 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 index 7627c7f047a88..43c523cbf5717 100644 --- 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 @@ -11,53 +11,69 @@ fn baz_baz_mut(_1: Pin<&mut Baz, Baz>>) -> () { let mut _7: isize; let mut _8: isize; let _9: std::pin::Pin<&mut T>; - let _10: &mut U; + let _10: std::pin::Pin<&mut U>; let _11: std::pin::Pin<&mut T>; - let _12: &mut U; + let _12: std::pin::Pin<&mut U>; let mut _13: &mut T; - let mut _14: &mut T; - let _15: std::pin::Pin<&mut T>; - let _16: &mut U; + let mut _14: &mut U; + let mut _15: &mut T; + let mut _16: &mut U; let _17: std::pin::Pin<&mut T>; - let _18: &mut U; - let mut _19: &mut T; - let mut _20: &mut T; - let _21: std::pin::Pin<&mut T>; - let _22: &mut U; - let _23: std::pin::Pin<&mut T>; - let _24: &mut U; - let mut _25: &mut T; - let mut _26: &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: &mut U; - let _29: std::pin::Pin<&mut T>; - let _30: &mut U; + 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 T; + let mut _32: &mut U; let _33: std::pin::Pin<&mut T>; - let _34: &mut U; + let _34: std::pin::Pin<&mut U>; let _35: std::pin::Pin<&mut T>; - let _36: &mut U; + let _36: std::pin::Pin<&mut U>; let mut _37: &mut T; - let mut _38: &mut T; - let _39: std::pin::Pin<&mut T>; - let _40: &mut U; + let mut _38: &mut U; + let mut _39: &mut T; + let mut _40: &mut U; let _41: std::pin::Pin<&mut T>; - let _42: &mut U; - let mut _43: &mut T; - let mut _44: &mut T; - let _45: std::pin::Pin<&mut T>; - let _46: &mut U; - let _47: std::pin::Pin<&mut T>; - let _48: &mut U; - let mut _49: &mut T; - let mut _50: &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: &mut U; - let _53: std::pin::Pin<&mut T>; - let _54: &mut U; + 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 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; @@ -65,51 +81,51 @@ fn baz_baz_mut(_1: Pin<&mut Baz, Baz>>) -> () { debug w => _12; } scope 2 { - debug x => _15; - debug y => _16; - debug z => _17; - debug w => _18; + debug x => _17; + debug y => _18; + debug z => _19; + debug w => _20; } scope 3 { - debug x => _21; - debug y => _22; - debug z => _23; - debug w => _24; + debug x => _25; + debug y => _26; + debug z => _27; + debug w => _28; } scope 4 { - debug x => _27; - debug y => _28; - debug z => _29; - debug w => _30; - } - scope 5 { 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 => _39; - debug y => _40; - debug z => _41; - debug w => _42; + debug x => _49; + debug y => _50; + debug z => _51; + debug w => _52; } scope 7 { - debug x => _45; - debug y => _46; - debug z => _47; - debug w => _48; + debug x => _57; + debug y => _58; + debug z => _59; + debug w => _60; } scope 8 { - debug x => _51; - debug y => _52; - debug z => _53; - debug w => _54; + debug x => _65; + debug y => _66; + debug z => _67; + debug w => _68; } bb0: { PlaceMention(_1); - _8 = discriminant((*_1)); + _8 = discriminant((*(_1.0: &mut Baz, Baz>))); switchInt(move _8) -> [0: bb2, 1: bb16, otherwise: bb1]; } @@ -119,7 +135,7 @@ fn baz_baz_mut(_1: Pin<&mut Baz, Baz>>) -> () { } bb2: { - _4 = discriminant((((*_1) as Foo).0: Baz)); + _4 = discriminant((((*(_1.0: &mut Baz, Baz>)) as Foo).0: Baz)); switchInt(move _4) -> [0: bb4, 1: bb10, otherwise: bb3]; } @@ -128,7 +144,7 @@ fn baz_baz_mut(_1: Pin<&mut Baz, Baz>>) -> () { } bb4: { - _2 = discriminant((((*_1) as Foo).1: Baz)); + _2 = discriminant((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz)); switchInt(move _2) -> [0: bb6, 1: bb8, otherwise: bb5]; } @@ -153,7 +169,7 @@ fn baz_baz_mut(_1: Pin<&mut Baz, Baz>>) -> () { } bb10: { - _3 = discriminant((((*_1) as Foo).1: Baz)); + _3 = discriminant((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz)); switchInt(move _3) -> [0: bb12, 1: bb14, otherwise: bb11]; } @@ -178,7 +194,7 @@ fn baz_baz_mut(_1: Pin<&mut Baz, Baz>>) -> () { } bb16: { - _7 = discriminant((((*_1) as Bar).0: Baz)); + _7 = discriminant((((*(_1.0: &mut Baz, Baz>)) as Bar).0: Baz)); switchInt(move _7) -> [0: bb18, 1: bb24, otherwise: bb17]; } @@ -187,7 +203,7 @@ fn baz_baz_mut(_1: Pin<&mut Baz, Baz>>) -> () { } bb18: { - _5 = discriminant((((*_1) as Bar).1: Baz)); + _5 = discriminant((((*(_1.0: &mut Baz, Baz>)) as Bar).1: Baz)); switchInt(move _5) -> [0: bb20, 1: bb22, otherwise: bb19]; } @@ -212,7 +228,7 @@ fn baz_baz_mut(_1: Pin<&mut Baz, Baz>>) -> () { } bb24: { - _6 = discriminant((((*_1) as Bar).1: Baz)); + _6 = discriminant((((*(_1.0: &mut Baz, Baz>)) as Bar).1: Baz)); switchInt(move _6) -> [0: bb26, 1: bb28, otherwise: bb25]; } @@ -229,21 +245,23 @@ fn baz_baz_mut(_1: Pin<&mut Baz, Baz>>) -> () { } bb28: { - StorageLive(_51); - _55 = &mut (((((*_1) as Bar).0: Baz) as Bar).0: T); - _51 = Pin::<&mut T> { __pointer: move _55 }; - StorageLive(_52); - _52 = &mut (((((*_1) as Bar).0: Baz) as Bar).1: U); - StorageLive(_53); - _56 = &mut (((((*_1) as Bar).1: Baz) as Bar).0: T); - _53 = Pin::<&mut T> { __pointer: move _56 }; - StorageLive(_54); - _54 = &mut (((((*_1) as Bar).1: Baz) as Bar).1: U); + 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(_54); - StorageDead(_53); - StorageDead(_52); - StorageDead(_51); + StorageDead(_68); + StorageDead(_67); + StorageDead(_66); + StorageDead(_65); goto -> bb37; } @@ -252,54 +270,81 @@ fn baz_baz_mut(_1: Pin<&mut Baz, Baz>>) -> () { } bb30: { - StorageLive(_45); - _49 = &mut (((((*_1) as Bar).0: Baz) as Bar).0: T); - _45 = Pin::<&mut T> { __pointer: move _49 }; - StorageLive(_46); - _46 = &mut (((((*_1) as Bar).0: Baz) as Bar).1: U); - StorageLive(_47); - _50 = &mut (((((*_1) as Bar).1: Baz) as Foo).0: T); - _47 = Pin::<&mut T> { __pointer: move _50 }; - StorageLive(_48); - _48 = &mut (((((*_1) as Bar).1: Baz) as Foo).1: U); + 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(_48); - StorageDead(_47); - StorageDead(_46); - StorageDead(_45); + StorageDead(_60); + StorageDead(_59); + StorageDead(_58); + StorageDead(_57); goto -> bb37; } bb31: { - StorageLive(_39); - _43 = &mut (((((*_1) as Bar).0: Baz) as Foo).0: T); - _39 = Pin::<&mut T> { __pointer: move _43 }; - StorageLive(_40); - _40 = &mut (((((*_1) as Bar).0: Baz) as Foo).1: U); + 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); - _44 = &mut (((((*_1) as Bar).1: Baz) as Bar).0: T); - _41 = Pin::<&mut T> { __pointer: move _44 }; + _45 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Bar).0: Baz) as Foo).0: T); + _41 = Pin::<&mut T> { pointer: move _45 }; StorageLive(_42); - _42 = &mut (((((*_1) as Bar).1: Baz) as Bar).1: U); + _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); - StorageDead(_40); - StorageDead(_39); goto -> bb37; } - bb32: { + bb33: { StorageLive(_33); - _37 = &mut (((((*_1) as Bar).0: Baz) as Foo).0: T); - _33 = Pin::<&mut T> { __pointer: move _37 }; + _37 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).0: Baz) as Bar).0: T); + _33 = Pin::<&mut T> { pointer: move _37 }; StorageLive(_34); - _34 = &mut (((((*_1) as Bar).0: Baz) as Foo).1: U); + _38 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).0: Baz) as Bar).1: U); + _34 = Pin::<&mut U> { pointer: move _38 }; StorageLive(_35); - _38 = &mut (((((*_1) as Bar).1: Baz) as Foo).0: T); - _35 = Pin::<&mut T> { __pointer: move _38 }; + _39 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz) as Bar).0: T); + _35 = Pin::<&mut T> { pointer: move _39 }; StorageLive(_36); - _36 = &mut (((((*_1) as Bar).1: Baz) as Foo).1: U); + _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); @@ -308,74 +353,61 @@ fn baz_baz_mut(_1: Pin<&mut Baz, Baz>>) -> () { goto -> bb37; } - bb33: { + 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) as Foo).0: Baz) as Bar).0: T); - _27 = Pin::<&mut T> { __pointer: move _31 }; + _31 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz) as Foo).0: T); + _27 = Pin::<&mut T> { pointer: move _31 }; StorageLive(_28); - _28 = &mut (((((*_1) as Foo).0: Baz) as Bar).1: U); - StorageLive(_29); - _32 = &mut (((((*_1) as Foo).1: Baz) as Bar).0: T); - _29 = Pin::<&mut T> { __pointer: move _32 }; - StorageLive(_30); - _30 = &mut (((((*_1) as Foo).1: Baz) as Bar).1: U); + _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(_30); - StorageDead(_29); StorageDead(_28); StorageDead(_27); - goto -> bb37; - } - - bb34: { - StorageLive(_21); - _25 = &mut (((((*_1) as Foo).0: Baz) as Bar).0: T); - _21 = Pin::<&mut T> { __pointer: move _25 }; - StorageLive(_22); - _22 = &mut (((((*_1) as Foo).0: Baz) as Bar).1: U); - StorageLive(_23); - _26 = &mut (((((*_1) as Foo).1: Baz) as Foo).0: T); - _23 = Pin::<&mut T> { __pointer: move _26 }; - StorageLive(_24); - _24 = &mut (((((*_1) as Foo).1: Baz) as Foo).1: U); - _0 = const (); - StorageDead(_24); - StorageDead(_23); - StorageDead(_22); - StorageDead(_21); + StorageDead(_26); + StorageDead(_25); goto -> bb37; } bb35: { - StorageLive(_15); - _19 = &mut (((((*_1) as Foo).0: Baz) as Foo).0: T); - _15 = Pin::<&mut T> { __pointer: move _19 }; - StorageLive(_16); - _16 = &mut (((((*_1) as Foo).0: Baz) as Foo).1: U); StorageLive(_17); - _20 = &mut (((((*_1) as Foo).1: Baz) as Bar).0: T); - _17 = Pin::<&mut T> { __pointer: move _20 }; + _21 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).0: Baz) as Foo).0: T); + _17 = Pin::<&mut T> { pointer: move _21 }; StorageLive(_18); - _18 = &mut (((((*_1) as Foo).1: Baz) as Bar).1: U); + _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); - StorageDead(_16); - StorageDead(_15); goto -> bb37; } bb36: { StorageLive(_9); - _13 = &mut (((((*_1) as Foo).0: Baz) as Foo).0: T); - _9 = Pin::<&mut T> { __pointer: move _13 }; + _13 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).0: Baz) as Foo).0: T); + _9 = Pin::<&mut T> { pointer: move _13 }; StorageLive(_10); - _10 = &mut (((((*_1) as Foo).0: Baz) as Foo).1: U); + _14 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).0: Baz) as Foo).1: U); + _10 = Pin::<&mut U> { pointer: move _14 }; StorageLive(_11); - _14 = &mut (((((*_1) as Foo).1: Baz) as Foo).0: T); - _11 = Pin::<&mut T> { __pointer: move _14 }; + _15 = &mut (((((*(_1.0: &mut Baz, Baz>)) as Foo).1: Baz) as Foo).0: T); + _11 = Pin::<&mut T> { pointer: move _15 }; StorageLive(_12); - _12 = &mut (((((*_1) as Foo).1: Baz) as Foo).1: U); + _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); 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 index 2de14b4d14e13..5538449cc43cc 100644 --- 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 @@ -5,23 +5,25 @@ fn baz_const(_1: Pin<&Baz>) -> () { let mut _0: (); let mut _2: isize; let _3: std::pin::Pin<&T>; - let _4: &U; + let _4: std::pin::Pin<&U>; let mut _5: &T; - let _6: std::pin::Pin<&T>; - let _7: &U; - let mut _8: &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 => _6; - debug y => _7; + debug x => _7; + debug y => _8; } bb0: { PlaceMention(_1); - _2 = discriminant((*_1)); + _2 = discriminant((*(_1.0: &Baz))); switchInt(move _2) -> [0: bb2, 1: bb4, otherwise: bb1]; } @@ -39,14 +41,15 @@ fn baz_const(_1: Pin<&Baz>) -> () { } bb4: { - StorageLive(_6); - _8 = &(((*_1) as Bar).0: T); - _6 = Pin::<&T> { __pointer: move _8 }; StorageLive(_7); - _7 = &(((*_1) as Bar).1: U); + _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); - StorageDead(_6); goto -> bb7; } @@ -56,10 +59,11 @@ fn baz_const(_1: Pin<&Baz>) -> () { bb6: { StorageLive(_3); - _5 = &(((*_1) as Foo).0: T); - _3 = Pin::<&T> { __pointer: move _5 }; + _5 = &(((*(_1.0: &Baz)) as Foo).0: T); + _3 = Pin::<&T> { pointer: move _5 }; StorageLive(_4); - _4 = &(((*_1) as Foo).1: U); + _6 = &(((*(_1.0: &Baz)) as Foo).1: U); + _4 = Pin::<&U> { pointer: move _6 }; _0 = const (); StorageDead(_4); StorageDead(_3); 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 index 9377d3a1dbc0f..4ae472cba3a58 100644 --- 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 @@ -5,23 +5,25 @@ fn baz_mut(_1: Pin<&mut Baz>) -> () { let mut _0: (); let mut _2: isize; let _3: std::pin::Pin<&mut T>; - let _4: &mut U; + let _4: std::pin::Pin<&mut U>; let mut _5: &mut T; - let _6: std::pin::Pin<&mut T>; - let _7: &mut U; - let mut _8: &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 => _6; - debug y => _7; + debug x => _7; + debug y => _8; } bb0: { PlaceMention(_1); - _2 = discriminant((*_1)); + _2 = discriminant((*(_1.0: &mut Baz))); switchInt(move _2) -> [0: bb2, 1: bb4, otherwise: bb1]; } @@ -39,14 +41,15 @@ fn baz_mut(_1: Pin<&mut Baz>) -> () { } bb4: { - StorageLive(_6); - _8 = &mut (((*_1) as Bar).0: T); - _6 = Pin::<&mut T> { __pointer: move _8 }; StorageLive(_7); - _7 = &mut (((*_1) as Bar).1: U); + _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); - StorageDead(_6); goto -> bb7; } @@ -56,10 +59,11 @@ fn baz_mut(_1: Pin<&mut Baz>) -> () { bb6: { StorageLive(_3); - _5 = &mut (((*_1) as Foo).0: T); - _3 = Pin::<&mut T> { __pointer: move _5 }; + _5 = &mut (((*(_1.0: &mut Baz)) as Foo).0: T); + _3 = Pin::<&mut T> { pointer: move _5 }; StorageLive(_4); - _4 = &mut (((*_1) as Foo).1: U); + _6 = &mut (((*(_1.0: &mut Baz)) as Foo).1: U); + _4 = Pin::<&mut U> { pointer: move _6 }; _0 = const (); StorageDead(_4); StorageDead(_3); 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 index 363d6a7e98748..8b397ffd18142 100644 --- 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 @@ -4,11 +4,13 @@ fn foo_bar_const(_1: Pin<&Foo, Bar>>) -> () { debug foo => _1; let mut _0: (); let _2: std::pin::Pin<&T>; - let _3: &U; + let _3: std::pin::Pin<&U>; let _4: std::pin::Pin<&T>; - let _5: &U; + let _5: std::pin::Pin<&U>; let mut _6: &T; - let mut _7: &T; + let mut _7: &U; + let mut _8: &T; + let mut _9: &U; scope 1 { debug x => _2; debug y => _3; @@ -19,15 +21,17 @@ fn foo_bar_const(_1: Pin<&Foo, Bar>>) -> () { bb0: { PlaceMention(_1); StorageLive(_2); - _6 = &(((*_1).0: Bar).0: T); - _2 = Pin::<&T> { __pointer: move _6 }; + _6 = &(((*(_1.0: &Foo, Bar>)).0: Bar).0: T); + _2 = Pin::<&T> { pointer: move _6 }; StorageLive(_3); - _3 = &(((*_1).0: Bar).1: U); + _7 = &(((*(_1.0: &Foo, Bar>)).0: Bar).1: U); + _3 = Pin::<&U> { pointer: move _7 }; StorageLive(_4); - _7 = &(((*_1).1: Bar).0: T); - _4 = Pin::<&T> { __pointer: move _7 }; + _8 = &(((*(_1.0: &Foo, Bar>)).1: Bar).0: T); + _4 = Pin::<&T> { pointer: move _8 }; StorageLive(_5); - _5 = &(((*_1).1: Bar).1: U); + _9 = &(((*(_1.0: &Foo, Bar>)).1: Bar).1: U); + _5 = Pin::<&U> { pointer: move _9 }; _0 = const (); StorageDead(_5); StorageDead(_4); 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 index c5871a2fb4a26..2e8128bb9d1e4 100644 --- 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 @@ -4,11 +4,13 @@ fn foo_bar_mut(_1: Pin<&mut Foo, Bar>>) -> () { debug foo => _1; let mut _0: (); let _2: std::pin::Pin<&mut T>; - let _3: &mut U; + let _3: std::pin::Pin<&mut U>; let _4: std::pin::Pin<&mut T>; - let _5: &mut U; + let _5: std::pin::Pin<&mut U>; let mut _6: &mut T; - let mut _7: &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; @@ -19,15 +21,17 @@ fn foo_bar_mut(_1: Pin<&mut Foo, Bar>>) -> () { bb0: { PlaceMention(_1); StorageLive(_2); - _6 = &mut (((*_1).0: Bar).0: T); - _2 = Pin::<&mut T> { __pointer: move _6 }; + _6 = &mut (((*(_1.0: &mut Foo, Bar>)).0: Bar).0: T); + _2 = Pin::<&mut T> { pointer: move _6 }; StorageLive(_3); - _3 = &mut (((*_1).0: Bar).1: U); + _7 = &mut (((*(_1.0: &mut Foo, Bar>)).0: Bar).1: U); + _3 = Pin::<&mut U> { pointer: move _7 }; StorageLive(_4); - _7 = &mut (((*_1).1: Bar).0: T); - _4 = Pin::<&mut T> { __pointer: move _7 }; + _8 = &mut (((*(_1.0: &mut Foo, Bar>)).1: Bar).0: T); + _4 = Pin::<&mut T> { pointer: move _8 }; StorageLive(_5); - _5 = &mut (((*_1).1: Bar).1: U); + _9 = &mut (((*(_1.0: &mut Foo, Bar>)).1: Bar).1: U); + _5 = Pin::<&mut U> { pointer: move _9 }; _0 = const (); StorageDead(_5); StorageDead(_4); 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 index 95d62aacfb778..b77b341d4ef76 100644 --- 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 @@ -4,8 +4,9 @@ fn foo_const(_1: Pin<&Foo>) -> () { debug foo => _1; let mut _0: (); let _2: std::pin::Pin<&T>; - let _3: &U; + let _3: std::pin::Pin<&U>; let mut _4: &T; + let mut _5: &U; scope 1 { debug x => _2; debug y => _3; @@ -14,10 +15,11 @@ fn foo_const(_1: Pin<&Foo>) -> () { bb0: { PlaceMention(_1); StorageLive(_2); - _4 = &((*_1).0: T); - _2 = Pin::<&T> { __pointer: move _4 }; + _4 = &((*(_1.0: &Foo)).0: T); + _2 = Pin::<&T> { pointer: move _4 }; StorageLive(_3); - _3 = &((*_1).1: U); + _5 = &((*(_1.0: &Foo)).1: U); + _3 = Pin::<&U> { pointer: move _5 }; _0 = const (); StorageDead(_3); StorageDead(_2); 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 index 043e7a9bbd51e..c7b88d239f87a 100644 --- 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 @@ -4,8 +4,9 @@ fn foo_mut(_1: Pin<&mut Foo>) -> () { debug foo => _1; let mut _0: (); let _2: std::pin::Pin<&mut T>; - let _3: &mut U; + 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; @@ -14,10 +15,11 @@ fn foo_mut(_1: Pin<&mut Foo>) -> () { bb0: { PlaceMention(_1); StorageLive(_2); - _4 = &mut ((*_1).0: T); - _2 = Pin::<&mut T> { __pointer: move _4 }; + _4 = &mut ((*(_1.0: &mut Foo)).0: T); + _2 = Pin::<&mut T> { pointer: move _4 }; StorageLive(_3); - _3 = &mut ((*_1).1: U); + _5 = &mut ((*(_1.0: &mut Foo)).1: U); + _3 = Pin::<&mut U> { pointer: move _5 }; _0 = const (); StorageDead(_3); StorageDead(_2); diff --git a/tests/ui/async-await/pin-ergonomics/project-pattern-match.normal.stderr b/tests/ui/async-await/pin-ergonomics/project-pattern-match.normal.stderr index 04284fbd68063..0f8368dc47e93 100644 --- a/tests/ui/async-await/pin-ergonomics/project-pattern-match.normal.stderr +++ b/tests/ui/async-await/pin-ergonomics/project-pattern-match.normal.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/project-pattern-match.rs:41:9 + --> $DIR/project-pattern-match.rs:35:9 | LL | let Foo { x, y } = foo; | ^^^^^^^^^^^^ --- this expression has type `Pin<&mut Foo>` @@ -14,7 +14,7 @@ LL | let Foo { x, y } = *foo; | + error[E0308]: mismatched types - --> $DIR/project-pattern-match.rs:48:9 + --> $DIR/project-pattern-match.rs:42:9 | LL | let Foo { x, y } = foo; | ^^^^^^^^^^^^ --- this expression has type `Pin<&Foo>` @@ -29,7 +29,7 @@ LL | let Foo { x, y } = *foo; | + error[E0308]: mismatched types - --> $DIR/project-pattern-match.rs:55:9 + --> $DIR/project-pattern-match.rs:49:9 | LL | let Bar(x, y) = bar; | ^^^^^^^^^ --- this expression has type `Pin<&mut Bar>` @@ -44,7 +44,7 @@ LL | let Bar(x, y) = *bar; | + error[E0308]: mismatched types - --> $DIR/project-pattern-match.rs:62:9 + --> $DIR/project-pattern-match.rs:56:9 | LL | let Bar(x, y) = bar; | ^^^^^^^^^ --- this expression has type `Pin<&Bar>` @@ -59,7 +59,7 @@ LL | let Bar(x, y) = *bar; | + error[E0308]: mismatched types - --> $DIR/project-pattern-match.rs:69:9 + --> $DIR/project-pattern-match.rs:63:9 | LL | let Foo { x: Bar(x, y), y: Bar(z, w) } = foo; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --- this expression has type `Pin<&mut Foo, Bar>>` @@ -74,7 +74,7 @@ LL | let Foo { x: Bar(x, y), y: Bar(z, w) } = *foo; | + error[E0308]: mismatched types - --> $DIR/project-pattern-match.rs:78:9 + --> $DIR/project-pattern-match.rs:72:9 | LL | let Foo { x: Bar(x, y), y: Bar(z, w) } = foo; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --- this expression has type `Pin<&Foo, Bar>>` @@ -89,7 +89,7 @@ LL | let Foo { x: Bar(x, y), y: Bar(z, w) } = *foo; | + error[E0308]: mismatched types - --> $DIR/project-pattern-match.rs:88:9 + --> $DIR/project-pattern-match.rs:82:9 | LL | match baz { | --- this expression has type `Pin<&mut Baz>` @@ -104,7 +104,7 @@ LL | match *baz { | + error[E0308]: mismatched types - --> $DIR/project-pattern-match.rs:93:9 + --> $DIR/project-pattern-match.rs:87:9 | LL | match baz { | --- this expression has type `Pin<&mut Baz>` @@ -120,7 +120,7 @@ LL | match *baz { | + error[E0308]: mismatched types - --> $DIR/project-pattern-match.rs:103:9 + --> $DIR/project-pattern-match.rs:97:9 | LL | match baz { | --- this expression has type `Pin<&Baz>` @@ -135,7 +135,7 @@ LL | match *baz { | + error[E0308]: mismatched types - --> $DIR/project-pattern-match.rs:108:9 + --> $DIR/project-pattern-match.rs:102:9 | LL | match baz { | --- this expression has type `Pin<&Baz>` @@ -151,7 +151,7 @@ LL | match *baz { | + error[E0308]: mismatched types - --> $DIR/project-pattern-match.rs:118:9 + --> $DIR/project-pattern-match.rs:112:9 | LL | match baz { | --- this expression has type `Pin<&mut Baz, Baz>>` @@ -166,7 +166,7 @@ LL | match *baz { | + error[E0308]: mismatched types - --> $DIR/project-pattern-match.rs:125:9 + --> $DIR/project-pattern-match.rs:119:9 | LL | match baz { | --- this expression has type `Pin<&mut Baz, Baz>>` @@ -182,7 +182,7 @@ LL | match *baz { | + error[E0308]: mismatched types - --> $DIR/project-pattern-match.rs:132:9 + --> $DIR/project-pattern-match.rs:126:9 | LL | match baz { | --- this expression has type `Pin<&mut Baz, Baz>>` @@ -198,7 +198,7 @@ LL | match *baz { | + error[E0308]: mismatched types - --> $DIR/project-pattern-match.rs:139:9 + --> $DIR/project-pattern-match.rs:133:9 | LL | match baz { | --- this expression has type `Pin<&mut Baz, Baz>>` @@ -214,7 +214,7 @@ LL | match *baz { | + error[E0308]: mismatched types - --> $DIR/project-pattern-match.rs:151:9 + --> $DIR/project-pattern-match.rs:145:9 | LL | match baz { | --- this expression has type `Pin<&Baz, Baz>>` @@ -229,7 +229,7 @@ LL | match *baz { | + error[E0308]: mismatched types - --> $DIR/project-pattern-match.rs:156:9 + --> $DIR/project-pattern-match.rs:150:9 | LL | match baz { | --- this expression has type `Pin<&Baz, Baz>>` @@ -245,7 +245,7 @@ LL | match *baz { | + error[E0308]: mismatched types - --> $DIR/project-pattern-match.rs:161:9 + --> $DIR/project-pattern-match.rs:155:9 | LL | match baz { | --- this expression has type `Pin<&Baz, Baz>>` @@ -261,7 +261,7 @@ LL | match *baz { | + error[E0308]: mismatched types - --> $DIR/project-pattern-match.rs:168:9 + --> $DIR/project-pattern-match.rs:162:9 | LL | match baz { | --- this expression has type `Pin<&Baz, Baz>>` @@ -277,7 +277,7 @@ LL | match *baz { | + error[E0308]: mismatched types - --> $DIR/project-pattern-match.rs:175:9 + --> $DIR/project-pattern-match.rs:169:9 | LL | match baz { | --- this expression has type `Pin<&Baz, Baz>>` @@ -293,7 +293,7 @@ LL | match *baz { | + error[E0308]: mismatched types - --> $DIR/project-pattern-match.rs:182:9 + --> $DIR/project-pattern-match.rs:176:9 | LL | match baz { | --- this expression has type `Pin<&Baz, Baz>>` diff --git a/tests/ui/async-await/pin-ergonomics/project-pattern-match.rs b/tests/ui/async-await/pin-ergonomics/project-pattern-match.rs index 8f290e55a8dc0..06b6d76daf114 100644 --- a/tests/ui/async-await/pin-ergonomics/project-pattern-match.rs +++ b/tests/ui/async-await/pin-ergonomics/project-pattern-match.rs @@ -25,62 +25,56 @@ enum Baz { trait IsPinMut {} trait IsPinConst {} -trait IsRefMut {} -trait IsRef {} impl IsPinMut for Pin<&mut T> {} impl IsPinConst for Pin<&T> {} -impl IsRefMut for &mut T {} -impl IsRef for &T {} fn assert_pin_mut(_: T) {} fn assert_pin_const(_: T) {} -fn assert_ref_mut(_: T) {} -fn assert_ref(_: T) {} fn foo_mut(foo: Pin<&mut Foo>) { let Foo { x, y } = foo; //[normal]~^ ERROR mismatched types assert_pin_mut(x); - assert_ref_mut(y); + assert_pin_mut(y); } fn foo_const(foo: Pin<&Foo>) { let Foo { x, y } = foo; //[normal]~^ ERROR mismatched types assert_pin_const(x); - assert_ref(y); + 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_ref_mut(y); + assert_pin_mut(y); } fn bar_const(bar: Pin<&Bar>) { let Bar(x, y) = bar; //[normal]~^ ERROR mismatched types assert_pin_const(x); - assert_ref(y); + 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_ref_mut(y); + assert_pin_mut(y); assert_pin_mut(z); - assert_ref_mut(w); + 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_ref(y); + assert_pin_const(y); assert_pin_const(z); - assert_ref(w); + assert_pin_const(w); } fn baz_mut(baz: Pin<&mut Baz>) { @@ -88,12 +82,12 @@ fn baz_mut(baz: Pin<&mut Baz>) { Baz::Foo(x, y) => { //[normal]~^ ERROR mismatched types assert_pin_mut(x); - assert_ref_mut(y); + assert_pin_mut(y); } Baz::Bar { x, y } => { //[normal]~^ ERROR mismatched types assert_pin_mut(x); - assert_ref_mut(y); + assert_pin_mut(y); } } } @@ -103,12 +97,12 @@ fn baz_const(baz: Pin<&Baz>) { Baz::Foo(x, y) => { //[normal]~^ ERROR mismatched types assert_pin_const(x); - assert_ref(y); + assert_pin_const(y); } Baz::Bar { x, y } => { //[normal]~^ ERROR mismatched types assert_pin_const(x); - assert_ref(y); + assert_pin_const(y); } } } @@ -118,30 +112,30 @@ fn baz_baz_mut(baz: Pin<&mut Baz, 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_ref_mut(y); + assert_pin_mut(y); assert_pin_mut(z); - assert_ref_mut(w); + 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_ref_mut(y); + assert_pin_mut(y); assert_pin_mut(z); - assert_ref_mut(w); + 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_ref_mut(y); + assert_pin_mut(y); assert_pin_mut(z); - assert_ref_mut(w); + 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_ref_mut(y); + assert_pin_mut(y); assert_pin_mut(z); - assert_ref_mut(w); + assert_pin_mut(w); } } } @@ -151,40 +145,40 @@ fn baz_baz_const(baz: Pin<&Baz, Baz>>) { Baz::Foo(foo, _) if let Baz::Foo(x, y) = foo => { //[normal]~^ ERROR mismatched types assert_pin_const(x); - assert_ref(y); + 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_ref(y); + 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_ref(y); + assert_pin_const(y); assert_pin_const(z); - assert_ref(w); + 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_ref(y); + assert_pin_const(y); assert_pin_const(z); - assert_ref(w); + 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_ref(y); + assert_pin_const(y); assert_pin_const(z); - assert_ref(w); + 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_ref(y); + assert_pin_const(y); assert_pin_const(z); - assert_ref(w); + assert_pin_const(w); } } }