Skip to content

Commit dd5a8d7

Browse files
committed
Use a separate pattern type for rustc_pattern_analysis diagnostics
The pattern-analysis code needs to print patterns, as part of its user-visible diagnostics. But it never actually tries to print "real" patterns! Instead, it only ever prints synthetic patterns that it has reconstructed from its own internal represenations. We can therefore simultaneously remove two obstacles to changing `thir::Pat`, by having the pattern-analysis code use its own dedicated type for building printable patterns, and then making `thir::Pat` not printable at all.
1 parent a9ea85e commit dd5a8d7

File tree

3 files changed

+209
-169
lines changed

3 files changed

+209
-169
lines changed

compiler/rustc_middle/src/thir.rs

+1-158
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use rustc_middle::ty::{
2828
TyCtxt, UpvarArgs,
2929
};
3030
use rustc_span::def_id::LocalDefId;
31-
use rustc_span::{sym, ErrorGuaranteed, Span, Symbol, DUMMY_SP};
31+
use rustc_span::{ErrorGuaranteed, Span, Symbol};
3232
use rustc_target::abi::{FieldIdx, Integer, Size, VariantIdx};
3333
use rustc_target::asm::InlineAsmRegOrRegClass;
3434
use tracing::instrument;
@@ -597,10 +597,6 @@ pub struct Pat<'tcx> {
597597
}
598598

