From 3e1a6df2f29a6cd2de31a856093690da389ba86c Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 4 Feb 2025 14:00:08 +1100 Subject: [PATCH] Split `thir::PatKind::ExpandedConstant` into two distinct kinds These two kinds of marker node are superficially similar, but are actually very different in practice, and there is no code that actually wants to treat them as the same thing. --- compiler/rustc_middle/src/thir.rs | 44 +++++++++++-------- compiler/rustc_middle/src/thir/visit.rs | 6 ++- .../src/builder/custom/parse/instruction.rs | 2 +- .../src/builder/matches/match_pair.rs | 9 ++-- .../src/builder/matches/mod.rs | 3 +- .../rustc_mir_build/src/check_unsafety.rs | 13 +++--- .../src/thir/pattern/check_match.rs | 6 +-- .../rustc_mir_build/src/thir/pattern/mod.rs | 36 ++++++++------- compiler/rustc_mir_build/src/thir/print.rs | 12 +++-- compiler/rustc_pattern_analysis/src/rustc.rs | 8 +++- 10 files changed, 82 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 5490f1f53ea14..8f2fd9070bb14 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -678,11 +678,14 @@ impl<'tcx> Pat<'tcx> { | Binding { subpattern: None, .. } | Constant { .. } | Error(_) => {} + AscribeUserType { subpattern, .. } | Binding { subpattern: Some(subpattern), .. } | Deref { subpattern } | DerefPattern { subpattern, .. } - | ExpandedConstant { subpattern, .. } => subpattern.walk_(it), + | InlineConstMarker { subpattern, .. } + | NamedConstMarker { subpattern, .. } => subpattern.walk_(it), + Leaf { subpatterns } | Variant { subpatterns, .. } => { subpatterns.iter().for_each(|field| field.pattern.walk_(it)) } @@ -825,24 +828,29 @@ pub enum PatKind<'tcx> { value: mir::Const<'tcx>, }, - /// Pattern obtained by converting a constant (inline or named) to its pattern - /// representation using `const_to_pat`. - ExpandedConstant { - /// [DefId] of the constant, we need this so that we have a - /// reference that can be used by unsafety checking to visit nested - /// unevaluated constants and for diagnostics. If the `DefId` doesn't - /// correspond to a local crate, it points at the `const` item. + /// Marker node that wraps a pattern representing an inline-const block. + /// + /// THIR unsafeck uses this marker to discover inline-const blocks that + /// appear in patterns, so that they can be checked together with the rest + /// of their enclosing body. + /// + /// Note that if a range pattern has inline-const blocks for both endpoints, + /// the resulting THIR pattern will be an `InlineConstMarker`, containing + /// another `InlineConstMarker`, containing the underlying `Range` pattern. + InlineConstMarker { + /// ID of the inline-const block, for use by THIR unsafeck. + def_id: LocalDefId, + subpattern: Box>, + }, + + /// Marker node that wraps a pattern representing a named constant. + /// Enables better diagnostics in some cases, but has no other significance. + /// + /// (Even though this is superficially similar to `InlineConstMarker`, they + /// are very different in actual usage, so they should be kept separate.) + NamedConstMarker { + /// ID of the named constant, for use by diagnostics. def_id: DefId, - /// If `false`, then `def_id` points at a `const` item, otherwise it - /// corresponds to a local inline const. - is_inline: bool, - /// If the inline constant is used in a range pattern, this subpattern - /// represents the range (if both ends are inline constants, there will - /// be multiple InlineConstant wrappers). - /// - /// Otherwise, the actual pattern that the constant lowered to. As with - /// other constants, inline constants are matched structurally where - /// possible. subpattern: Box>, }, diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 2aeb13942a382..f2fc93848f0f3 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -243,7 +243,10 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( AscribeUserType { subpattern, ascription: _ } | Deref { subpattern } | DerefPattern { subpattern, .. } - | Binding { subpattern: Some(subpattern), .. } => visitor.visit_pat(subpattern), + | Binding { subpattern: Some(subpattern), .. } + | InlineConstMarker { subpattern, .. } + | NamedConstMarker { subpattern, .. } => visitor.visit_pat(subpattern), + Binding { .. } | Wild | Never | Error(_) => {} Variant { subpatterns, adt_def: _, args: _, variant_index: _ } | Leaf { subpatterns } => { for subpattern in subpatterns { @@ -251,7 +254,6 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( } } Constant { value: _ } => {} - ExpandedConstant { def_id: _, is_inline: _, subpattern } => visitor.visit_pat(subpattern), Range(_) => {} Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => { for subpattern in prefix.iter() { diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index eab414e150fa3..6d8244e490ed9 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -146,7 +146,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { let arm = &self.thir[*arm]; let value = match arm.pattern.kind { PatKind::Constant { value } => value, - PatKind::ExpandedConstant { ref subpattern, def_id: _, is_inline: false } + PatKind::NamedConstMarker { ref subpattern, def_id: _ } if let PatKind::Constant { value } = subpattern.kind => { value 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 9d59ffc88ba23..95b37da722748 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -162,11 +162,11 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> { TestCase::Irrefutable { ascription: None, binding } } - PatKind::ExpandedConstant { subpattern: ref pattern, def_id: _, is_inline: false } => { + PatKind::NamedConstMarker { subpattern: ref pattern, def_id: _ } => { subpairs.push(MatchPairTree::for_pattern(place_builder, pattern, cx)); default_irrefutable() } - PatKind::ExpandedConstant { subpattern: ref pattern, def_id, is_inline: true } => { + PatKind::InlineConstMarker { subpattern: ref pattern, def_id } => { // Apply a type ascription for the inline constant to the value at `match_pair.place` let ascription = place.map(|source| { let span = pattern.span; @@ -177,7 +177,10 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> { }) .args; let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::new( - ty::UserTypeKind::TypeOf(def_id, ty::UserArgs { args, user_self_ty: None }), + ty::UserTypeKind::TypeOf(def_id.to_def_id(), ty::UserArgs { + args, + user_self_ty: None, + }), )); let annotation = ty::CanonicalUserTypeAnnotation { inferred_ty: pattern.ty, diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index b21ec8f3083b3..0e7cfc04deaec 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -925,7 +925,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.visit_primary_bindings(subpattern, subpattern_user_ty, f) } - PatKind::ExpandedConstant { ref subpattern, .. } => { + PatKind::InlineConstMarker { ref subpattern, .. } + | PatKind::NamedConstMarker { ref subpattern, .. } => { self.visit_primary_bindings(subpattern, pattern_user_ty, f) } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index b6494173b0f08..45e3b610a6272 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -332,7 +332,8 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { PatKind::Wild | // these just wrap other patterns, which we recurse on below. PatKind::Or { .. } | - PatKind::ExpandedConstant { .. } | + PatKind::InlineConstMarker { .. } | + PatKind::NamedConstMarker { .. } | PatKind::AscribeUserType { .. } | PatKind::Error(_) => {} } @@ -400,12 +401,10 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { visit::walk_pat(self, pat); self.inside_adt = old_inside_adt; } - PatKind::ExpandedConstant { def_id, is_inline, .. } => { - if let Some(def) = def_id.as_local() - && *is_inline - { - self.visit_inner_body(def); - } + PatKind::InlineConstMarker { def_id, .. } => { + // Also visit the inline `const {}` block that this pattern + // represents. (See #116482 for context.) + self.visit_inner_body(*def_id); visit::walk_pat(self, pat); } _ => { 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 8247a6c6a32d5..89e19d6e78997 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -676,10 +676,10 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { let mut interpreted_as_const = None; let mut interpreted_as_const_sugg = None; - if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } + if let PatKind::NamedConstMarker { def_id, .. } | PatKind::AscribeUserType { subpattern: - box Pat { kind: PatKind::ExpandedConstant { def_id, is_inline: false, .. }, .. }, + box Pat { kind: PatKind::NamedConstMarker { def_id, .. }, .. }, .. } = pat.kind && let DefKind::Const = self.tcx.def_kind(def_id) @@ -1309,7 +1309,7 @@ fn report_non_exhaustive_match<'p, 'tcx>( for &arm in arms { let arm = &thir.arms[arm]; - if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } = arm.pattern.kind + if let PatKind::NamedConstMarker { def_id, .. } = arm.pattern.kind && let Ok(snippet) = cx.tcx.sess.source_map().span_to_snippet(arm.pattern.span) // We filter out paths with multiple path::segments. && snippet.chars().all(|c| c.is_alphanumeric() || c == '_') diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 0aa61152330a7..dd1c84a9d3e87 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -165,17 +165,23 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // deconstructed to obtain the constant value and other data. let mut kind: PatKind<'tcx> = self.lower_lit(expr); - // Unpeel any ascription or inline-const wrapper nodes. + // Unpeel any wrapper nodes, while preserving marker data that will + // need to be reapplied to the range pattern node. loop { match kind { PatKind::AscribeUserType { ascription, subpattern } => { ascriptions.push(ascription); kind = subpattern.kind; } - PatKind::ExpandedConstant { is_inline, def_id, subpattern } => { - if is_inline { - inline_consts.extend(def_id.as_local()); - } + PatKind::InlineConstMarker { def_id, subpattern } => { + // Preserve inline-const markers, so that THIR unsafeck can + // see const blocks that are part of a range pattern. + inline_consts.push(def_id); + kind = subpattern.kind; + } + PatKind::NamedConstMarker { subpattern, .. } => { + // Named-const markers are only used for improved diagnostics that + // aren't relevant to range patterns, so it's OK to discard them. kind = subpattern.kind; } _ => break, @@ -307,12 +313,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { subpattern: Box::new(Pat { span, ty, kind }), }; } - for def in inline_consts { - kind = PatKind::ExpandedConstant { - def_id: def.to_def_id(), - is_inline: true, - subpattern: Box::new(Pat { span, ty, kind }), - }; + // If one or both endpoints is an inline-const block, reapply the marker + // nodes so that unsafeck can traverse into the corresponding block body. + for def_id in inline_consts { + let subpattern = Box::new(Pat { span, ty, kind }); + kind = PatKind::InlineConstMarker { def_id, subpattern }; } Ok(kind) } @@ -593,11 +598,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let args = self.typeck_results.node_args(id); let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args }); let subpattern = self.const_to_pat(c, ty, id, span); - let pattern = Box::new(Pat { - span, - ty, - kind: PatKind::ExpandedConstant { subpattern, def_id, is_inline: false }, - }); + let pattern = + Box::new(Pat { span, ty, kind: PatKind::NamedConstMarker { subpattern, def_id } }); if !is_associated_const { return pattern; @@ -648,7 +650,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args }; let subpattern = self.const_to_pat(ty::Const::new_unevaluated(self.tcx, ct), ty, id, span); - PatKind::ExpandedConstant { subpattern, def_id: def_id.to_def_id(), is_inline: true } + PatKind::InlineConstMarker { subpattern, def_id } } /// Converts literals, paths and negation of literals to patterns. diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 729c8f784ba9f..11ad289bac5f1 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -733,10 +733,16 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, format!("value: {:?}", value), depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } - PatKind::ExpandedConstant { def_id, is_inline, subpattern } => { - print_indented!(self, "ExpandedConstant {", depth_lvl + 1); + PatKind::InlineConstMarker { def_id, subpattern } => { + print_indented!(self, "InlineConstMarker {", depth_lvl + 1); + print_indented!(self, format!("def_id: {def_id:?}"), depth_lvl + 2); + print_indented!(self, "subpattern:", depth_lvl + 2); + self.print_pat(subpattern, depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::NamedConstMarker { def_id, subpattern } => { + print_indented!(self, "NamedConstMarker {", depth_lvl + 1); print_indented!(self, format!("def_id: {def_id:?}"), depth_lvl + 2); - print_indented!(self, format!("is_inline: {is_inline:?}"), depth_lvl + 2); print_indented!(self, "subpattern:", depth_lvl + 2); self.print_pat(subpattern, depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 2694cf472f480..e805d22f5d723 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -456,8 +456,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { let fields: Vec<_>; match &pat.kind { PatKind::AscribeUserType { subpattern, .. } - | PatKind::ExpandedConstant { subpattern, .. } => return self.lower_pat(subpattern), - PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat), + | PatKind::InlineConstMarker { subpattern, .. } + | PatKind::NamedConstMarker { subpattern, .. } + | PatKind::Binding { subpattern: Some(subpattern), .. } => { + return self.lower_pat(subpattern); + } + PatKind::Binding { subpattern: None, .. } | PatKind::Wild => { ctor = Wildcard; fields = vec![];