diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/rustc_ast/src/ast.rs | 1 | ||||
-rw-r--r-- | compiler/rustc_feature/src/unstable.rs | 2 | ||||
-rw-r--r-- | compiler/rustc_hir_typeck/src/pat.rs | 84 | ||||
-rw-r--r-- | compiler/rustc_span/src/symbol.rs | 1 |
4 files changed, 59 insertions, 29 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index dbbc4980050..f2cdedc0087 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -714,6 +714,7 @@ pub enum ByRef { } impl ByRef { + #[must_use] pub fn cap_ref_mutability(mut self, mutbl: Mutability) -> Self { if let ByRef::Yes(old_mutbl) = &mut self { *old_mutbl = cmp::min(*old_mutbl, mutbl); diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index ad6f7da8937..c05cac155b7 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -575,6 +575,8 @@ declare_features! ( (unstable, raw_ref_op, "1.41.0", Some(64490)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024. (incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)), + /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024—structural variant + (incomplete, ref_pat_eat_one_layer_2024_structural, "CURRENT_RUSTC_VERSION", Some(123076)), /// Allows using the `#[register_tool]` attribute. (unstable, register_tool, "1.41.0", Some(66079)), /// Allows the `#[repr(i128)]` attribute for enums. diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 478bbc0ed98..c8db4b97bae 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -328,8 +328,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { adjust_mode: AdjustMode, max_ref_mutbl: MutblCap, ) -> (Ty<'tcx>, ByRef, MutblCap) { - if let ByRef::Yes(Mutability::Mut) = def_br { - debug_assert!(max_ref_mutbl == MutblCap::Mut); + #[cfg(debug_assertions)] + if def_br == ByRef::Yes(Mutability::Mut) && max_ref_mutbl != MutblCap::Mut { + span_bug!(pat.span, "Pattern mutability cap violated!"); } match adjust_mode { AdjustMode::Pass => (expected, def_br, max_ref_mutbl), @@ -437,7 +438,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); } - if self.tcx.features().ref_pat_eat_one_layer_2024 { + let features = self.tcx.features(); + if features.ref_pat_eat_one_layer_2024 || features.ref_pat_eat_one_layer_2024_structural { def_br = def_br.cap_ref_mutability(max_ref_mutbl.as_mutbl()); if def_br == ByRef::Yes(Mutability::Not) { max_ref_mutbl = MutblCap::Not; @@ -669,7 +671,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Determine the binding mode... let bm = match user_bind_annot { BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => { - if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 { + if pat.span.at_least_rust_2024() + && (self.tcx.features().ref_pat_eat_one_layer_2024 + || self.tcx.features().ref_pat_eat_one_layer_2024_structural) + { if !self.tcx.features().mut_ref { feature_err( &self.tcx.sess, @@ -2123,7 +2128,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mut expected: Ty<'tcx>, mut pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { - let no_ref_mut_behind_and = self.tcx.features().ref_pat_eat_one_layer_2024; + let tcx = self.tcx; + let features = tcx.features(); + let ref_pat_eat_one_layer_2024 = features.ref_pat_eat_one_layer_2024; + let ref_pat_eat_one_layer_2024_structural = features.ref_pat_eat_one_layer_2024_structural; + + let no_ref_mut_behind_and = + ref_pat_eat_one_layer_2024 || ref_pat_eat_one_layer_2024_structural; let new_match_ergonomics = pat.span.at_least_rust_2024() && no_ref_mut_behind_and; let pat_prefix_span = @@ -2138,32 +2149,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat_info.max_ref_mutbl = MutblCap::Mut; } + expected = self.try_structurally_resolve_type(pat.span, expected); if new_match_ergonomics { if let ByRef::Yes(inh_mut) = pat_info.binding_mode { - // ref pattern consumes inherited reference - - if pat_mutbl > inh_mut { - // Tried to match inherited `ref` with `&mut`, which is an error - let err_msg = "cannot match inherited `&` with `&mut` pattern"; - let err = if let Some(span) = pat_prefix_span { - let mut err = self.dcx().struct_span_err(span, err_msg); - err.span_suggestion_verbose( - span, - "replace this `&mut` pattern with `&`", - "&", - Applicability::MachineApplicable, - ); - err + if !ref_pat_eat_one_layer_2024 && let ty::Ref(_, _, r_mutbl) = *expected.kind() { + // Don't attempt to consume inherited reference + pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(r_mutbl); + } else { + // ref pattern attempts to consume inherited reference + if pat_mutbl > inh_mut { + // Tried to match inherited `ref` with `&mut` + if !ref_pat_eat_one_layer_2024_structural { + let err_msg = "mismatched types"; + let err = if let Some(span) = pat_prefix_span { + let mut err = self.dcx().struct_span_err(span, err_msg); + err.code(E0308); + err.note("cannot match inherited `&` with `&mut` pattern"); + err.span_suggestion_verbose( + span, + "replace this `&mut` pattern with `&`", + "&", + Applicability::MachineApplicable, + ); + err + } else { + self.dcx().struct_span_err(pat.span, err_msg) + }; + err.emit(); + + pat_info.binding_mode = ByRef::No; + self.typeck_results + .borrow_mut() + .skipped_ref_pats_mut() + .insert(pat.hir_id); + self.check_pat(inner, expected, pat_info); + return expected; + } } else { - self.dcx().struct_span_err(pat.span, err_msg) - }; - err.emit(); + pat_info.binding_mode = ByRef::No; + self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id); + self.check_pat(inner, expected, pat_info); + return expected; + } } - - pat_info.binding_mode = ByRef::No; - self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id); - self.check_pat(inner, expected, pat_info); - return expected; } } else { // Reset binding mode on old editions @@ -2178,8 +2206,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let tcx = self.tcx; - expected = self.try_structurally_resolve_type(pat.span, expected); let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) { Ok(()) => { // `demand::subtype` would be good enough, but using `eqtype` turns diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 7da9211bcbf..af56f4e5141 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1513,6 +1513,7 @@ symbols! { recursion_limit, reexport_test_harness_main, ref_pat_eat_one_layer_2024, + ref_pat_eat_one_layer_2024_structural, ref_pat_everywhere, ref_unwind_safe_trait, reference, |