599599
impl<'tcx> Pat<'tcx> {
600-
pub fn wildcard_from_ty(ty: Ty<'tcx>) -> Self {
601-
Pat { ty, span: DUMMY_SP, kind: PatKind::Wild }
602-
}
603-
604600
pub fn simple_ident(&self) -> Option<Symbol> {
605601
match self.kind {
606602
PatKind::Binding {
@@ -1073,159 +1069,6 @@ impl<'tcx> PatRangeBoundary<'tcx> {
10731069
}
10741070
}
10751071

1076-
impl<'tcx> fmt::Display for Pat<'tcx> {
1077-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1078-
// Printing lists is a chore.
1079-
let mut first = true;
1080-
let mut start_or_continue = |s| {
1081-
if first {
1082-
first = false;
1083-
""
1084-
} else {
1085-
s
1086-
}
1087-
};
1088-
let mut start_or_comma = || start_or_continue(", ");
1089-
1090-
match self.kind {
1091-
PatKind::Wild => write!(f, "_"),
1092-
PatKind::Never => write!(f, "!"),
1093-
PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{subpattern}: _"),
1094-
PatKind::Binding { name, mode, ref subpattern, .. } => {
1095-
f.write_str(mode.prefix_str())?;
1096-
write!(f, "{name}")?;
1097-
if let Some(ref subpattern) = *subpattern {
1098-
write!(f, " @ {subpattern}")?;
1099-
}
1100-
Ok(())
1101-
}
1102-
PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => {
1103-
let variant_and_name = match self.kind {
1104-
PatKind::Variant { adt_def, variant_index, .. } => ty::tls::with(|tcx| {
1105-
let variant = adt_def.variant(variant_index);
1106-
let adt_did = adt_def.did();
1107-
let name = if tcx.get_diagnostic_item(sym::Option) == Some(adt_did)
1108-
|| tcx.get_diagnostic_item(sym::Result) == Some(adt_did)
1109-
{
1110-
variant.name.to_string()
1111-
} else {
1112-
format!("{}::{}", tcx.def_path_str(adt_def.did()), variant.name)
1113-
};
1114-
Some((variant, name))
1115-
}),
1116-
_ => self.ty.ty_adt_def().and_then(|adt_def| {
1117-
if !adt_def.is_enum() {
1118-
ty::tls::with(|tcx| {
1119-
Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did())))
1120-
})
1121-
} else {
1122-
None
1123-
}
1124-
}),
1125-
};
1126-
1127-
if let Some((variant, name)) = &variant_and_name {
1128-
write!(f, "{name}")?;
1129-
1130-
// Only for Adt we can have `S {...}`,
1131-
// which we handle separately here.
1132-
if variant.ctor.is_none() {
1133-
write!(f, " {{ ")?;
1134-
1135-
let mut printed = 0;
1136-
for p in subpatterns {
1137-
if let PatKind::Wild = p.pattern.kind {
1138-
continue;
1139-
}
1140-
let name = variant.fields[p.field].name;
1141-
write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
1142-
printed += 1;
1143-
}
1144-
1145-
let is_union = self.ty.ty_adt_def().is_some_and(|adt| adt.is_union());
1146-
if printed < variant.fields.len() && (!is_union || printed == 0) {
1147-
write!(f, "{}..", start_or_comma())?;
1148-
}
1149-
1150-
return write!(f, " }}");
1151-
}
1152-
}
1153-
1154-
let num_fields =
1155-
variant_and_name.as_ref().map_or(subpatterns.len(), |(v, _)| v.fields.len());
1156-
if num_fields != 0 || variant_and_name.is_none() {
1157-
write!(f, "(")?;
1158-
for i in 0..num_fields {
1159-
write!(f, "{}", start_or_comma())?;
1160-
1161-
// Common case: the field is where we expect it.
1162-
if let Some(p) = subpatterns.get(i) {
1163-
if p.field.index() == i {
1164-
write!(f, "{}", p.pattern)?;
1165-
continue;
1166-
}
1167-
}
1168-
1169-
// Otherwise, we have to go looking for it.
1170-
if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
1171-
write!(f, "{}", p.pattern)?;
1172-
} else {
1173-
write!(f, "_")?;
1174-
}
1175-
}
1176-
write!(f, ")")?;
1177-
}
1178-
1179-
Ok(())
1180-
}
1181-
PatKind::Deref { ref subpattern } => {
1182-
match self.ty.kind() {
1183-
ty::Adt(def, _) if def.is_box() => write!(f, "box ")?,
1184-
ty::Ref(_, _, mutbl) => {
1185-
write!(f, "&{}", mutbl.prefix_str())?;
1186-
}
1187-
_ => bug!("{} is a bad Deref pattern type", self.ty),
1188-
}
1189-
write!(f, "{subpattern}")
1190-
}
1191-
PatKind::DerefPattern { ref subpattern, .. } => {
1192-
write!(f, "deref!({subpattern})")
1193-
}
1194-
PatKind::Constant { value } => write!(f, "{value}"),
1195-
PatKind::InlineConstant { def: _, ref subpattern } => {
1196-
write!(f, "{} (from inline const)", subpattern)
1197-
}
1198-
PatKind::Range(ref range) => write!(f, "{range}"),
1199-
PatKind::Slice { ref prefix, ref slice, ref suffix }
1200-
| PatKind::Array { ref prefix, ref slice, ref suffix } => {
1201-
write!(f, "[")?;
1202-
for p in prefix.iter() {
1203-
write!(f, "{}{}", start_or_comma(), p)?;
1204-
}
1205-
if let Some(ref slice) = *slice {
1206-
write!(f, "{}", start_or_comma())?;
1207-
match slice.kind {
1208-
PatKind::Wild => {}
1209-
_ => write!(f, "{slice}")?,
1210-
}
1211-
write!(f, "..")?;
1212-
}
1213-
for p in suffix.iter() {
1214-
write!(f, "{}{}", start_or_comma(), p)?;
1215-
}
1216-
write!(f, "]")
1217-
}
1218-
PatKind::Or { ref pats } => {
1219-
for pat in pats.iter() {
1220-
write!(f, "{}{}", start_or_continue(" | "), pat)?;
1221-
}
1222-
Ok(())
1223-
}
1224-
PatKind::Error(_) => write!(f, "<error>"),
1225-
}
1226-
}
1227-
}
1228-
12291072
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
12301073
#[cfg(target_pointer_width = "64")]
12311074
mod size_asserts {

compiler/rustc_pattern_analysis/src/rustc.rs

+15-11
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_hir::HirId;
77
use rustc_index::{Idx, IndexVec};
88
use rustc_middle::middle::stability::EvalResult;
99
use rustc_middle::mir::{self, Const};
10-
use rustc_middle::thir::{self, FieldPat, Pat, PatKind, PatRange, PatRangeBoundary};
10+
use rustc_middle::thir::{self, Pat, PatKind, PatRange, PatRangeBoundary};
1111
use rustc_middle::ty::layout::IntegerExt;
1212
use rustc_middle::ty::{
1313
self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeVisitableExt, VariantDef,
@@ -26,6 +26,8 @@ use crate::pat_column::PatternColumn;
2626
use crate::usefulness::{compute_match_usefulness, PlaceValidity};
2727
use crate::{errors, Captures, PatCx, PrivateUninhabitedField};
2828

29+
mod print;
30+
2931
// Re-export rustc-specific versions of all these types.
3032
pub type Constructor<'p, 'tcx> = crate::constructor::Constructor<RustcPatCtxt<'p, 'tcx>>;
3133
pub type ConstructorSet<'p, 'tcx> = crate::constructor::ConstructorSet<RustcPatCtxt<'p, 'tcx>>;
@@ -773,8 +775,9 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
773775
}
774776
}
775777

