Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split thir::PatKind::ExpandedConstant into two distinct kinds #136529

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 26 additions & 18 deletions compiler/rustc_middle/src/thir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
Expand Down Expand Up @@ -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<Pat<'tcx>>,
},

/// 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<Pat<'tcx>>,
},

Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_middle/src/thir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,15 +243,17 @@ 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 {
visitor.visit_pat(&subpattern.pattern);
}
}
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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 6 additions & 3 deletions compiler/rustc_mir_build/src/builder/matches/match_pair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_mir_build/src/builder/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down
13 changes: 6 additions & 7 deletions compiler/rustc_mir_build/src/check_unsafety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(_) => {}
}
Expand Down Expand Up @@ -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);
}
_ => {
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_mir_build/src/thir/pattern/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 == '_')
Expand Down
36 changes: 19 additions & 17 deletions compiler/rustc_mir_build/src/thir/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down
12 changes: 9 additions & 3 deletions compiler/rustc_mir_build/src/thir/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_pattern_analysis/src/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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![];
Expand Down
Loading