From 75d8687f2b6ac1e73071450cb57c4157fcba53b4 Mon Sep 17 00:00:00 2001 From: Valdemar Erk Date: Sat, 23 Aug 2025 11:37:53 +0200 Subject: [PATCH] add span to struct pattern rest (..) --- compiler/rustc_ast/src/ast.rs | 6 +++--- compiler/rustc_ast_lowering/src/expr.rs | 6 +++--- compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_ast_lowering/src/pat.rs | 9 +++++---- compiler/rustc_ast_pretty/src/pprust/state.rs | 2 +- compiler/rustc_hir/src/hir.rs | 8 ++++---- compiler/rustc_hir_pretty/src/lib.rs | 4 ++-- compiler/rustc_hir_typeck/src/pat.rs | 12 +++++++++-- compiler/rustc_parse/src/parser/pat.rs | 2 +- compiler/rustc_passes/src/liveness.rs | 2 +- compiler/rustc_resolve/src/late.rs | 2 +- .../clippy_lints/src/equatable_if_let.rs | 2 +- .../clippy_lints/src/manual_let_else.rs | 4 ++-- .../matches/rest_pat_in_fully_bound_struct.rs | 2 +- .../clippy/clippy_lints/src/utils/author.rs | 3 ++- src/tools/clippy/clippy_utils/src/lib.rs | 2 +- src/tools/rustfmt/src/patterns.rs | 2 +- tests/ui/stats/input-stats.stderr | 20 +++++++++---------- 18 files changed, 50 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index de3e0e0c87f5a..802a6fa324984 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -937,7 +937,7 @@ pub enum PatKind { #[derive(Clone, Copy, Encodable, Decodable, Debug, PartialEq, Walkable)] pub enum PatFieldsRest { /// `module::StructName { field, ..}` - Rest, + Rest(Span), /// `module::StructName { field, syntax error }` Recovered(ErrorGuaranteed), /// `module::StructName { field }` @@ -4051,8 +4051,8 @@ mod size_asserts { static_assert_size!(Local, 96); static_assert_size!(MetaItemLit, 40); static_assert_size!(Param, 40); - static_assert_size!(Pat, 72); - static_assert_size!(PatKind, 48); + static_assert_size!(Pat, 80); + static_assert_size!(PatKind, 56); static_assert_size!(Path, 24); static_assert_size!(PathSegment, 24); static_assert_size!(Stmt, 32); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index cbd17d66b7548..3674814b796c2 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1434,10 +1434,10 @@ impl<'hir> LoweringContext<'_, 'hir> { self.dcx().emit_err(FunctionalRecordUpdateDestructuringAssignment { span: e.span, }); - true + Some(self.lower_span(e.span)) } - StructRest::Rest(_) => true, - StructRest::None => false, + StructRest::Rest(span) => Some(self.lower_span(*span)), + StructRest::None => None, }; let struct_pat = hir::PatKind::Struct(qpath, field_pats, fields_omitted); return self.pat_without_dbm(lhs.span, struct_pat); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 70595391b85bc..137207bde1f12 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2508,7 +2508,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fields: &'hir [hir::PatField<'hir>], ) -> &'hir hir::Pat<'hir> { let qpath = hir::QPath::LangItem(lang_item, self.lower_span(span)); - self.pat(span, hir::PatKind::Struct(qpath, fields, false)) + self.pat(span, hir::PatKind::Struct(qpath, fields, None)) } fn pat_ident(&mut self, span: Span, ident: Ident) -> (&'hir hir::Pat<'hir>, HirId) { diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index b8f8624787565..ed159f37051c1 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -106,10 +106,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { break hir::PatKind::Struct( qpath, fs, - matches!( - etc, - ast::PatFieldsRest::Rest | ast::PatFieldsRest::Recovered(_) - ), + match etc { + ast::PatFieldsRest::Rest(sp) => Some(self.lower_span(*sp)), + ast::PatFieldsRest::Recovered(_) => Some(Span::default()), + _ => None, + }, ); } PatKind::Tuple(pats) => { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index a056ce3e29d28..41b520b04c993 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1769,7 +1769,7 @@ impl<'a> State<'a> { }, |f| f.pat.span, ); - if let ast::PatFieldsRest::Rest | ast::PatFieldsRest::Recovered(_) = etc { + if let ast::PatFieldsRest::Rest(_) | ast::PatFieldsRest::Recovered(_) = etc { if !fields.is_empty() { self.word_space(","); } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e397c286de289..e3c27c73638c1 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1884,8 +1884,8 @@ pub enum PatKind<'hir> { Binding(BindingMode, HirId, Ident, Option<&'hir Pat<'hir>>), /// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`). - /// The `bool` is `true` in the presence of a `..`. - Struct(QPath<'hir>, &'hir [PatField<'hir>], bool), + /// The `Option` contains the span of a possible `..`. + Struct(QPath<'hir>, &'hir [PatField<'hir>], Option), /// A tuple struct/variant pattern `Variant(x, y, .., z)`. /// If the `..` pattern fragment is present, then `DotDotPos` denotes its position. @@ -4979,8 +4979,8 @@ mod size_asserts { static_assert_size!(ItemKind<'_>, 64); static_assert_size!(LetStmt<'_>, 72); static_assert_size!(Param<'_>, 32); - static_assert_size!(Pat<'_>, 72); - static_assert_size!(PatKind<'_>, 48); + static_assert_size!(Pat<'_>, 80); + static_assert_size!(PatKind<'_>, 56); static_assert_size!(Path<'_>, 40); static_assert_size!(PathSegment<'_>, 48); static_assert_size!(QPath<'_>, 24); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index be5859b57c5e0..52b29e05dcb0e 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1958,12 +1958,12 @@ impl<'a> State<'a> { self.print_qpath(qpath, true); self.nbsp(); self.word("{"); - let empty = fields.is_empty() && !etc; + let empty = fields.is_empty() && etc.is_none(); if !empty { self.space(); } self.commasep_cmnt(Consistent, fields, |s, f| s.print_patfield(f), |f| f.pat.span); - if etc { + if etc.is_some() { if !fields.is_empty() { self.word_space(","); } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 7dc736e5e6b14..f735c0a416099 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -605,7 +605,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, PatKind::Struct(_, fields, has_rest_pat) => match opt_path_res.unwrap() { Ok(ResolvedPat { ty, kind: ResolvedPatKind::Struct { variant } }) => self - .check_pat_struct(pat, fields, has_rest_pat, ty, variant, expected, pat_info), + .check_pat_struct( + pat, + fields, + has_rest_pat.is_some(), + ty, + variant, + expected, + pat_info, + ), Err(guar) => { let ty_err = Ty::new_error(self.tcx, guar); for field in fields { @@ -2428,7 +2436,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let len = unmentioned_fields.len(); let (prefix, postfix, sp) = match fields { [] => match &pat.kind { - PatKind::Struct(path, [], false) => { + PatKind::Struct(path, [], None) => { (" { ", " }", path.span().shrink_to_hi().until(pat.span.shrink_to_hi())) } _ => return err, diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 9754691a0b9ca..c4d30b3d32832 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1516,7 +1516,7 @@ impl<'a> Parser<'a> { || self.check_noexpect(&token::DotDotDot) || self.check_keyword(exp!(Underscore)) { - etc = PatFieldsRest::Rest; + etc = PatFieldsRest::Rest(self.token.span); let mut etc_sp = self.token.span; if first_etc_and_maybe_comma_span.is_none() { if let Some(comma_tok) = diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 801a533c94338..ae16a51bc693c 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1583,7 +1583,7 @@ impl<'tcx> Liveness<'_, 'tcx> { }); let can_remove = match pat.kind { - hir::PatKind::Struct(_, fields, true) => { + hir::PatKind::Struct(_, fields, Some(_)) => { // if all fields are shorthand, remove the struct field, otherwise, mark with _ as prefix fields.iter().all(|f| f.is_shorthand) } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 679e663f88614..84108f0b8663d 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3922,7 +3922,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { fn record_patterns_with_skipped_bindings(&mut self, pat: &Pat, rest: &ast::PatFieldsRest) { match rest { - ast::PatFieldsRest::Rest | ast::PatFieldsRest::Recovered(_) => { + ast::PatFieldsRest::Rest(_) | ast::PatFieldsRest::Recovered(_) => { // Record that the pattern doesn't introduce all the bindings it could. if let Some(partial_res) = self.r.partial_res_map.get(&pat.id) && let Some(res) = partial_res.full_res() 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 72f5eaf8a4bcc..c3fc09343dbfe 100644 --- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs +++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs @@ -53,7 +53,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { | PatKind::Never | PatKind::Or(_) | PatKind::Err(_) => false, - PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), + PatKind::Struct(_, a, etc) => etc.is_none() && 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) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x), PatKind::Expr(_) => true, diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs index 5a7967bbf9468..2705ef20b795d 100644 --- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs @@ -287,7 +287,7 @@ fn replace_in_pattern( } return or_pat; }, - PatKind::Struct(path, fields, has_dot_dot) => { + PatKind::Struct(path, fields, dot_dot) => { let fields = fields .iter() .map(|fld| { @@ -311,7 +311,7 @@ fn replace_in_pattern( .collect::>(); let fields_string = fields.join(", "); - let dot_dot_str = if has_dot_dot { " .." } else { "" }; + let dot_dot_str = if dot_dot.is_some() { " .." } else { "" }; let (sn_pth, _) = snippet_with_context(cx, path.span(), span.ctxt(), "", app); return format!("{sn_pth} {{ {fields_string}{dot_dot_str} }}"); }, diff --git a/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs b/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs index 2154cd5b24a54..ae09c2e87d6b7 100644 --- a/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs +++ b/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs @@ -7,7 +7,7 @@ use super::REST_PAT_IN_FULLY_BOUND_STRUCTS; pub(crate) fn check(cx: &LateContext<'_>, pat: &Pat<'_>) { if !pat.span.from_expansion() - && let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind + && let PatKind::Struct(QPath::Resolved(_, path), fields, Some(_)) = pat.kind && let Some(def_id) = path.res.opt_def_id() && let ty = cx.tcx.type_of(def_id).instantiate_identity() && let ty::Adt(def, _) = ty.kind() diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 2113cb92137eb..ece29362a39f9 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -754,7 +754,8 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { self.ident(name); sub.if_some(|p| self.pat(p)); }, - PatKind::Struct(ref qpath, fields, ignore) => { + PatKind::Struct(ref qpath, fields, etc) => { + let ignore = etc.is_some(); bind!(self, qpath, fields); kind!("Struct(ref {qpath}, {fields}, {ignore})"); self.qpath(qpath, pat); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 8533fa8554199..011c9b2f931ae 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -2011,7 +2011,7 @@ pub fn is_expr_identity_of_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr< false } }, - (PatKind::Struct(pat_ident, field_pats, false), ExprKind::Struct(ident, fields, hir::StructTailExpr::None)) + (PatKind::Struct(pat_ident, field_pats, None), ExprKind::Struct(ident, fields, hir::StructTailExpr::None)) if field_pats.len() == fields.len() => { // check ident diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index d212ecf392a7f..848bd0766e786 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -303,7 +303,7 @@ impl Rewrite for Pat { qself, path, fields, - rest == ast::PatFieldsRest::Rest, + matches!(rest, ast::PatFieldsRest::Rest(_)), self.span, context, shape, diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index 72a9820bb6431..4a73a4747ad0c 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -23,10 +23,10 @@ ast-stats - Path 72 (NN.N%) 1 ast-stats - Struct 72 (NN.N%) 1 ast-stats - Lit 144 (NN.N%) 2 ast-stats - Block 216 (NN.N%) 3 -ast-stats Pat 504 (NN.N%) 7 72 -ast-stats - Struct 72 (NN.N%) 1 -ast-stats - Wild 72 (NN.N%) 1 -ast-stats - Ident 360 (NN.N%) 5 +ast-stats Pat 560 (NN.N%) 7 80 +ast-stats - Struct 80 (NN.N%) 1 +ast-stats - Wild 80 (NN.N%) 1 +ast-stats - Ident 400 (NN.N%) 5 ast-stats GenericParam 480 (NN.N%) 5 96 ast-stats GenericBound 352 (NN.N%) 4 88 ast-stats - Trait 352 (NN.N%) 4 @@ -57,7 +57,7 @@ ast-stats GenericArgs 40 (NN.N%) 1 40 ast-stats - AngleBracketed 40 (NN.N%) 1 ast-stats Crate 40 (NN.N%) 1 40 ast-stats ---------------------------------------------------------------- -ast-stats Total 7_472 129 +ast-stats Total 7_528 129 ast-stats ================================================================ hir-stats ================================================================ hir-stats HIR STATS: input_stats @@ -85,11 +85,11 @@ hir-stats - Ptr 48 (NN.N%) 1 hir-stats - Ref 48 (NN.N%) 1 hir-stats - Path 624 (NN.N%) 13 hir-stats Generics 560 (NN.N%) 10 56 +hir-stats Pat 400 (NN.N%) 5 80 +hir-stats - Struct 80 (NN.N%) 1 +hir-stats - Wild 80 (NN.N%) 1 +hir-stats - Binding 240 (NN.N%) 3 hir-stats GenericParam 400 (NN.N%) 5 80 -hir-stats Pat 360 (NN.N%) 5 72 -hir-stats - Struct 72 (NN.N%) 1 -hir-stats - Wild 72 (NN.N%) 1 -hir-stats - Binding 216 (NN.N%) 3 hir-stats Block 288 (NN.N%) 6 48 hir-stats GenericBound 256 (NN.N%) 4 64 hir-stats - Trait 256 (NN.N%) 4 @@ -119,5 +119,5 @@ hir-stats TraitItemId 8 (NN.N%) 2 4 hir-stats ImplItemId 8 (NN.N%) 2 4 hir-stats ForeignItemId 4 (NN.N%) 1 4 hir-stats ---------------------------------------------------------------- -hir-stats Total 8_584 173 +hir-stats Total 8_624 173 hir-stats ================================================================