@@ -64,130 +64,159 @@ pub(crate) enum PatKind<'tcx> {
64
64
65
65
impl<'tcx> fmt::Display for Pat<'tcx> {
66
66
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67
- // Printing lists is a chore.
68
- let mut first = true;
69
- let mut start_or_continue = |s| {
70
- if first {
71
- first = false;
72
- ""
73
- } else {
74
- s
75
- }
76
- };
77
- let mut start_or_comma = || start_or_continue(", ");
78
-
79
67
match self.kind {
80
68
PatKind::Wild => write!(f, "_"),
81
69
PatKind::Never => write!(f, "!"),
82
70
PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => {
83
- let variant_and_name = match self.kind {
84
- PatKind::Variant { adt_def, variant_index, .. } => ty::tls::with(|tcx| {
85
- let variant = adt_def.variant(variant_index);
86
- let adt_did = adt_def.did();
87
- let name = if tcx.get_diagnostic_item(sym::Option) == Some(adt_did)
88
- || tcx.get_diagnostic_item(sym::Result) == Some(adt_did)
89
- {
90
- variant.name.to_string()
91
- } else {
92
- format!("{}::{}", tcx.def_path_str(adt_def.did()), variant.name)
93
- };
94
- Some((variant, name))
95
- }),
96
- _ => self.ty.ty_adt_def().and_then(|adt_def| {
97
- if !adt_def.is_enum() {
98
- ty::tls::with(|tcx| {
99
- Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did())))
100
- })
101
- } else {
102
- None
103
- }
104
- }),
105
- };
106
-
107
- if let Some((variant, name)) = &variant_and_name {
108
- write!(f, "{name}")?;
109
-
110
- // Only for Adt we can have `S {...}`,
111
- // which we handle separately here.
112
- if variant.ctor.is_none() {
113
- write!(f, " {{ ")?;
114
-
115
- let mut printed = 0;
116
- for p in subpatterns {
117
- if let PatKind::Wild = p.pattern.kind {
118
- continue;
119
- }
120
- let name = variant.fields[p.field].name;
121
- write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
122
- printed += 1;
123
- }
124
-
125
- let is_union = self.ty.ty_adt_def().is_some_and(|adt| adt.is_union());
126
- if printed < variant.fields.len() && (!is_union || printed == 0) {
127
- write!(f, "{}..", start_or_comma())?;
128
- }
129
-
130
- return write!(f, " }}");
131
- }
132
- }
133
-
134
- let num_fields =
135
- variant_and_name.as_ref().map_or(subpatterns.len(), |(v, _)| v.fields.len());
136
- if num_fields != 0 || variant_and_name.is_none() {
137
- write!(f, "(")?;
138
- for i in 0..num_fields {
139
- write!(f, "{}", start_or_comma())?;
140
-
141
- // Common case: the field is where we expect it.
142
- if let Some(p) = subpatterns.get(i) {
143
- if p.field.index() == i {
144
- write!(f, "{}", p.pattern)?;
145
- continue;
146
- }
147
- }
148
-
149
- // Otherwise, we have to go looking for it.
150
- if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
151
- write!(f, "{}", p.pattern)?;
152
- } else {
153
- write!(f, "_")?;
154
- }
155
- }
156
- write!(f, ")")?;
157
- }
158
-
159
- Ok(())
160
- }
161
- PatKind::Deref { ref subpattern } => {
162
- match self.ty.kind() {
163
- ty::Adt(def, _) if def.is_box() => write!(f, "box ")?,
164
- ty::Ref(_, _, mutbl) => {
165
- write!(f, "&{}", mutbl.prefix_str())?;
166
- }
167
- _ => bug!("{} is a bad Deref pattern type", self.ty),
168
- }
169
- write!(f, "{subpattern}")
71
+ write_struct_like(f, self.ty, &self.kind, subpatterns)
170
72
}
73
+ PatKind::Deref { ref subpattern } => write_ref_like(f, self.ty, subpattern),
171
74
PatKind::Constant { value } => write!(f, "{value}"),
172
75
PatKind::Range(ref range) => write!(f, "{range}"),
173
76
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
174
- write!(f, "[")?;
175
- for p in prefix.iter() {
176
- write!(f, "{}{}", start_or_comma(), p)?;
177
- }
178
- if let Some(ref slice) = *slice {
179
- write!(f, "{}", start_or_comma())?;
180
- match slice.kind {
181
- PatKind::Wild => {}
182
- _ => write!(f, "{slice}")?,
183
- }
184
- write!(f, "..")?;
77
+ write_slice_like(f, prefix, slice, suffix)
78
+ }
79
+ }
80
+ }
81
+ }
82
+
83
+ /// Returns a closure that will return `""` when called the first time,
84
+ /// and then return `", "` when called any subsequent times.
85
+ /// Useful for printing comma-separated lists.
86
+ fn start_or_comma() -> impl FnMut() -> &'static str {
87
+ let mut first = true;
88
+ move || {
89
+ if first {
90
+ first = false;
91
+ ""
92
+ } else {
93
+ ", "
94
+ }
95
+ }
96
+ }
97
+
98
+ fn write_struct_like<'tcx>(
99
+ f: &mut impl fmt::Write,
100
+ ty: Ty<'tcx>,
101
+ kind: &PatKind<'tcx>,
102
+ subpatterns: &[FieldPat<'tcx>],
103
+ ) -> fmt::Result {
104
+ let variant_and_name = match *kind {
105
+ PatKind::Variant { adt_def, variant_index, .. } => ty::tls::with(|tcx| {
106
+ let variant = adt_def.variant(variant_index);
107
+ let adt_did = adt_def.did();
108
+ let name = if tcx.get_diagnostic_item(sym::Option) == Some(adt_did)
109
+ || tcx.get_diagnostic_item(sym::Result) == Some(adt_did)
110
+ {
111
+ variant.name.to_string()
112
+ } else {
113
+ format!("{}::{}", tcx.def_path_str(adt_def.did()), variant.name)
114
+ };
115
+ Some((variant, name))
116
+ }),
117
+ _ => ty.ty_adt_def().and_then(|adt_def| {
118
+ if !adt_def.is_enum() {
119
+ ty::tls::with(|tcx| {
120
+ Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did())))
121
+ })
122
+ } else {
123
+ None
124
+ }
125
+ }),
126
+ };
127
+
128
+ let mut start_or_comma = start_or_comma();
129
+
130
+ if let Some((variant, name)) = &variant_and_name {
131
+ write!(f, "{name}")?;
132
+
133
+ // Only for Adt we can have `S {...}`,
134
+ // which we handle separately here.
135
+ if variant.ctor.is_none() {
136
+ write!(f, " {{ ")?;
137
+
138
+ let mut printed = 0;
139
+ for p in subpatterns {
140
+ if let PatKind::Wild = p.pattern.kind {
141
+ continue;
185
142
}
186
- for p in suffix.iter() {
187
- write!(f, "{}{}", start_or_comma(), p)?;
143
+ let name = variant.fields[p.field].name;
144
+ write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
145
+ printed += 1;
146
+ }
147
+
148
+ let is_union = ty.ty_adt_def().is_some_and(|adt| adt.is_union());
149
+ if printed < variant.fields.len() && (!is_union || printed == 0) {
150
+ write!(f, "{}..", start_or_comma())?;
151
+ }
152
+
153
+ return write!(f, " }}");
154
+ }
155
+ }
156
+
157
+ let num_fields = variant_and_name.as_ref().map_or(subpatterns.len(), |(v, _)| v.fields.len());
158
+ if num_fields != 0 || variant_and_name.is_none() {
159
+ write!(f, "(")?;
160
+ for i in 0..num_fields {
161
+ write!(f, "{}", start_or_comma())?;
162
+
163
+ // Common case: the field is where we expect it.
164
+ if let Some(p) = subpatterns.get(i) {
165
+ if p.field.index() == i {
166
+ write!(f, "{}", p.pattern)?;
167
+ continue;
188
168
}
189
- write!(f, "]")
169
+ }
170
+
171
+ // Otherwise, we have to go looking for it.
172
+ if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
173
+ write!(f, "{}", p.pattern)?;
174
+ } else {
175
+ write!(f, "_")?;
190
176
}
191
177
}
178
+ write!(f, ")")?;
179
+ }
180
+
181
+ Ok(())
182
+ }
183
+
184
+ fn write_ref_like<'tcx>(
185
+ f: &mut impl fmt::Write,
186
+ ty: Ty<'tcx>,
187
+ subpattern: &Pat<'tcx>,
188
+ ) -> fmt::Result {
189
+ match ty.kind() {
190
+ ty::Adt(def, _) if def.is_box() => write!(f, "box ")?,
191
+ ty::Ref(_, _, mutbl) => {
192
+ write!(f, "&{}", mutbl.prefix_str())?;
193
+ }
194
+ _ => bug!("{ty} is a bad ref pattern type"),
195
+ }
196
+ write!(f, "{subpattern}")
197
+ }
198
+
199
+ fn write_slice_like<'tcx>(
200
+ f: &mut impl fmt::Write,
201
+ prefix: &[Box<Pat<'tcx>>],
202
+ slice: &Option<Box<Pat<'tcx>>>,
203
+ suffix: &[Box<Pat<'tcx>>],
204
+ ) -> fmt::Result {
205
+ let mut start_or_comma = start_or_comma();
206
+ write!(f, "[")?;
207
+ for p in prefix.iter() {
208
+ write!(f, "{}{}", start_or_comma(), p)?;
209
+ }
210
+ if let Some(ref slice) = *slice {
211
+ write!(f, "{}", start_or_comma())?;
212
+ match slice.kind {
213
+ PatKind::Wild => {}
214
+ _ => write!(f, "{slice}")?,
215
+ }
216
+ write!(f, "..")?;
217
+ }
218
+ for p in suffix.iter() {
219
+ write!(f, "{}{}", start_or_comma(), p)?;
192
220
}
221
+ write!(f, "]")
193
222
}
0 commit comments