Skip to content

Commit

Permalink
Unify expanded constants and named constants in PatKind
Browse files Browse the repository at this point in the history
  • Loading branch information
estebank committed Nov 7, 2024
1 parent f7179b8 commit d02ba09
Show file tree
Hide file tree
Showing 17 changed files with 215 additions and 58 deletions.
22 changes: 12 additions & 10 deletions compiler/rustc_middle/src/thir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,7 @@ impl<'tcx> Pat<'tcx> {
| Binding { subpattern: Some(subpattern), .. }
| Deref { subpattern }
| DerefPattern { subpattern, .. }
| InlineConstant { subpattern, .. } => subpattern.walk_(it),
| ExpandedConstant { subpattern, .. } => subpattern.walk_(it),
Leaf { subpatterns } | Variant { subpatterns, .. } => {
subpatterns.iter().for_each(|field| field.pattern.walk_(it))
}
Expand Down Expand Up @@ -786,16 +786,18 @@ pub enum PatKind<'tcx> {
/// * `String`, if `string_deref_patterns` is enabled.
Constant {
value: mir::Const<'tcx>,
/// The `const` item this constant came from, if any.
opt_def: Option<DefId>,
},

/// Inline constant found while lowering a pattern.
InlineConstant {
/// [LocalDefId] of the constant, we need this so that we have a
/// Inline or named constant found while lowering a pattern.
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.
def: LocalDefId,
/// unevaluated constants. If the `DefId` doesn't correspond to a local
/// crate, it points at the `const` item.
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).
Expand Down Expand Up @@ -1086,8 +1088,8 @@ mod size_asserts {
static_assert_size!(Block, 48);
static_assert_size!(Expr<'_>, 64);
static_assert_size!(ExprKind<'_>, 40);
static_assert_size!(Pat<'_>, 72);
static_assert_size!(PatKind<'_>, 56);
static_assert_size!(Pat<'_>, 64);
static_assert_size!(PatKind<'_>, 48);
static_assert_size!(Stmt<'_>, 48);
static_assert_size!(StmtKind<'_>, 48);
// tidy-alphabetical-end
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/thir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,8 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
visitor.visit_pat(&subpattern.pattern);
}
}
Constant { value: _, opt_def: _ } => {}
InlineConstant { def: _, subpattern } => visitor.visit_pat(subpattern),
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 @@ -144,7 +144,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
let mut targets = Vec::new();
for arm in rest {
let arm = &self.thir[*arm];
let PatKind::Constant { value, opt_def: _ } = arm.pattern.kind else {
let PatKind::Constant { value } = arm.pattern.kind else {
return Err(ParseError {
span: arm.pattern.span,
item_description: format!("{:?}", arm.pattern.kind),
Expand Down
10 changes: 7 additions & 3 deletions compiler/rustc_mir_build/src/build/matches/match_pair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
}
}

PatKind::Constant { value, opt_def: _ } => TestCase::Constant { value },
PatKind::Constant { value } => TestCase::Constant { value },

PatKind::AscribeUserType {
ascription: thir::Ascription { ref annotation, variance },
Expand Down Expand Up @@ -162,7 +162,11 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
TestCase::Irrefutable { ascription: None, binding }
}

PatKind::InlineConstant { subpattern: ref pattern, def, .. } => {
PatKind::ExpandedConstant { subpattern: ref pattern, def_id: _, is_inline: false } => {
subpairs.push(MatchPairTree::for_pattern(place_builder, pattern, cx));
default_irrefutable()
}
PatKind::ExpandedConstant { subpattern: ref pattern, def_id, is_inline: true } => {
// 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 @@ -173,7 +177,7 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
})
.args;
let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
def.to_def_id(),
def_id,
ty::UserArgs { args, user_self_ty: None },
));
let annotation = ty::CanonicalUserTypeAnnotation {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/build/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -917,7 +917,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.visit_primary_bindings(subpattern, subpattern_user_ty, f)
}

PatKind::InlineConstant { ref subpattern, .. } => {
PatKind::ExpandedConstant { ref subpattern, .. } => {
self.visit_primary_bindings(subpattern, pattern_user_ty, f)
}

Expand Down
10 changes: 7 additions & 3 deletions compiler/rustc_mir_build/src/check_unsafety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ 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::InlineConstant { .. } |
PatKind::ExpandedConstant { .. } |
PatKind::AscribeUserType { .. } |
PatKind::Error(_) => {}
}
Expand Down Expand Up @@ -386,8 +386,12 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
visit::walk_pat(self, pat);
self.inside_adt = old_inside_adt;
}
PatKind::InlineConstant { def, .. } => {
self.visit_inner_body(*def);
PatKind::ExpandedConstant { def_id, is_inline, .. } => {
if let Some(def) = def_id.as_local()
&& *is_inline
{
self.visit_inner_body(def);
}
visit::walk_pat(self, pat);
}
_ => {
Expand Down
8 changes: 5 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 @@ -670,11 +670,13 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
let mut interpreted_as_const = None;
let mut interpreted_as_const_sugg = None;

if let PatKind::Constant { opt_def: Some(def_id), .. }
if let PatKind::ExpandedConstant { def_id, is_inline: false, .. }
| PatKind::AscribeUserType {
subpattern: box Pat { kind: PatKind::Constant { opt_def: Some(def_id), .. }, .. },
subpattern:
box Pat { kind: PatKind::ExpandedConstant { def_id, is_inline: false, .. }, .. },
..
} = pat.kind
&& let DefKind::Const = self.tcx.def_kind(def_id)
{
let span = self.tcx.def_span(def_id);
let variable = self.tcx.item_name(def_id).to_string();
Expand Down Expand Up @@ -1145,7 +1147,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(

for &arm in arms {
let arm = &thir.arms[arm];
if let PatKind::Constant { opt_def: Some(def_id), .. } = arm.pattern.kind {
if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } = arm.pattern.kind {
let const_name = cx.tcx.item_name(def_id);
err.span_label(
arm.pattern.span,
Expand Down
7 changes: 1 addition & 6 deletions compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,6 @@ impl<'tcx> ConstToPat<'tcx> {
// optimization for now.
ty::Str => PatKind::Constant {
value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)),
opt_def: None,
},
// All other references are converted into deref patterns and then recursively
// convert the dereferenced constant to a pattern that is the sub-pattern of the
Expand Down Expand Up @@ -294,17 +293,13 @@ impl<'tcx> ConstToPat<'tcx> {
} else {
PatKind::Constant {
value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)),
opt_def: None,
}
}
}
ty::Pat(..) | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => {
// The raw pointers we see here have been "vetted" by valtree construction to be
// just integers, so we simply allow them.
PatKind::Constant {
value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)),
opt_def: None,
}
PatKind::Constant { value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)) }
}
ty::FnPtr(..) => {
unreachable!(
Expand Down
37 changes: 27 additions & 10 deletions compiler/rustc_mir_build/src/thir/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,15 +149,18 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
None => Ok((None, None, None)),
Some(expr) => {
let (kind, ascr, inline_const) = match self.lower_lit(expr) {
PatKind::InlineConstant { subpattern, def } => {
(subpattern.kind, None, Some(def))
PatKind::ExpandedConstant { subpattern, def_id, is_inline: true } => {
(subpattern.kind, None, def_id.as_local())
}
PatKind::ExpandedConstant { subpattern, is_inline: false, .. } => {
(subpattern.kind, None, None)
}
PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => {
(kind, Some(ascription), None)
}
kind => (kind, None, None),
};
let value = if let PatKind::Constant { value, opt_def: _ } = kind {
let value = if let PatKind::Constant { value } = kind {
value
} else {
let msg = format!(
Expand Down Expand Up @@ -251,7 +254,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
(RangeEnd::Included, Some(Ordering::Less)) => {}
// `x..=y` where `x == y` and `x` and `y` are finite.
(RangeEnd::Included, Some(Ordering::Equal)) if lo.is_finite() && hi.is_finite() => {
kind = PatKind::Constant { value: lo.as_finite().unwrap(), opt_def: None };
kind = PatKind::Constant { value: lo.as_finite().unwrap() };
}
// `..=x` where `x == ty::MIN`.
(RangeEnd::Included, Some(Ordering::Equal)) if !lo.is_finite() => {}
Expand Down Expand Up @@ -288,7 +291,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
};
}
for def in [lo_inline, hi_inline].into_iter().flatten() {
kind = PatKind::InlineConstant { def, subpattern: Box::new(Pat { span, ty, kind }) };
kind = PatKind::ExpandedConstant {
def_id: def.to_def_id(),
is_inline: true,
subpattern: Box::new(Pat { span, ty, kind }),
};
}
Ok(kind)
}
Expand Down Expand Up @@ -562,10 +569,20 @@ 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 mut pattern = self.const_to_pat(c, ty, id, span);
if let PatKind::Constant { value, opt_def: None } = pattern.kind {
pattern.kind = PatKind::Constant { value, opt_def: Some(def_id) };
}
let subpattern = self.const_to_pat(c, ty, id, span);
let pattern = if let hir::QPath::Resolved(None, path) = qpath
&& path.segments.len() == 1
{
// We only want to mark constants when referenced as bare names that could have been
// new bindings if the `const` didn't exist.
Box::new(Pat {
span,
ty,
kind: PatKind::ExpandedConstant { subpattern, def_id, is_inline: false },
})
} else {
subpattern
};

if !is_associated_const {
return pattern;
Expand Down Expand Up @@ -640,7 +657,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::InlineConstant { subpattern, def: def_id }
PatKind::ExpandedConstant { subpattern, def_id: def_id.to_def_id(), is_inline: true }
}

/// Converts literals, paths and negation of literals to patterns.
Expand Down
9 changes: 5 additions & 4 deletions compiler/rustc_mir_build/src/thir/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -702,14 +702,15 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
self.print_pat(subpattern, depth_lvl + 2);
print_indented!(self, "}", depth_lvl + 1);
}
PatKind::Constant { value, opt_def: _ } => {
PatKind::Constant { value } => {
print_indented!(self, "Constant {", depth_lvl + 1);
print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
print_indented!(self, "}", depth_lvl + 1);
}
PatKind::InlineConstant { def, subpattern } => {
print_indented!(self, "InlineConstant {", depth_lvl + 1);
print_indented!(self, format!("def: {:?}", def), depth_lvl + 2);
PatKind::ExpandedConstant { def_id, is_inline, subpattern } => {
print_indented!(self, "ExpandedConstant {", 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
4 changes: 2 additions & 2 deletions compiler/rustc_pattern_analysis/src/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
let fields: Vec<_>;
match &pat.kind {
PatKind::AscribeUserType { subpattern, .. }
| PatKind::InlineConstant { subpattern, .. } => return self.lower_pat(subpattern),
| PatKind::ExpandedConstant { subpattern, .. } => return self.lower_pat(subpattern),
PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat),
PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
ctor = Wildcard;
Expand Down Expand Up @@ -536,7 +536,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
),
}
}
PatKind::Constant { value, opt_def: _ } => {
PatKind::Constant { value } => {
match ty.kind() {
ty::Bool => {
ctor = match value.try_eval_bool(cx.tcx, cx.param_env) {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ty_utils/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {
}

match pat.kind {
thir::PatKind::Constant { value, opt_def: _ } => value.has_non_region_param(),
thir::PatKind::Constant { value } => value.has_non_region_param(),
thir::PatKind::Range(box thir::PatRange { lo, hi, .. }) => {
lo.has_non_region_param() || hi.has_non_region_param()
}
Expand Down
21 changes: 18 additions & 3 deletions tests/ui/consts/const-pattern-irrefutable.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
mod foo {
pub const b: u8 = 2;
//~^ missing patterns are not covered because `b` is interpreted as a constant pattern, not a new variable
pub const d: u8 = 2;
pub const d: (u8, u8) = (2, 1);
//~^ missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
}

Expand All @@ -11,6 +11,15 @@ use foo::d;
const a: u8 = 2;
//~^ missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable

#[derive(PartialEq)]
struct S {
foo: u8,
}

const e: S = S {
foo: 0,
};

fn main() {
let a = 4;
//~^ ERROR refutable pattern in local binding
Expand All @@ -20,9 +29,15 @@ fn main() {
//~^ ERROR refutable pattern in local binding
//~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
//~| HELP introduce a variable instead
let d = 4;
let d = (4, 4);
//~^ ERROR refutable pattern in local binding
//~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
//~| patterns `(0_u8..=1_u8, _)` and `(3_u8..=u8::MAX, _)` not covered
//~| HELP introduce a variable instead
let e = S {
//~^ ERROR refutable pattern in local binding
//~| pattern `S { foo: 1_u8..=u8::MAX }` not covered
//~| HELP introduce a variable instead
foo: 1,
};
fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115).
}
Loading

0 comments on commit d02ba09

Please sign in to comment.