From 2d633317f30dd02895f167b65dc1feeee0d08265 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 20 Mar 2024 16:53:50 -0400 Subject: [PATCH 1/2] Implement macro-based deref!() syntax for deref patterns Stop using `box PAT` syntax for deref patterns, as it's misleading and also causes their semantics being tangled up. --- compiler/rustc_ast/src/ast.rs | 7 ++++++- compiler/rustc_ast/src/mut_visit.rs | 1 + compiler/rustc_ast/src/visit.rs | 5 ++++- compiler/rustc_ast_lowering/src/pat.rs | 3 +++ compiler/rustc_ast_passes/src/feature_gate.rs | 10 ++-------- compiler/rustc_ast_pretty/src/pprust/state.rs | 6 ++++++ compiler/rustc_hir/src/hir.rs | 7 +++++-- compiler/rustc_hir/src/intravisit.rs | 4 +++- .../rustc_hir_analysis/src/check/region.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 6 ++++++ .../rustc_hir_typeck/src/expr_use_visitor.rs | 1 + .../src/mem_categorization.rs | 2 +- compiler/rustc_hir_typeck/src/pat.rs | 6 +++--- compiler/rustc_lint/src/unused.rs | 2 +- compiler/rustc_middle/src/thir.rs | 2 +- .../rustc_mir_build/src/thir/pattern/mod.rs | 2 +- compiler/rustc_parse/src/parser/pat.rs | 20 ++++++++++++++++++- compiler/rustc_passes/src/hir_stats.rs | 2 ++ library/core/src/macros/mod.rs | 12 +++++++++++ library/core/src/prelude/v1.rs | 8 ++++++++ library/std/src/prelude/v1.rs | 9 +++++++++ src/librustdoc/clean/utils.rs | 1 + .../clippy_lints/src/equatable_if_let.rs | 2 +- .../src/matches/match_same_arms.rs | 2 +- .../clippy_lints/src/unnested_or_patterns.rs | 2 ++ .../clippy/clippy_lints/src/utils/author.rs | 5 +++++ .../clippy/clippy_utils/src/hir_utils.rs | 1 + src/tools/clippy/clippy_utils/src/lib.rs | 2 +- src/tools/rustfmt/src/patterns.rs | 8 +++++--- tests/ui/pattern/deref-patterns/typeck.rs | 8 ++++---- ...mismatch-closure-from-another-scope.stderr | 10 +++++++--- 31 files changed, 123 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index d0e8b86b71d3b..e4096e244e103 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -621,7 +621,9 @@ impl Pat { | PatKind::Or(s) => s.iter().for_each(|p| p.walk(it)), // Trivial wrappers over inner patterns. - PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it), + PatKind::Box(s) | PatKind::Deref(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => { + s.walk(it) + } // These patterns do not contain subpatterns, skip. PatKind::Wild @@ -792,6 +794,9 @@ pub enum PatKind { /// A `box` pattern. Box(P), + /// A `deref` pattern (currently `deref!()` macro-based syntax). + Deref(P), + /// A reference pattern (e.g., `&mut (a, b)`). Ref(P, Mutability), diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 83468c5f10122..5b22ae5f54bf8 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1295,6 +1295,7 @@ pub fn noop_visit_pat(pat: &mut P, vis: &mut T) { fields.flat_map_in_place(|field| vis.flat_map_pat_field(field)); } PatKind::Box(inner) => vis.visit_pat(inner), + PatKind::Deref(inner) => vis.visit_pat(inner), PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner), PatKind::Range(e1, e2, Spanned { span: _, node: _ }) => { visit_opt(e1, |e| vis.visit_expr(e)); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 825f8dad8e480..7bdbf48a81f21 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -576,7 +576,10 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res try_visit!(visitor.visit_path(path, pattern.id)); walk_list!(visitor, visit_pat_field, fields); } - PatKind::Box(subpattern) | PatKind::Ref(subpattern, _) | PatKind::Paren(subpattern) => { + PatKind::Box(subpattern) + | PatKind::Deref(subpattern) + | PatKind::Ref(subpattern, _) + | PatKind::Paren(subpattern) => { try_visit!(visitor.visit_pat(subpattern)); } PatKind::Ident(_, ident, optional_subpattern) => { diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 469cdac11e439..8631d90be81f7 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -91,6 +91,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { PatKind::Box(inner) => { break hir::PatKind::Box(self.lower_pat(inner)); } + PatKind::Deref(inner) => { + break hir::PatKind::Deref(self.lower_pat(inner)); + } PatKind::Ref(inner, mutbl) => { break hir::PatKind::Ref(self.lower_pat(inner), *mutbl); } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 277e82b4e5399..81065fa3dce27 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -413,10 +413,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } PatKind::Box(..) => { - if !self.features.deref_patterns { - // Allow box patterns under `deref_patterns`. - gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental"); - } + gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental"); } PatKind::Range(_, Some(_), Spanned { node: RangeEnd::Excluded, .. }) => { gate!( @@ -610,10 +607,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { }; } - if !visitor.features.deref_patterns { - // Allow box patterns under `deref_patterns`. - gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental"); - } + gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental"); gate_all_legacy_dont_use!(trait_alias, "trait aliases are experimental"); // Despite being a new feature, `where T: Trait`, which is RTN syntax now, // used to be gated under associated_type_bounds, which are right above, so RTN needs to diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index c50878e32a460..a70daf1b644e3 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1626,6 +1626,12 @@ impl<'a> State<'a> { self.word("box "); self.print_pat(inner); } + PatKind::Deref(inner) => { + self.word("deref!"); + self.popen(); + self.print_pat(inner); + self.pclose(); + } PatKind::Ref(inner, mutbl) => { self.word("&"); if mutbl.is_mut() { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 141b8a418013d..21aec11b314f1 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1015,7 +1015,7 @@ impl<'hir> Pat<'hir> { use PatKind::*; match self.kind { Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true, - Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it), + Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it), Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)), TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)), Slice(before, slice, after) => { @@ -1042,7 +1042,7 @@ impl<'hir> Pat<'hir> { use PatKind::*; match self.kind { Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {} - Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it), + Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it), Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)), TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)), Slice(before, slice, after) => { @@ -1185,6 +1185,9 @@ pub enum PatKind<'hir> { /// A `box` pattern. Box(&'hir Pat<'hir>), + /// A `deref` pattern (currently `deref!()` macro-based syntax). + Deref(&'hir Pat<'hir>), + /// A reference pattern (e.g., `&mut (a, b)`). Ref(&'hir Pat<'hir>, Mutability), diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 3cf1093eeec72..468c7fd5c73ec 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -660,7 +660,9 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V: PatKind::Tuple(tuple_elements, _) => { walk_list!(visitor, visit_pat, tuple_elements); } - PatKind::Box(ref subpattern) | PatKind::Ref(ref subpattern, _) => { + PatKind::Box(ref subpattern) + | PatKind::Deref(ref subpattern) + | PatKind::Ref(ref subpattern, _) => { try_visit!(visitor.visit_pat(subpattern)); } PatKind::Binding(_, _hir_id, ident, ref optional_subpattern) => { diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 3c26729eff8af..eb31e1546cfaa 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -668,7 +668,7 @@ fn resolve_local<'tcx>( | PatKind::TupleStruct(_, subpats, _) | PatKind::Tuple(subpats, _) => subpats.iter().any(|p| is_binding_pat(p)), - PatKind::Box(subpat) => is_binding_pat(subpat), + PatKind::Box(subpat) | PatKind::Deref(subpat) => is_binding_pat(subpat), PatKind::Ref(_, _) | PatKind::Binding(hir::BindingAnnotation(hir::ByRef::No, _), ..) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index c7651cf3264a5..71fdcc76a702f 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1808,6 +1808,12 @@ impl<'a> State<'a> { self.pclose(); } } + PatKind::Deref(inner) => { + self.word("deref!"); + self.popen(); + self.print_pat(inner); + self.pclose(); + } PatKind::Ref(inner, mutbl) => { let is_range_inner = matches!(inner.kind, PatKind::Range(..)); self.word("&"); diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 2dc355b72f61a..f3d523efd68d1 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -463,6 +463,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } PatKind::Or(_) | PatKind::Box(_) + | PatKind::Deref(_) | PatKind::Ref(..) | PatKind::Wild | PatKind::Err(_) => { diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index 9307cccf092c4..d949772f1a343 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -719,7 +719,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { self.cat_pattern_(place_with_id, subpat, op)?; } - PatKind::Box(subpat) | PatKind::Ref(subpat, _) => { + PatKind::Box(subpat) | PatKind::Ref(subpat, _) | PatKind::Deref(subpat) => { // box p1, &p1, &mut p1. we can ignore the mutability of // PatKind::Ref since that information is already contained // in the type. diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 633f851c7d541..dad43cb8abe97 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -210,10 +210,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PatKind::Tuple(elements, ddpos) => { self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info) } - PatKind::Box(inner) if self.tcx.features().deref_patterns => { - self.check_pat_deref(pat.span, inner, expected, pat_info) - } PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info), + PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info), PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info), PatKind::Slice(before, slice, after) => { self.check_pat_slice(pat.span, before, slice, after, expected, pat_info) @@ -297,6 +295,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | PatKind::TupleStruct(..) | PatKind::Tuple(..) | PatKind::Box(_) + | PatKind::Deref(_) | PatKind::Range(..) | PatKind::Slice(..) => AdjustMode::Peel, // A never pattern behaves somewhat like a literal or unit variant. @@ -762,6 +761,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | PatKind::Binding(..) | PatKind::Path(..) | PatKind::Box(..) + | PatKind::Deref(_) | PatKind::Ref(..) | PatKind::Lit(..) | PatKind::Range(..) diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 91f907e456705..df77181d6f7f2 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1183,7 +1183,7 @@ impl EarlyLintPass for UnusedParens { self.check_unused_parens_pat(cx, &f.pat, false, false, keep_space); }, // Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106. - Ident(.., Some(p)) | Box(p) => self.check_unused_parens_pat(cx, p, true, false, keep_space), + Ident(.., Some(p)) | Box(p) | Deref(p) => self.check_unused_parens_pat(cx, p, true, false, keep_space), // Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342. // Also avoid linting on `& mut? (p0 | .. | pn)`, #64106. Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space), diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index fc9950a51fb2a..f684f83a26123 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -1179,7 +1179,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { write!(f, "{subpattern}") } PatKind::DerefPattern { ref subpattern } => { - write!(f, "k#deref {subpattern}") + write!(f, "deref!({subpattern})") } PatKind::Constant { value } => write!(f, "{value}"), PatKind::InlineConstant { def: _, ref subpattern } => { diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index f4aed91cd724b..0a7e9653377be 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -257,7 +257,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { return self.lower_path(qpath, pat.hir_id, pat.span); } - hir::PatKind::Box(subpattern) if self.tcx.features().deref_patterns => { + hir::PatKind::Deref(subpattern) => { PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern) } } hir::PatKind::Ref(subpattern, _) | hir::PatKind::Box(subpattern) => { diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 88ae1b5420fe7..6837c99758205 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -498,11 +498,14 @@ impl<'a> Parser<'a> { } else { PatKind::Lit(const_expr) } + } else if self.is_builtin() { + self.parse_pat_builtin()? + } // Don't eagerly error on semantically invalid tokens when matching // declarative macros, as the input to those doesn't have to be // semantically valid. For attribute/derive proc macros this is not the // case, so doing the recovery for them is fine. - } else if self.can_be_ident_pat() + else if self.can_be_ident_pat() || (self.is_lit_bad_ident().is_some() && self.may_recover()) { // Parse `ident @ pat` @@ -1119,6 +1122,21 @@ impl<'a> Parser<'a> { .contains(&self.token.kind) } + fn parse_pat_builtin(&mut self) -> PResult<'a, PatKind> { + self.parse_builtin(|self_, _lo, ident| { + Ok(match ident.name { + // builtin#deref(PAT) + sym::deref => Some(ast::PatKind::Deref(self_.parse_pat_allow_top_alt( + None, + RecoverComma::Yes, + RecoverColon::Yes, + CommaRecoveryMode::LikelyTuple, + )?)), + _ => None, + }) + }) + } + /// Parses `box pat` fn parse_pat_box(&mut self) -> PResult<'a, PatKind> { let box_span = self.prev_token.span; diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index d742ffc69e450..d0dba938b3b4d 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -300,6 +300,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { Path, Tuple, Box, + Deref, Ref, Lit, Range, @@ -566,6 +567,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { Path, Tuple, Box, + Deref, Ref, Lit, Range, diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index ebcaa626bd333..a78842c8f8d68 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1714,6 +1714,18 @@ pub(crate) mod builtin { builtin # type_ascribe($expr, $ty) } + #[cfg(not(bootstrap))] + /// Unstable placeholder for deref patterns. + #[allow_internal_unstable(builtin_syntax)] + #[unstable( + feature = "deref_patterns", + issue = "87121", + reason = "placeholder syntax for deref patterns" + )] + pub macro deref($pat:pat) { + builtin # deref($pat) + } + /// Unstable implementation detail of the `rustc` compiler, do not use. #[rustc_builtin_macro] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 10525a16f3a66..29f73bb4942aa 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -103,3 +103,11 @@ pub use crate::macros::builtin::cfg_eval; reason = "placeholder syntax for type ascription" )] pub use crate::macros::builtin::type_ascribe; + +#[cfg(not(bootstrap))] +#[unstable( + feature = "deref_patterns", + issue = "87121", + reason = "placeholder syntax for deref patterns" +)] +pub use crate::macros::builtin::deref; diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 7a7a773763559..36fa4e88b5bde 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -91,6 +91,15 @@ pub use core::prelude::v1::cfg_eval; )] pub use core::prelude::v1::type_ascribe; +#[cfg(not(bootstrap))] +// Do not `doc(no_inline)` either. +#[unstable( + feature = "deref_patterns", + issue = "87121", + reason = "placeholder syntax for deref patterns" +)] +pub use core::prelude::v1::deref; + // The file so far is equivalent to core/src/prelude/v1.rs. It is duplicated // rather than glob imported because we want docs to show these re-exports as // pointing to within `std`. diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 365d63d965744..977b4bb45b620 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -329,6 +329,7 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { elts.iter().map(|p| name_from_pat(p).to_string()).collect::>().join(", ") ), PatKind::Box(p) => return name_from_pat(&*p), + PatKind::Deref(p) => format!("deref!({})", name_from_pat(&*p)), PatKind::Ref(p, _) => return name_from_pat(&*p), PatKind::Lit(..) => { warn!( diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs index 4e728d61b853a..37442bf3e2867 100644 --- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs +++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs @@ -55,7 +55,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { | PatKind::Err(_) => false, PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a), - PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x), + PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) => unary_pattern(x), PatKind::Path(_) | PatKind::Lit(_) => true, } } diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index c7c453b7f6ec8..cd61e733694bb 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -243,7 +243,7 @@ impl<'a> NormalizedPat<'a> { fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) -> Self { match pat.kind { PatKind::Wild | PatKind::Binding(.., None) => Self::Wild, - PatKind::Binding(.., Some(pat)) | PatKind::Box(pat) | PatKind::Ref(pat, _) => { + PatKind::Binding(.., Some(pat)) | PatKind::Box(pat) | PatKind::Deref(pat) | PatKind::Ref(pat, _) => { Self::from_pat(cx, arena, pat) }, PatKind::Never => Self::Never, diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index 7246214f9bf87..d4dd31e11781a 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -242,6 +242,8 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec>, focus_idx: us |k| matches!(k, Box(_)), |k| always_pat!(k, Box(p) => p), ), + // FIXME(deref_patterns): Should we merge patterns here? + Deref(_) => false, // Transform `&mut x | ... | &mut y` into `&mut (x | y)`. Ref(target, Mutability::Mut) => extend_with_matching( target, start, alternatives, diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 187bfda129cd7..5319915b2eac1 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -689,6 +689,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { kind!("Box({pat})"); self.pat(pat); }, + PatKind::Deref(pat) => { + bind!(self, pat); + kind!("Deref({pat})"); + self.pat(pat); + }, PatKind::Ref(pat, muta) => { bind!(self, pat); kind!("Ref({pat}, Mutability::{muta:?})"); diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 162bf24d85d29..7a4eba9790ed4 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -955,6 +955,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } }, PatKind::Box(pat) => self.hash_pat(pat), + PatKind::Deref(pat) => self.hash_pat(pat), PatKind::Lit(expr) => self.hash_expr(expr), PatKind::Or(pats) => { for pat in pats { diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index a38db0ebec0f5..b4cc747e0e62b 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1678,7 +1678,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { match pat.kind { PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable. PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)), - PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat), + PatKind::Box(pat) | PatKind::Deref(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat), PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id), PatKind::Or(pats) => { // TODO: should be the honest check, that pats is exhaustive set diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index 7f57627943209..47b48468a24c8 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -55,9 +55,10 @@ fn is_short_pattern_inner(pat: &ast::Pat) -> bool { ast::PatKind::TupleStruct(_, ref path, ref subpats) => { path.segments.len() <= 1 && subpats.len() <= 1 } - ast::PatKind::Box(ref p) | ast::PatKind::Ref(ref p, _) | ast::PatKind::Paren(ref p) => { - is_short_pattern_inner(&*p) - } + ast::PatKind::Box(ref p) + | PatKind::Deref(ref p) + | ast::PatKind::Ref(ref p, _) + | ast::PatKind::Paren(ref p) => is_short_pattern_inner(&*p), PatKind::Or(ref pats) => pats.iter().all(|p| is_short_pattern_inner(p)), } } @@ -277,6 +278,7 @@ impl Rewrite for Pat { .rewrite(context, shape.offset_left(1)?.sub_width(1)?) .map(|inner_pat| format!("({})", inner_pat)), PatKind::Err(_) => None, + PatKind::Deref(_) => None, } } } diff --git a/tests/ui/pattern/deref-patterns/typeck.rs b/tests/ui/pattern/deref-patterns/typeck.rs index 20577abe48575..ead6dcdbaf0f9 100644 --- a/tests/ui/pattern/deref-patterns/typeck.rs +++ b/tests/ui/pattern/deref-patterns/typeck.rs @@ -7,19 +7,19 @@ use std::rc::Rc; fn main() { let vec: Vec = Vec::new(); match vec { - box [..] => {} + deref!([..]) => {} _ => {} } match Box::new(true) { - box true => {} + deref!(true) => {} _ => {} } match &Box::new(true) { - box true => {} + deref!(true) => {} _ => {} } match &Rc::new(0) { - box (1..) => {} + deref!(1..) => {} _ => {} } // FIXME(deref_patterns): fails to typecheck because `"foo"` has type &str but deref creates a diff --git a/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr index 1470c32d7de90..394186fafe417 100644 --- a/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr +++ b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr @@ -26,12 +26,16 @@ note: closure parameter defined here LL | let mut closure = expect_sig(|p, y| *p = y); | ^ -error[E0425]: cannot find function `deref` in this scope +error[E0423]: expected function, found macro `deref` --> $DIR/unboxed-closures-type-mismatch-closure-from-another-scope.rs:13:5 | LL | deref(p); - | ^^^^^ not found in this scope + | ^^^^^ not a function | +help: use `!` to invoke the macro + | +LL | deref!(p); + | + help: use the `.` operator to call the method `Deref::deref` on `&&()` | LL - deref(p); @@ -40,5 +44,5 @@ LL + p.deref(); error: aborting due to 4 previous errors -Some errors have detailed explanations: E0308, E0425. +Some errors have detailed explanations: E0308, E0423, E0425. For more information about an error, try `rustc --explain E0308`. From a4db3ffdcbce5e43c1ba47277719fecd0dd53b63 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 20 Mar 2024 18:22:21 -0400 Subject: [PATCH 2/2] Don't suggest deref macro since it's unstable --- compiler/rustc_resolve/src/late/diagnostics.rs | 7 ++++++- ...losures-type-mismatch-closure-from-another-scope.stderr | 4 ---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 1b8f2fc005cfc..bb4294fbcfb2b 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1592,18 +1592,23 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { match (res, source) { ( - Res::Def(DefKind::Macro(MacroKind::Bang), _), + Res::Def(DefKind::Macro(MacroKind::Bang), def_id), PathSource::Expr(Some(Expr { kind: ExprKind::Index(..) | ExprKind::Call(..), .. })) | PathSource::Struct, ) => { + // Don't suggest macro if it's unstable. + let suggestable = def_id.is_local() + || self.r.tcx.lookup_stability(def_id).map_or(true, |s| s.is_stable()); + err.span_label(span, fallback_label.to_string()); // Don't suggest `!` for a macro invocation if there are generic args if path .last() .is_some_and(|segment| !segment.has_generic_args && !segment.has_lifetime_args) + && suggestable { err.span_suggestion_verbose( span.shrink_to_hi(), diff --git a/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr index 394186fafe417..5f22c781345ff 100644 --- a/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr +++ b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr @@ -32,10 +32,6 @@ error[E0423]: expected function, found macro `deref` LL | deref(p); | ^^^^^ not a function | -help: use `!` to invoke the macro - | -LL | deref!(p); - | + help: use the `.` operator to call the method `Deref::deref` on `&&()` | LL - deref(p);