776-
/// Convert back to a `thir::Pat` for diagnostic purposes.
777-
fn hoist_pat_range(&self, range: &IntRange, ty: RevealedTy<'tcx>) -> Pat<'tcx> {
778+
/// Convert to a [`print::Pat`] for diagnostic purposes.
779+
fn hoist_pat_range(&self, range: &IntRange, ty: RevealedTy<'tcx>) -> print::Pat<'tcx> {
780+
use print::{Pat, PatKind};
778781
use MaybeInfiniteInt::*;
779782
let cx = self;
780783
let kind = if matches!((range.lo, range.hi), (NegInfinity, PosInfinity)) {
@@ -808,19 +811,20 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
808811
PatKind::Range(Box::new(PatRange { lo, hi, end, ty: ty.inner() }))
809812
};
810813

811-
Pat { ty: ty.inner(), span: DUMMY_SP, kind }
814+
Pat { ty: ty.inner(), kind }
812815
}
813816

814817
/// Prints a [`WitnessPat`] to an owned string, for diagnostic purposes.
815818
pub fn print_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> String {
816-
// This works by converting the witness pattern back to a `thir::Pat`
819+
// This works by converting the witness pattern to a `print::Pat`
817820
// and then printing that, but callers don't need to know that.
818821
self.hoist_witness_pat(pat).to_string()
819822
}
820823

821-
/// Convert back to a `thir::Pat` for diagnostic purposes. This panics for patterns that don't
824+
/// Convert to a [`print::Pat`] for diagnostic purposes. This panics for patterns that don't
822825
/// appear in diagnostics, like float ranges.
823-
fn hoist_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> Pat<'tcx> {
826+
fn hoist_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> print::Pat<'tcx> {
827+
use print::{FieldPat, Pat, PatKind};
824828
let cx = self;
825829
let is_wildcard = |pat: &Pat<'_>| matches!(pat.kind, PatKind::Wild);
826830
let mut subpatterns = pat.iter_fields().map(|p| Box::new(cx.hoist_witness_pat(p)));
@@ -840,15 +844,15 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
840844
// the pattern is a box pattern.
841845
PatKind::Deref { subpattern: subpatterns.next().unwrap() }
842846
}
843-
ty::Adt(adt_def, args) => {
847+
ty::Adt(adt_def, _args) => {
844848
let variant_index = RustcPatCtxt::variant_index_for_adt(&pat.ctor(), *adt_def);
845849
let subpatterns = subpatterns
846850
.enumerate()
847851
.map(|(i, pattern)| FieldPat { field: FieldIdx::new(i), pattern })
848852
.collect();
849853

850854
if adt_def.is_enum() {
851-
PatKind::Variant { adt_def: *adt_def, args, variant_index, subpatterns }
855+
PatKind::Variant { adt_def: *adt_def, variant_index, subpatterns }
852856
} else {
853857
PatKind::Leaf { subpatterns }
854858
}
@@ -885,7 +889,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
885889
}
886890
}
887891
let suffix: Box<[_]> = subpatterns.collect();
888-
let wild = Pat::wildcard_from_ty(pat.ty().inner());
892+
let wild = Pat { ty: pat.ty().inner(), kind: PatKind::Wild };
889893
PatKind::Slice {
890894
prefix: prefix.into_boxed_slice(),
891895
slice: Some(Box::new(wild)),
@@ -906,7 +910,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
906910
}
907911
};
908912

909-
Pat { ty: pat.ty().inner(), span: DUMMY_SP, kind }
913+
Pat { ty: pat.ty().inner(), kind }
910914
}
911915
}
912916

0 commit comments

Comments
 (0)