Break up print::Pat
printing into several helper functions
This commit is contained in:
parent
6a2cd0d50c
commit
ccfd94e334
@ -64,130 +64,159 @@ pub(crate) enum PatKind<'tcx> {
|
||||
|
||||
impl<'tcx> fmt::Display for Pat<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// Printing lists is a chore.
|
||||
let mut first = true;
|
||||
let mut start_or_continue = |s| {
|
||||
if first {
|
||||
first = false;
|
||||
""
|
||||
} else {
|
||||
s
|
||||
}
|
||||
};
|
||||
let mut start_or_comma = || start_or_continue(", ");
|
||||
|
||||
match self.kind {
|
||||
PatKind::Wild => write!(f, "_"),
|
||||
PatKind::Never => write!(f, "!"),
|
||||
PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => {
|
||||
let variant_and_name = match self.kind {
|
||||
PatKind::Variant { adt_def, variant_index, .. } => ty::tls::with(|tcx| {
|
||||
let variant = adt_def.variant(variant_index);
|
||||
let adt_did = adt_def.did();
|
||||
let name = if tcx.get_diagnostic_item(sym::Option) == Some(adt_did)
|
||||
|| tcx.get_diagnostic_item(sym::Result) == Some(adt_did)
|
||||
{
|
||||
variant.name.to_string()
|
||||
} else {
|
||||
format!("{}::{}", tcx.def_path_str(adt_def.did()), variant.name)
|
||||
};
|
||||
Some((variant, name))
|
||||
}),
|
||||
_ => self.ty.ty_adt_def().and_then(|adt_def| {
|
||||
if !adt_def.is_enum() {
|
||||
ty::tls::with(|tcx| {
|
||||
Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did())))
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}),
|
||||
};
|
||||
|
||||
if let Some((variant, name)) = &variant_and_name {
|
||||
write!(f, "{name}")?;
|
||||
|
||||
// Only for Adt we can have `S {...}`,
|
||||
// which we handle separately here.
|
||||
if variant.ctor.is_none() {
|
||||
write!(f, " {{ ")?;
|
||||
|
||||
let mut printed = 0;
|
||||
for p in subpatterns {
|
||||
if let PatKind::Wild = p.pattern.kind {
|
||||
continue;
|
||||
}
|
||||
let name = variant.fields[p.field].name;
|
||||
write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
|
||||
printed += 1;
|
||||
}
|
||||
|
||||
let is_union = self.ty.ty_adt_def().is_some_and(|adt| adt.is_union());
|
||||
if printed < variant.fields.len() && (!is_union || printed == 0) {
|
||||
write!(f, "{}..", start_or_comma())?;
|
||||
}
|
||||
|
||||
return write!(f, " }}");
|
||||
}
|
||||
}
|
||||
|
||||
let num_fields =
|
||||
variant_and_name.as_ref().map_or(subpatterns.len(), |(v, _)| v.fields.len());
|
||||
if num_fields != 0 || variant_and_name.is_none() {
|
||||
write!(f, "(")?;
|
||||
for i in 0..num_fields {
|
||||
write!(f, "{}", start_or_comma())?;
|
||||
|
||||
// Common case: the field is where we expect it.
|
||||
if let Some(p) = subpatterns.get(i) {
|
||||
if p.field.index() == i {
|
||||
write!(f, "{}", p.pattern)?;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, we have to go looking for it.
|
||||
if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
|
||||
write!(f, "{}", p.pattern)?;
|
||||
} else {
|
||||
write!(f, "_")?;
|
||||
}
|
||||
}
|
||||
write!(f, ")")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
PatKind::Deref { ref subpattern } => {
|
||||
match self.ty.kind() {
|
||||
ty::Adt(def, _) if def.is_box() => write!(f, "box ")?,
|
||||
ty::Ref(_, _, mutbl) => {
|
||||
write!(f, "&{}", mutbl.prefix_str())?;
|
||||
}
|
||||
_ => bug!("{} is a bad Deref pattern type", self.ty),
|
||||
}
|
||||
write!(f, "{subpattern}")
|
||||
write_struct_like(f, self.ty, &self.kind, subpatterns)
|
||||
}
|
||||
PatKind::Deref { ref subpattern } => write_ref_like(f, self.ty, subpattern),
|
||||
PatKind::Constant { value } => write!(f, "{value}"),
|
||||
PatKind::Range(ref range) => write!(f, "{range}"),
|
||||
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
|
||||
write!(f, "[")?;
|
||||
for p in prefix.iter() {
|
||||
write!(f, "{}{}", start_or_comma(), p)?;
|
||||
}
|
||||
if let Some(ref slice) = *slice {
|
||||
write!(f, "{}", start_or_comma())?;
|
||||
match slice.kind {
|
||||
PatKind::Wild => {}
|
||||
_ => write!(f, "{slice}")?,
|
||||
}
|
||||
write!(f, "..")?;
|
||||
}
|
||||
for p in suffix.iter() {
|
||||
write!(f, "{}{}", start_or_comma(), p)?;
|
||||
}
|
||||
write!(f, "]")
|
||||
write_slice_like(f, prefix, slice, suffix)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a closure that will return `""` when called the first time,
|
||||
/// and then return `", "` when called any subsequent times.
|
||||
/// Useful for printing comma-separated lists.
|
||||
fn start_or_comma() -> impl FnMut() -> &'static str {
|
||||
let mut first = true;
|
||||
move || {
|
||||
if first {
|
||||
first = false;
|
||||
""
|
||||
} else {
|
||||
", "
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn write_struct_like<'tcx>(
|
||||
f: &mut impl fmt::Write,
|
||||
ty: Ty<'tcx>,
|
||||
kind: &PatKind<'tcx>,
|
||||
subpatterns: &[FieldPat<'tcx>],
|
||||
) -> fmt::Result {
|
||||
let variant_and_name = match *kind {
|
||||
PatKind::Variant { adt_def, variant_index, .. } => ty::tls::with(|tcx| {
|
||||
let variant = adt_def.variant(variant_index);
|
||||
let adt_did = adt_def.did();
|
||||
let name = if tcx.get_diagnostic_item(sym::Option) == Some(adt_did)
|
||||
|| tcx.get_diagnostic_item(sym::Result) == Some(adt_did)
|
||||
{
|
||||
variant.name.to_string()
|
||||
} else {
|
||||
format!("{}::{}", tcx.def_path_str(adt_def.did()), variant.name)
|
||||
};
|
||||
Some((variant, name))
|
||||
}),
|
||||
_ => ty.ty_adt_def().and_then(|adt_def| {
|
||||
if !adt_def.is_enum() {
|
||||
ty::tls::with(|tcx| {
|
||||
Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did())))
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}),
|
||||
};
|
||||
|
||||
let mut start_or_comma = start_or_comma();
|
||||
|
||||
if let Some((variant, name)) = &variant_and_name {
|
||||
write!(f, "{name}")?;
|
||||
|
||||
// Only for Adt we can have `S {...}`,
|
||||
// which we handle separately here.
|
||||
if variant.ctor.is_none() {
|
||||
write!(f, " {{ ")?;
|
||||
|
||||
let mut printed = 0;
|
||||
for p in subpatterns {
|
||||
if let PatKind::Wild = p.pattern.kind {
|
||||
continue;
|
||||
}
|
||||
let name = variant.fields[p.field].name;
|
||||
write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
|
||||
printed += 1;
|
||||
}
|
||||
|
||||
let is_union = ty.ty_adt_def().is_some_and(|adt| adt.is_union());
|
||||
if printed < variant.fields.len() && (!is_union || printed == 0) {
|
||||
write!(f, "{}..", start_or_comma())?;
|
||||
}
|
||||
|
||||
return write!(f, " }}");
|
||||
}
|
||||
}
|
||||
|
||||
let num_fields = variant_and_name.as_ref().map_or(subpatterns.len(), |(v, _)| v.fields.len());
|
||||
if num_fields != 0 || variant_and_name.is_none() {
|
||||
write!(f, "(")?;
|
||||
for i in 0..num_fields {
|
||||
write!(f, "{}", start_or_comma())?;
|
||||
|
||||
// Common case: the field is where we expect it.
|
||||
if let Some(p) = subpatterns.get(i) {
|
||||
if p.field.index() == i {
|
||||
write!(f, "{}", p.pattern)?;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, we have to go looking for it.
|
||||
if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
|
||||
write!(f, "{}", p.pattern)?;
|
||||
} else {
|
||||
write!(f, "_")?;
|
||||
}
|
||||
}
|
||||
write!(f, ")")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_ref_like<'tcx>(
|
||||
f: &mut impl fmt::Write,
|
||||
ty: Ty<'tcx>,
|
||||
subpattern: &Pat<'tcx>,
|
||||
) -> fmt::Result {
|
||||
match ty.kind() {
|
||||
ty::Adt(def, _) if def.is_box() => write!(f, "box ")?,
|
||||
ty::Ref(_, _, mutbl) => {
|
||||
write!(f, "&{}", mutbl.prefix_str())?;
|
||||
}
|
||||
_ => bug!("{ty} is a bad ref pattern type"),
|
||||
}
|
||||
write!(f, "{subpattern}")
|
||||
}
|
||||
|
||||
fn write_slice_like<'tcx>(
|
||||
f: &mut impl fmt::Write,
|
||||
prefix: &[Box<Pat<'tcx>>],
|
||||
slice: &Option<Box<Pat<'tcx>>>,
|
||||
suffix: &[Box<Pat<'tcx>>],
|
||||
) -> fmt::Result {
|
||||
let mut start_or_comma = start_or_comma();
|
||||
write!(f, "[")?;
|
||||
for p in prefix.iter() {
|
||||
write!(f, "{}{}", start_or_comma(), p)?;
|
||||
}
|
||||
if let Some(ref slice) = *slice {
|
||||
write!(f, "{}", start_or_comma())?;
|
||||
match slice.kind {
|
||||
PatKind::Wild => {}
|
||||
_ => write!(f, "{slice}")?,
|
||||
}
|
||||
write!(f, "..")?;
|
||||
}
|
||||
for p in suffix.iter() {
|
||||
write!(f, "{}{}", start_or_comma(), p)?;
|
||||
}
|
||||
write!(f, "]")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user