rustc_pattern_analysis/rustc/
print.rs1use std::fmt;
13
14use rustc_abi::{FieldIdx, VariantIdx};
15use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
16use rustc_span::{bug, sym};
17
18#[derive(#[automatically_derived]
impl ::core::clone::Clone for FieldPat {
#[inline]
fn clone(&self) -> FieldPat {
FieldPat {
field: ::core::clone::Clone::clone(&self.field),
pattern: ::core::clone::Clone::clone(&self.pattern),
is_wildcard: ::core::clone::Clone::clone(&self.is_wildcard),
}
}
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for FieldPat {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f, "FieldPat",
"field", &self.field, "pattern", &self.pattern, "is_wildcard",
&&self.is_wildcard)
}
}Debug)]
19pub(crate) struct FieldPat {
20 pub(crate) field: FieldIdx,
21 pub(crate) pattern: String,
22 pub(crate) is_wildcard: bool,
23}
24
25fn start_or_comma() -> impl FnMut() -> &'static str {
29 let mut first = true;
30 move || {
31 if first {
32 first = false;
33 ""
34 } else {
35 ", "
36 }
37 }
38}
39
40#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for EnumInfo<'tcx> {
#[inline]
fn clone(&self) -> EnumInfo<'tcx> {
match self {
EnumInfo::Enum { adt_def: __self_0, variant_index: __self_1 } =>
EnumInfo::Enum {
adt_def: ::core::clone::Clone::clone(__self_0),
variant_index: ::core::clone::Clone::clone(__self_1),
},
EnumInfo::NotEnum => EnumInfo::NotEnum,
}
}
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for EnumInfo<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
EnumInfo::Enum { adt_def: __self_0, variant_index: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f, "Enum",
"adt_def", __self_0, "variant_index", &__self_1),
EnumInfo::NotEnum =>
::core::fmt::Formatter::write_str(f, "NotEnum"),
}
}
}Debug)]
41pub(crate) enum EnumInfo<'tcx> {
42 Enum { adt_def: AdtDef<'tcx>, variant_index: VariantIdx },
43 NotEnum,
44}
45
46pub(crate) fn write_struct_like<'tcx>(
47 f: &mut impl fmt::Write,
48 tcx: TyCtxt<'_>,
49 ty: Ty<'tcx>,
50 enum_info: &EnumInfo<'tcx>,
51 subpatterns: &[FieldPat],
52) -> fmt::Result {
53 let variant_and_name = match *enum_info {
54 EnumInfo::Enum { adt_def, variant_index } => {
55 let variant = adt_def.variant(variant_index);
56 let adt_did = adt_def.did();
57 let name = if tcx.is_diagnostic_item(sym::Option, adt_did)
58 || tcx.is_diagnostic_item(sym::Result, adt_did)
59 {
60 variant.name.to_string()
61 } else {
62 {
let _guard =
::rustc_middle::ty::print::pretty::RtnModeHelper::with(RtnMode::ForSuggestion);
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}",
tcx.def_path_str(adt_def.did()), variant.name))
})
}ty::print::with_types_for_suggestion!(format!(
63 "{}::{}",
64 tcx.def_path_str(adt_def.did()),
65 variant.name
66 ))
67 };
68 Some((variant, name))
69 }
70 EnumInfo::NotEnum => ty.ty_adt_def().and_then(|adt_def| {
71 Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did())))
72 }),
73 };
74
75 let mut start_or_comma = start_or_comma();
76
77 if let Some((variant, name)) = &variant_and_name {
78 f.write_fmt(format_args!("{0}", name))write!(f, "{name}")?;
79
80 if variant.ctor.is_none() {
83 f.write_fmt(format_args!(" {{ "))write!(f, " {{ ")?;
84
85 let mut printed = 0;
86 for &FieldPat { field, ref pattern, is_wildcard } in subpatterns {
87 if is_wildcard {
88 continue;
89 }
90 let field_name = variant.fields[field].name;
91 f.write_fmt(format_args!("{0}{1}: {2}", start_or_comma(), field_name,
pattern))write!(f, "{}{field_name}: {pattern}", start_or_comma())?;
92 printed += 1;
93 }
94
95 let is_union = ty.ty_adt_def().is_some_and(|adt| adt.is_union());
96 if printed < variant.fields.len() && (!is_union || printed == 0) {
97 f.write_fmt(format_args!("{0}..", start_or_comma()))write!(f, "{}..", start_or_comma())?;
98 }
99
100 return f.write_fmt(format_args!(" }}"))write!(f, " }}");
101 }
102 }
103
104 let num_fields = variant_and_name.as_ref().map_or(subpatterns.len(), |(v, _)| v.fields.len());
105 if num_fields != 0 || variant_and_name.is_none() {
106 f.write_fmt(format_args!("("))write!(f, "(")?;
107 for FieldPat { pattern, .. } in subpatterns {
108 f.write_fmt(format_args!("{0}{1}", start_or_comma(), pattern))write!(f, "{}{pattern}", start_or_comma())?;
109 }
110 if #[allow(non_exhaustive_omitted_patterns)] match ty.kind() {
ty::Tuple(..) => true,
_ => false,
}matches!(ty.kind(), ty::Tuple(..)) && num_fields == 1 {
111 f.write_fmt(format_args!(","))write!(f, ",")?;
112 }
113 f.write_fmt(format_args!(")"))write!(f, ")")?;
114 }
115
116 Ok(())
117}
118
119pub(crate) fn write_ref_like<'tcx>(
120 f: &mut impl fmt::Write,
121 ty: Ty<'tcx>,
122 subpattern: &str,
123) -> fmt::Result {
124 match ty.kind() {
125 ty::Ref(_, _, mutbl) => {
126 f.write_fmt(format_args!("&{0}", mutbl.prefix_str()))write!(f, "&{}", mutbl.prefix_str())?;
127 }
128 _ => bug_impl(None, format_args!("{0} is a bad ref pattern type", ty),
Location::caller())bug!("{ty} is a bad ref pattern type"),
129 }
130 f.write_fmt(format_args!("{0}", subpattern))write!(f, "{subpattern}")
131}
132
133pub(crate) fn write_slice_like(
134 f: &mut impl fmt::Write,
135 prefix: &[String],
136 has_dot_dot: bool,
137 suffix: &[String],
138) -> fmt::Result {
139 let mut start_or_comma = start_or_comma();
140 f.write_fmt(format_args!("["))write!(f, "[")?;
141 for p in prefix.iter() {
142 f.write_fmt(format_args!("{0}{1}", start_or_comma(), p))write!(f, "{}{}", start_or_comma(), p)?;
143 }
144 if has_dot_dot {
145 f.write_fmt(format_args!("{0}..", start_or_comma()))write!(f, "{}..", start_or_comma())?;
146 }
147 for p in suffix.iter() {
148 f.write_fmt(format_args!("{0}{1}", start_or_comma(), p))write!(f, "{}{}", start_or_comma(), p)?;
149 }
150 f.write_fmt(format_args!("]"))write!(f, "]")
151}