]>
Commit | Line | Data |
---|---|---|
9fa01778 | 1 | //! Validation of patterns/matches. |
c30ab7b3 | 2 | |
0531ce1d | 3 | mod check_match; |
e74abb32 | 4 | mod const_to_pat; |
9c376795 | 5 | pub(crate) mod deconstruct_pat; |
fc512014 | 6 | mod usefulness; |
0531ce1d | 7 | |
0531ce1d | 8 | pub(crate) use self::check_match::check_match; |
9c376795 | 9 | pub(crate) use self::usefulness::MatchCheckCtxt; |
0531ce1d | 10 | |
9c376795 | 11 | use crate::errors::*; |
3dfed10e | 12 | use crate::thir::util::UserAnnotatedTyHelpers; |
0531ce1d | 13 | |
9c376795 | 14 | use rustc_errors::error_code; |
dfeec247 | 15 | use rustc_hir as hir; |
17df50a5 | 16 | use rustc_hir::def::{CtorOf, DefKind, Res}; |
dfeec247 XL |
17 | use rustc_hir::pat_util::EnumerateAndAdjustIterator; |
18 | use rustc_hir::RangeEnd; | |
49aad941 | 19 | use rustc_index::Idx; |
ed00b5ec FG |
20 | use rustc_middle::mir::interpret::{ErrorHandled, GlobalId, LitToConstError, LitToConstInput}; |
21 | use rustc_middle::mir::{self, BorrowKind, Const, Mutability, UserTypeProjection}; | |
22 | use rustc_middle::thir::{ | |
23 | Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary, | |
923072b8 | 24 | }; |
ed00b5ec FG |
25 | use rustc_middle::ty::layout::IntegerExt; |
26 | use rustc_middle::ty::{ | |
27 | self, AdtDef, CanonicalUserTypeAnnotation, GenericArg, GenericArgsRef, Region, Ty, TyCtxt, | |
28 | TypeVisitableExt, UserType, | |
29 | }; | |
30 | use rustc_span::def_id::LocalDefId; | |
31 | use rustc_span::{ErrorGuaranteed, Span, Symbol}; | |
32 | use rustc_target::abi::{FieldIdx, Integer}; | |
c30ab7b3 | 33 | |
0531ce1d | 34 | use std::cmp::Ordering; |
c30ab7b3 | 35 | |
f2b60f7d FG |
36 | struct PatCtxt<'a, 'tcx> { |
37 | tcx: TyCtxt<'tcx>, | |
38 | param_env: ty::ParamEnv<'tcx>, | |
39 | typeck_results: &'a ty::TypeckResults<'tcx>, | |
c30ab7b3 SL |
40 | } |
41 | ||
f2b60f7d | 42 | pub(super) fn pat_from_hir<'a, 'tcx>( |
17df50a5 XL |
43 | tcx: TyCtxt<'tcx>, |
44 | param_env: ty::ParamEnv<'tcx>, | |
45 | typeck_results: &'a ty::TypeckResults<'tcx>, | |
46 | pat: &'tcx hir::Pat<'tcx>, | |
f2b60f7d | 47 | ) -> Box<Pat<'tcx>> { |
353b0b11 | 48 | let mut pcx = PatCtxt { tcx, param_env, typeck_results }; |
17df50a5 | 49 | let result = pcx.lower_pattern(pat); |
17df50a5 XL |
50 | debug!("pat_from_hir({:?}) = {:?}", pat, result); |
51 | result | |
c30ab7b3 SL |
52 | } |
53 | ||
e74abb32 | 54 | impl<'a, 'tcx> PatCtxt<'a, 'tcx> { |
f2b60f7d | 55 | fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> { |
ea8adc8c XL |
56 | // When implicit dereferences have been inserted in this pattern, the unadjusted lowered |
57 | // pattern has the type that results *after* dereferencing. For example, in this code: | |
58 | // | |
59 | // ``` | |
60 | // match &&Some(0i32) { | |
61 | // Some(n) => { ... }, | |
62 | // _ => { ... }, | |
63 | // } | |
64 | // ``` | |
65 | // | |
66 | // the type assigned to `Some(n)` in `unadjusted_pat` would be `Option<i32>` (this is | |
2b03887a | 67 | // determined in rustc_hir_analysis::check::match). The adjustments would be |
ea8adc8c XL |
68 | // |
69 | // `vec![&&Option<i32>, &Option<i32>]`. | |
70 | // | |
3dfed10e | 71 | // Applying the adjustments, we want to instead output `&&Some(n)` (as a THIR pattern). So |
e74abb32 | 72 | // we wrap the unadjusted pattern in `PatKind::Deref` repeatedly, consuming the |
ea8adc8c XL |
73 | // adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted |
74 | // gets the least-dereferenced type). | |
75 | let unadjusted_pat = self.lower_pattern_unadjusted(pat); | |
3dfed10e | 76 | self.typeck_results.pat_adjustments().get(pat.hir_id).unwrap_or(&vec![]).iter().rev().fold( |
dfeec247 | 77 | unadjusted_pat, |
f2b60f7d | 78 | |pat: Box<_>, ref_ty| { |
dfeec247 | 79 | debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty); |
f2b60f7d | 80 | Box::new(Pat { |
dfeec247 | 81 | span: pat.span, |
5099ac24 | 82 | ty: *ref_ty, |
f2b60f7d FG |
83 | kind: PatKind::Deref { subpattern: pat }, |
84 | }) | |
dfeec247 XL |
85 | }, |
86 | ) | |
ea8adc8c XL |
87 | } |
88 | ||
ed00b5ec | 89 | fn lower_pattern_range_endpoint( |
9fa01778 | 90 | &mut self, |
ed00b5ec FG |
91 | expr: Option<&'tcx hir::Expr<'tcx>>, |
92 | ) -> Result< | |
93 | (Option<PatRangeBoundary<'tcx>>, Option<Ascription<'tcx>>, Option<LocalDefId>), | |
94 | ErrorGuaranteed, | |
95 | > { | |
96 | match expr { | |
97 | None => Ok((None, None, None)), | |
98 | Some(expr) => { | |
99 | let (kind, ascr, inline_const) = match self.lower_lit(expr) { | |
100 | PatKind::InlineConstant { subpattern, def } => { | |
101 | (subpattern.kind, None, Some(def)) | |
102 | } | |
103 | PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => { | |
104 | (kind, Some(ascription), None) | |
105 | } | |
106 | kind => (kind, None, None), | |
107 | }; | |
108 | let value = if let PatKind::Constant { value } = kind { | |
109 | value | |
110 | } else { | |
111 | let msg = format!( | |
112 | "found bad range pattern endpoint `{expr:?}` outside of error recovery" | |
113 | ); | |
114 | return Err(self.tcx.sess.delay_span_bug(expr.span, msg)); | |
115 | }; | |
116 | Ok((Some(PatRangeBoundary::Finite(value)), ascr, inline_const)) | |
dfeec247 | 117 | } |
9fa01778 XL |
118 | } |
119 | } | |
120 | ||
ed00b5ec FG |
121 | /// Overflowing literals are linted against in a late pass. This is mostly fine, except when we |
122 | /// encounter a range pattern like `-130i8..2`: if we believe `eval_bits`, this looks like a | |
123 | /// range where the endpoints are in the wrong order. To avoid a confusing error message, we | |
124 | /// check for overflow then. | |
125 | /// This is only called when the range is already known to be malformed. | |
126 | fn error_on_literal_overflow( | |
127 | &self, | |
128 | expr: Option<&'tcx hir::Expr<'tcx>>, | |
129 | ty: Ty<'tcx>, | |
130 | ) -> Result<(), ErrorGuaranteed> { | |
131 | use hir::{ExprKind, UnOp}; | |
132 | use rustc_ast::ast::LitKind; | |
133 | ||
134 | let Some(mut expr) = expr else { | |
135 | return Ok(()); | |
136 | }; | |
137 | let span = expr.span; | |
138 | ||
139 | // We need to inspect the original expression, because if we only inspect the output of | |
140 | // `eval_bits`, an overflowed value has already been wrapped around. | |
141 | // We mostly copy the logic from the `rustc_lint::OVERFLOWING_LITERALS` lint. | |
142 | let mut negated = false; | |
143 | if let ExprKind::Unary(UnOp::Neg, sub_expr) = expr.kind { | |
144 | negated = true; | |
145 | expr = sub_expr; | |
146 | } | |
147 | let ExprKind::Lit(lit) = expr.kind else { | |
148 | return Ok(()); | |
149 | }; | |
150 | let LitKind::Int(lit_val, _) = lit.node else { | |
151 | return Ok(()); | |
152 | }; | |
153 | let (min, max): (i128, u128) = match ty.kind() { | |
154 | ty::Int(ity) => { | |
155 | let size = Integer::from_int_ty(&self.tcx, *ity).size(); | |
156 | (size.signed_int_min(), size.signed_int_max() as u128) | |
157 | } | |
158 | ty::Uint(uty) => { | |
159 | let size = Integer::from_uint_ty(&self.tcx, *uty).size(); | |
160 | (0, size.unsigned_int_max()) | |
161 | } | |
162 | _ => { | |
163 | return Ok(()); | |
164 | } | |
165 | }; | |
166 | // Detect literal value out of range `[min, max]` inclusive, avoiding use of `-min` to | |
167 | // prevent overflow/panic. | |
168 | if (negated && lit_val > max + 1) || (!negated && lit_val > max) { | |
169 | return Err(self.tcx.sess.emit_err(LiteralOutOfRange { span, ty, min, max })); | |
170 | } | |
171 | Ok(()) | |
172 | } | |
173 | ||
dfeec247 XL |
174 | fn lower_pattern_range( |
175 | &mut self, | |
ed00b5ec FG |
176 | lo_expr: Option<&'tcx hir::Expr<'tcx>>, |
177 | hi_expr: Option<&'tcx hir::Expr<'tcx>>, | |
dfeec247 | 178 | end: RangeEnd, |
ed00b5ec | 179 | ty: Ty<'tcx>, |
dfeec247 | 180 | span: Span, |
ed00b5ec FG |
181 | ) -> Result<PatKind<'tcx>, ErrorGuaranteed> { |
182 | if lo_expr.is_none() && hi_expr.is_none() { | |
183 | let msg = format!("found twice-open range pattern (`..`) outside of error recovery"); | |
184 | return Err(self.tcx.sess.delay_span_bug(span, msg)); | |
185 | } | |
186 | ||
187 | let (lo, lo_ascr, lo_inline) = self.lower_pattern_range_endpoint(lo_expr)?; | |
188 | let (hi, hi_ascr, hi_inline) = self.lower_pattern_range_endpoint(hi_expr)?; | |
189 | ||
190 | let lo = lo.unwrap_or(PatRangeBoundary::NegInfinity); | |
191 | let hi = hi.unwrap_or(PatRangeBoundary::PosInfinity); | |
192 | ||
193 | let cmp = lo.compare_with(hi, ty, self.tcx, self.param_env); | |
194 | let mut kind = PatKind::Range(Box::new(PatRange { lo, hi, end, ty })); | |
dfeec247 XL |
195 | match (end, cmp) { |
196 | // `x..y` where `x < y`. | |
ed00b5ec | 197 | (RangeEnd::Excluded, Some(Ordering::Less)) => {} |
dfeec247 | 198 | // `x..=y` where `x < y`. |
ed00b5ec FG |
199 | (RangeEnd::Included, Some(Ordering::Less)) => {} |
200 | // `x..=y` where `x == y` and `x` and `y` are finite. | |
201 | (RangeEnd::Included, Some(Ordering::Equal)) if lo.is_finite() && hi.is_finite() => { | |
202 | kind = PatKind::Constant { value: lo.as_finite().unwrap() }; | |
203 | } | |
204 | // `..=x` where `x == ty::MIN`. | |
205 | (RangeEnd::Included, Some(Ordering::Equal)) if !lo.is_finite() => {} | |
206 | // `x..` where `x == ty::MAX` (yes, `x..` gives `RangeEnd::Included` since it is meant | |
207 | // to include `ty::MAX`). | |
208 | (RangeEnd::Included, Some(Ordering::Equal)) if !hi.is_finite() => {} | |
209 | // `x..y` where `x >= y`, or `x..=y` where `x > y`. The range is empty => error. | |
210 | _ => { | |
211 | // Emit a more appropriate message if there was overflow. | |
212 | self.error_on_literal_overflow(lo_expr, ty)?; | |
213 | self.error_on_literal_overflow(hi_expr, ty)?; | |
214 | let e = match end { | |
215 | RangeEnd::Included => { | |
216 | self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper { | |
217 | span, | |
218 | teach: self.tcx.sess.teach(&error_code!(E0030)).then_some(()), | |
219 | }) | |
9c376795 | 220 | } |
ed00b5ec FG |
221 | RangeEnd::Excluded => { |
222 | self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanUpper { span }) | |
9c376795 | 223 | } |
ed00b5ec FG |
224 | }; |
225 | return Err(e); | |
dfeec247 XL |
226 | } |
227 | } | |
dfeec247 | 228 | |
ed00b5ec FG |
229 | // If we are handling a range with associated constants (e.g. |
230 | // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated | |
231 | // constants somewhere. Have them on the range pattern. | |
232 | for ascr in [lo_ascr, hi_ascr] { | |
233 | if let Some(ascription) = ascr { | |
234 | kind = PatKind::AscribeUserType { | |
235 | ascription, | |
236 | subpattern: Box::new(Pat { span, ty, kind }), | |
237 | }; | |
dfeec247 | 238 | } |
ed00b5ec FG |
239 | } |
240 | for inline_const in [lo_inline, hi_inline] { | |
241 | if let Some(def) = inline_const { | |
242 | kind = | |
243 | PatKind::InlineConstant { def, subpattern: Box::new(Pat { span, ty, kind }) }; | |
dfeec247 | 244 | } |
dfeec247 | 245 | } |
ed00b5ec | 246 | Ok(kind) |
dfeec247 XL |
247 | } |
248 | ||
2b03887a | 249 | #[instrument(skip(self), level = "debug")] |
f2b60f7d | 250 | fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> { |
3dfed10e | 251 | let mut ty = self.typeck_results.node_type(pat.hir_id); |
f2b60f7d | 252 | let mut span = pat.span; |
dfeec247 | 253 | |
e74abb32 XL |
254 | let kind = match pat.kind { |
255 | hir::PatKind::Wild => PatKind::Wild, | |
c30ab7b3 | 256 | |
5e7ed085 | 257 | hir::PatKind::Lit(value) => self.lower_lit(value), |
c30ab7b3 | 258 | |
e74abb32 | 259 | hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => { |
dfeec247 | 260 | let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref()); |
ed00b5ec FG |
261 | self.lower_pattern_range(lo_expr, hi_expr, end, ty, span) |
262 | .unwrap_or_else(PatKind::Error) | |
c30ab7b3 SL |
263 | } |
264 | ||
e74abb32 | 265 | hir::PatKind::Path(ref qpath) => { |
0531ce1d | 266 | return self.lower_path(qpath, pat.hir_id, pat.span); |
c30ab7b3 SL |
267 | } |
268 | ||
dfeec247 | 269 | hir::PatKind::Ref(ref subpattern, _) | hir::PatKind::Box(ref subpattern) => { |
e74abb32 | 270 | PatKind::Deref { subpattern: self.lower_pattern(subpattern) } |
c30ab7b3 SL |
271 | } |
272 | ||
e74abb32 | 273 | hir::PatKind::Slice(ref prefix, ref slice, ref suffix) => { |
dfeec247 | 274 | self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix) |
c30ab7b3 SL |
275 | } |
276 | ||
dfeec247 | 277 | hir::PatKind::Tuple(ref pats, ddpos) => { |
5e7ed085 FG |
278 | let ty::Tuple(ref tys) = ty.kind() else { |
279 | span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", ty); | |
dfeec247 XL |
280 | }; |
281 | let subpatterns = self.lower_tuple_subpats(pats, tys.len(), ddpos); | |
282 | PatKind::Leaf { subpatterns } | |
c30ab7b3 SL |
283 | } |
284 | ||
e74abb32 | 285 | hir::PatKind::Binding(_, id, ident, ref sub) => { |
f2b60f7d FG |
286 | if let Some(ident_span) = ident.span.find_ancestor_inside(span) { |
287 | span = span.with_hi(ident_span.hi()); | |
288 | } | |
289 | ||
3dfed10e XL |
290 | let bm = *self |
291 | .typeck_results | |
292 | .pat_binding_modes() | |
293 | .get(pat.hir_id) | |
294 | .expect("missing binding mode"); | |
c30ab7b3 | 295 | let (mutability, mode) = match bm { |
dfeec247 XL |
296 | ty::BindByValue(mutbl) => (mutbl, BindingMode::ByValue), |
297 | ty::BindByReference(hir::Mutability::Mut) => ( | |
298 | Mutability::Not, | |
fe692bf9 | 299 | BindingMode::ByRef(BorrowKind::Mut { kind: mir::MutBorrowKind::Default }), |
dfeec247 XL |
300 | ), |
301 | ty::BindByReference(hir::Mutability::Not) => { | |
302 | (Mutability::Not, BindingMode::ByRef(BorrowKind::Shared)) | |
303 | } | |
c30ab7b3 SL |
304 | }; |
305 | ||
306 | // A ref x pattern is the same node used for x, and as such it has | |
307 | // x's type, which is &T, where we want T (the type being matched). | |
dfeec247 | 308 | let var_ty = ty; |
3b2f2976 | 309 | if let ty::BindByReference(_) = bm { |
1b1a35ee | 310 | if let ty::Ref(_, rty, _) = ty.kind() { |
5099ac24 | 311 | ty = *rty; |
c30ab7b3 | 312 | } else { |
8faf50e0 | 313 | bug!("`ref {}` has wrong type {}", ident, ty); |
c30ab7b3 | 314 | } |
dfeec247 | 315 | }; |
c30ab7b3 | 316 | |
e74abb32 | 317 | PatKind::Binding { |
3b2f2976 XL |
318 | mutability, |
319 | mode, | |
8faf50e0 | 320 | name: ident.name, |
923072b8 | 321 | var: LocalVarId(id), |
c30ab7b3 SL |
322 | ty: var_ty, |
323 | subpattern: self.lower_opt_pattern(sub), | |
f9f354fc | 324 | is_primary: id == pat.hir_id, |
c30ab7b3 SL |
325 | } |
326 | } | |
327 | ||
dfeec247 | 328 | hir::PatKind::TupleStruct(ref qpath, ref pats, ddpos) => { |
3dfed10e | 329 | let res = self.typeck_results.qpath_res(qpath, pat.hir_id); |
5e7ed085 FG |
330 | let ty::Adt(adt_def, _) = ty.kind() else { |
331 | span_bug!(pat.span, "tuple struct pattern not applied to an ADT {:?}", ty); | |
c30ab7b3 | 332 | }; |
48663c56 | 333 | let variant_def = adt_def.variant_of_res(res); |
dfeec247 | 334 | let subpatterns = self.lower_tuple_subpats(pats, variant_def.fields.len(), ddpos); |
48663c56 | 335 | self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns) |
c30ab7b3 SL |
336 | } |
337 | ||
e74abb32 | 338 | hir::PatKind::Struct(ref qpath, ref fields, _) => { |
3dfed10e | 339 | let res = self.typeck_results.qpath_res(qpath, pat.hir_id); |
dfeec247 XL |
340 | let subpatterns = fields |
341 | .iter() | |
342 | .map(|field| FieldPat { | |
353b0b11 | 343 | field: self.typeck_results.field_index(field.hir_id), |
dfeec247 XL |
344 | pattern: self.lower_pattern(&field.pat), |
345 | }) | |
346 | .collect(); | |
c30ab7b3 | 347 | |
48663c56 | 348 | self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns) |
c30ab7b3 | 349 | } |
e1599b0c | 350 | |
dfeec247 | 351 | hir::PatKind::Or(ref pats) => PatKind::Or { pats: self.lower_patterns(pats) }, |
c30ab7b3 SL |
352 | }; |
353 | ||
f2b60f7d | 354 | Box::new(Pat { span, ty, kind }) |
c30ab7b3 SL |
355 | } |
356 | ||
dfeec247 XL |
357 | fn lower_tuple_subpats( |
358 | &mut self, | |
136023e0 | 359 | pats: &'tcx [hir::Pat<'tcx>], |
dfeec247 | 360 | expected_len: usize, |
f2b60f7d | 361 | gap_pos: hir::DotDotPos, |
dfeec247 XL |
362 | ) -> Vec<FieldPat<'tcx>> { |
363 | pats.iter() | |
364 | .enumerate_and_adjust(expected_len, gap_pos) | |
365 | .map(|(i, subpattern)| FieldPat { | |
353b0b11 | 366 | field: FieldIdx::new(i), |
dfeec247 XL |
367 | pattern: self.lower_pattern(subpattern), |
368 | }) | |
369 | .collect() | |
c30ab7b3 SL |
370 | } |
371 | ||
f2b60f7d | 372 | fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Box<[Box<Pat<'tcx>>]> { |
dfeec247 | 373 | pats.iter().map(|p| self.lower_pattern(p)).collect() |
c30ab7b3 SL |
374 | } |
375 | ||
f2b60f7d FG |
376 | fn lower_opt_pattern( |
377 | &mut self, | |
378 | pat: &'tcx Option<&'tcx hir::Pat<'tcx>>, | |
379 | ) -> Option<Box<Pat<'tcx>>> { | |
487cf647 | 380 | pat.map(|p| self.lower_pattern(p)) |
c30ab7b3 SL |
381 | } |
382 | ||
383 | fn slice_or_array_pattern( | |
384 | &mut self, | |
385 | span: Span, | |
386 | ty: Ty<'tcx>, | |
136023e0 | 387 | prefix: &'tcx [hir::Pat<'tcx>], |
dfeec247 | 388 | slice: &'tcx Option<&'tcx hir::Pat<'tcx>>, |
136023e0 | 389 | suffix: &'tcx [hir::Pat<'tcx>], |
dfeec247 | 390 | ) -> PatKind<'tcx> { |
c30ab7b3 SL |
391 | let prefix = self.lower_patterns(prefix); |
392 | let slice = self.lower_opt_pattern(slice); | |
393 | let suffix = self.lower_patterns(suffix); | |
1b1a35ee | 394 | match ty.kind() { |
dfeec247 XL |
395 | // Matching a slice, `[T]`. |
396 | ty::Slice(..) => PatKind::Slice { prefix, slice, suffix }, | |
397 | // Fixed-length array, `[T; len]`. | |
b7449926 | 398 | ty::Array(_, len) => { |
9ffffee4 | 399 | let len = len.eval_target_usize(self.tcx, self.param_env); |
ea8adc8c | 400 | assert!(len >= prefix.len() as u64 + suffix.len() as u64); |
dfeec247 | 401 | PatKind::Array { prefix, slice, suffix } |
c30ab7b3 | 402 | } |
dfeec247 | 403 | _ => span_bug!(span, "bad slice pattern type {:?}", ty), |
c30ab7b3 SL |
404 | } |
405 | } | |
406 | ||
407 | fn lower_variant_or_leaf( | |
408 | &mut self, | |
48663c56 | 409 | res: Res, |
0bf4aa26 | 410 | hir_id: hir::HirId, |
0531ce1d | 411 | span: Span, |
32a655c1 | 412 | ty: Ty<'tcx>, |
e74abb32 XL |
413 | subpatterns: Vec<FieldPat<'tcx>>, |
414 | ) -> PatKind<'tcx> { | |
48663c56 XL |
415 | let res = match res { |
416 | Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => { | |
04454e1e | 417 | let variant_id = self.tcx.parent(variant_ctor_id); |
48663c56 | 418 | Res::Def(DefKind::Variant, variant_id) |
dfeec247 | 419 | } |
48663c56 | 420 | res => res, |
532ac7d7 XL |
421 | }; |
422 | ||
48663c56 XL |
423 | let mut kind = match res { |
424 | Res::Def(DefKind::Variant, variant_id) => { | |
04454e1e | 425 | let enum_id = self.tcx.parent(variant_id); |
7cac9316 | 426 | let adt_def = self.tcx.adt_def(enum_id); |
ff7c6d11 | 427 | if adt_def.is_enum() { |
add651ee FG |
428 | let args = match ty.kind() { |
429 | ty::Adt(_, args) | ty::FnDef(_, args) => args, | |
ed00b5ec | 430 | ty::Error(e) => { |
dfeec247 | 431 | // Avoid ICE (#50585) |
ed00b5ec | 432 | return PatKind::Error(*e); |
8faf50e0 | 433 | } |
532ac7d7 | 434 | _ => bug!("inappropriate type for def: {:?}", ty), |
32a655c1 | 435 | }; |
e74abb32 | 436 | PatKind::Variant { |
3b2f2976 | 437 | adt_def, |
add651ee | 438 | args, |
c30ab7b3 | 439 | variant_index: adt_def.variant_index_with_id(variant_id), |
3b2f2976 | 440 | subpatterns, |
c30ab7b3 SL |
441 | } |
442 | } else { | |
e74abb32 | 443 | PatKind::Leaf { subpatterns } |
c30ab7b3 SL |
444 | } |
445 | } | |
446 | ||
ba9703b0 XL |
447 | Res::Def( |
448 | DefKind::Struct | |
449 | | DefKind::Ctor(CtorOf::Struct, ..) | |
450 | | DefKind::Union | |
781aab86 | 451 | | DefKind::TyAlias |
ba9703b0 XL |
452 | | DefKind::AssocTy, |
453 | _, | |
454 | ) | |
2b03887a FG |
455 | | Res::SelfTyParam { .. } |
456 | | Res::SelfTyAlias { .. } | |
dfeec247 | 457 | | Res::SelfCtor(..) => PatKind::Leaf { subpatterns }, |
0531ce1d | 458 | _ => { |
ed00b5ec | 459 | let e = match res { |
353b0b11 FG |
460 | Res::Def(DefKind::ConstParam, _) => { |
461 | self.tcx.sess.emit_err(ConstParamInPattern { span }) | |
462 | } | |
463 | Res::Def(DefKind::Static(_), _) => { | |
464 | self.tcx.sess.emit_err(StaticInPattern { span }) | |
465 | } | |
466 | _ => self.tcx.sess.emit_err(NonConstPath { span }), | |
ba9703b0 | 467 | }; |
ed00b5ec | 468 | PatKind::Error(e) |
0531ce1d | 469 | } |
0bf4aa26 XL |
470 | }; |
471 | ||
add651ee | 472 | if let Some(user_ty) = self.user_args_applied_to_ty_of_hir_id(hir_id) { |
0731742a | 473 | debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span); |
923072b8 | 474 | let annotation = CanonicalUserTypeAnnotation { |
f2b60f7d | 475 | user_ty: Box::new(user_ty), |
923072b8 FG |
476 | span, |
477 | inferred_ty: self.typeck_results.node_type(hir_id), | |
478 | }; | |
e74abb32 | 479 | kind = PatKind::AscribeUserType { |
f2b60f7d | 480 | subpattern: Box::new(Pat { span, ty, kind }), |
923072b8 | 481 | ascription: Ascription { annotation, variance: ty::Variance::Covariant }, |
0bf4aa26 | 482 | }; |
c30ab7b3 | 483 | } |
0bf4aa26 XL |
484 | |
485 | kind | |
c30ab7b3 | 486 | } |
32a655c1 | 487 | |
0531ce1d XL |
488 | /// Takes a HIR Path. If the path is a constant, evaluates it and feeds |
489 | /// it to `const_to_pat`. Any other path (like enum variants without fields) | |
9fa01778 | 490 | /// is converted to the corresponding pattern via `lower_variant_or_leaf`. |
923072b8 | 491 | #[instrument(skip(self), level = "debug")] |
f2b60f7d | 492 | fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Box<Pat<'tcx>> { |
3dfed10e XL |
493 | let ty = self.typeck_results.node_type(id); |
494 | let res = self.typeck_results.qpath_res(qpath, id); | |
f9f354fc | 495 | |
f2b60f7d | 496 | let pat_from_kind = |kind| Box::new(Pat { span, ty, kind }); |
f9f354fc XL |
497 | |
498 | let (def_id, is_associated_const) = match res { | |
499 | Res::Def(DefKind::Const, def_id) => (def_id, false), | |
500 | Res::Def(DefKind::AssocConst, def_id) => (def_id, true), | |
501 | ||
502 | _ => return pat_from_kind(self.lower_variant_or_leaf(res, id, span, ty, vec![])), | |
2c00a5a8 | 503 | }; |
dfeec247 | 504 | |
f9f354fc XL |
505 | // Use `Reveal::All` here because patterns are always monomorphic even if their function |
506 | // isn't. | |
3dfed10e | 507 | let param_env_reveal_all = self.param_env.with_reveal_all_normalized(self.tcx); |
add651ee | 508 | // N.B. There is no guarantee that args collected in typeck results are fully normalized, |
f2b60f7d FG |
509 | // so they need to be normalized in order to pass to `Instance::resolve`, which will ICE |
510 | // if given unnormalized types. | |
add651ee | 511 | let args = self |
f2b60f7d | 512 | .tcx |
add651ee FG |
513 | .normalize_erasing_regions(param_env_reveal_all, self.typeck_results.node_args(id)); |
514 | let instance = match ty::Instance::resolve(self.tcx, param_env_reveal_all, def_id, args) { | |
f9f354fc XL |
515 | Ok(Some(i)) => i, |
516 | Ok(None) => { | |
136023e0 XL |
517 | // It should be assoc consts if there's no error but we cannot resolve it. |
518 | debug_assert!(is_associated_const); | |
519 | ||
ed00b5ec FG |
520 | let e = self.tcx.sess.emit_err(AssocConstInPattern { span }); |
521 | return pat_from_kind(PatKind::Error(e)); | |
f9f354fc XL |
522 | } |
523 | ||
524 | Err(_) => { | |
ed00b5ec FG |
525 | let e = self.tcx.sess.emit_err(CouldNotEvalConstPattern { span }); |
526 | return pat_from_kind(PatKind::Error(e)); | |
32a655c1 | 527 | } |
32a655c1 SL |
528 | }; |
529 | ||
fe692bf9 FG |
530 | let cid = GlobalId { instance, promoted: None }; |
531 | // Prefer valtrees over opaque constants. | |
532 | let const_value = self | |
533 | .tcx | |
534 | .const_eval_global_id_for_typeck(param_env_reveal_all, cid, Some(span)) | |
535 | .map(|val| match val { | |
781aab86 FG |
536 | Some(valtree) => mir::Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)), |
537 | None => mir::Const::Val( | |
fe692bf9 FG |
538 | self.tcx |
539 | .const_eval_global_id(param_env_reveal_all, cid, Some(span)) | |
540 | .expect("const_eval_global_id_for_typeck should have already failed"), | |
541 | ty, | |
542 | ), | |
543 | }); | |
544 | ||
545 | match const_value { | |
546 | Ok(const_) => { | |
547 | let pattern = self.const_to_pat(const_, id, span, Some(instance.def_id())); | |
f9f354fc XL |
548 | |
549 | if !is_associated_const { | |
550 | return pattern; | |
551 | } | |
552 | ||
3dfed10e | 553 | let user_provided_types = self.typeck_results().user_provided_types(); |
923072b8 FG |
554 | if let Some(&user_ty) = user_provided_types.get(id) { |
555 | let annotation = CanonicalUserTypeAnnotation { | |
f2b60f7d | 556 | user_ty: Box::new(user_ty), |
923072b8 FG |
557 | span, |
558 | inferred_ty: self.typeck_results().node_type(id), | |
559 | }; | |
f2b60f7d | 560 | Box::new(Pat { |
f9f354fc | 561 | span, |
f2b60f7d | 562 | kind: PatKind::AscribeUserType { |
f9f354fc XL |
563 | subpattern: pattern, |
564 | ascription: Ascription { | |
923072b8 | 565 | annotation, |
781aab86 FG |
566 | // Note that use `Contravariant` here. See the |
567 | // `variance` field documentation for details. | |
f9f354fc | 568 | variance: ty::Variance::Contravariant, |
f9f354fc | 569 | }, |
f2b60f7d | 570 | }, |
5099ac24 | 571 | ty: const_.ty(), |
f2b60f7d | 572 | }) |
f9f354fc XL |
573 | } else { |
574 | pattern | |
575 | } | |
576 | } | |
781aab86 | 577 | Err(ErrorHandled::TooGeneric(_)) => { |
3dfed10e XL |
578 | // While `Reported | Linted` cases will have diagnostics emitted already |
579 | // it is not true for TooGeneric case, so we need to give user more information. | |
ed00b5ec FG |
580 | let e = self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span }); |
581 | pat_from_kind(PatKind::Error(e)) | |
3dfed10e | 582 | } |
f9f354fc | 583 | Err(_) => { |
ed00b5ec FG |
584 | let e = self.tcx.sess.emit_err(CouldNotEvalConstPattern { span }); |
585 | pat_from_kind(PatKind::Error(e)) | |
f9f354fc XL |
586 | } |
587 | } | |
32a655c1 SL |
588 | } |
589 | ||
a2a8927a XL |
590 | /// Converts inline const patterns. |
591 | fn lower_inline_const( | |
592 | &mut self, | |
fe692bf9 | 593 | block: &'tcx hir::ConstBlock, |
a2a8927a XL |
594 | id: hir::HirId, |
595 | span: Span, | |
596 | ) -> PatKind<'tcx> { | |
fe692bf9 FG |
597 | let tcx = self.tcx; |
598 | let def_id = block.def_id; | |
599 | let body_id = block.body; | |
600 | let expr = &tcx.hir().body(body_id).value; | |
601 | let ty = tcx.typeck(def_id).node_type(block.hir_id); | |
602 | ||
603 | // Special case inline consts that are just literals. This is solely | |
604 | // a performance optimization, as we could also just go through the regular | |
605 | // const eval path below. | |
606 | // FIXME: investigate the performance impact of removing this. | |
607 | let lit_input = match expr.kind { | |
ed00b5ec FG |
608 | hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), |
609 | hir::ExprKind::Unary(hir::UnOp::Neg, expr) => match expr.kind { | |
610 | hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: true }), | |
fe692bf9 | 611 | _ => None, |
f2b60f7d | 612 | }, |
fe692bf9 FG |
613 | _ => None, |
614 | }; | |
615 | if let Some(lit_input) = lit_input { | |
616 | match tcx.at(expr.span).lit_to_const(lit_input) { | |
781aab86 | 617 | Ok(c) => return self.const_to_pat(Const::Ty(c), id, span, None).kind, |
fe692bf9 FG |
618 | // If an error occurred, ignore that it's a literal |
619 | // and leave reporting the error up to const eval of | |
620 | // the unevaluated constant below. | |
621 | Err(_) => {} | |
622 | } | |
623 | } | |
624 | ||
625 | let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()); | |
add651ee FG |
626 | let parent_args = |
627 | tcx.erase_regions(ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id)); | |
628 | let args = ty::InlineConstArgs::new(tcx, ty::InlineConstArgsParts { parent_args, ty }).args; | |
fe692bf9 | 629 | |
add651ee FG |
630 | let uneval = mir::UnevaluatedConst { def: def_id.to_def_id(), args, promoted: None }; |
631 | debug_assert!(!args.has_free_regions()); | |
fe692bf9 | 632 | |
ed00b5ec | 633 | let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args }; |
fe692bf9 | 634 | // First try using a valtree in order to destructure the constant into a pattern. |
781aab86 FG |
635 | // FIXME: replace "try to do a thing, then fall back to another thing" |
636 | // but something more principled, like a trait query checking whether this can be turned into a valtree. | |
fe692bf9 FG |
637 | if let Ok(Some(valtree)) = |
638 | self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span)) | |
639 | { | |
ed00b5ec | 640 | let subpattern = self.const_to_pat( |
781aab86 | 641 | Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)), |
fe692bf9 FG |
642 | id, |
643 | span, | |
644 | None, | |
ed00b5ec FG |
645 | ); |
646 | PatKind::InlineConstant { subpattern, def: def_id } | |
fe692bf9 FG |
647 | } else { |
648 | // If that fails, convert it to an opaque constant pattern. | |
781aab86 FG |
649 | match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) { |
650 | Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span, None).kind, | |
651 | Err(ErrorHandled::TooGeneric(_)) => { | |
fe692bf9 | 652 | // If we land here it means the const can't be evaluated because it's `TooGeneric`. |
ed00b5ec FG |
653 | let e = self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span }); |
654 | PatKind::Error(e) | |
fe692bf9 | 655 | } |
ed00b5ec | 656 | Err(ErrorHandled::Reported(err, ..)) => PatKind::Error(err.into()), |
a2a8927a | 657 | } |
a2a8927a | 658 | } |
a2a8927a XL |
659 | } |
660 | ||
0531ce1d | 661 | /// Converts literals, paths and negation of literals to patterns. |
9fa01778 XL |
662 | /// The special case for negation exists to allow things like `-128_i8` |
663 | /// which would overflow if we tried to evaluate `128_i8` and then negate | |
0531ce1d | 664 | /// afterwards. |
dfeec247 | 665 | fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> { |
a2a8927a XL |
666 | let (lit, neg) = match expr.kind { |
667 | hir::ExprKind::Path(ref qpath) => { | |
f2b60f7d | 668 | return self.lower_path(qpath, expr.hir_id, expr.span).kind; |
32a655c1 | 669 | } |
a2a8927a XL |
670 | hir::ExprKind::ConstBlock(ref anon_const) => { |
671 | return self.lower_inline_const(anon_const, expr.hir_id, expr.span); | |
672 | } | |
673 | hir::ExprKind::Lit(ref lit) => (lit, false), | |
674 | hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => { | |
5e7ed085 FG |
675 | let hir::ExprKind::Lit(ref lit) = expr.kind else { |
676 | span_bug!(expr.span, "not a literal: {:?}", expr); | |
a2a8927a XL |
677 | }; |
678 | (lit, true) | |
679 | } | |
680 | _ => span_bug!(expr.span, "not a literal: {:?}", expr), | |
681 | }; | |
682 | ||
683 | let lit_input = | |
684 | LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg }; | |
fe692bf9 FG |
685 | match self.tcx.at(expr.span).lit_to_const(lit_input) { |
686 | Ok(constant) => { | |
781aab86 | 687 | self.const_to_pat(Const::Ty(constant), expr.hir_id, lit.span, None).kind |
fe692bf9 | 688 | } |
ed00b5ec | 689 | Err(LitToConstError::Reported(e)) => PatKind::Error(e), |
a2a8927a | 690 | Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"), |
32a655c1 SL |
691 | } |
692 | } | |
416331ca XL |
693 | } |
694 | ||
dfeec247 | 695 | impl<'tcx> UserAnnotatedTyHelpers<'tcx> for PatCtxt<'_, 'tcx> { |
dc9dc135 | 696 | fn tcx(&self) -> TyCtxt<'tcx> { |
0bf4aa26 XL |
697 | self.tcx |
698 | } | |
699 | ||
3dfed10e XL |
700 | fn typeck_results(&self) -> &ty::TypeckResults<'tcx> { |
701 | self.typeck_results | |
0bf4aa26 XL |
702 | } |
703 | } | |
704 | ||
f2b60f7d | 705 | trait PatternFoldable<'tcx>: Sized { |
c30ab7b3 SL |
706 | fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self { |
707 | self.super_fold_with(folder) | |
708 | } | |
709 | ||
710 | fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self; | |
711 | } | |
712 | ||
f2b60f7d | 713 | trait PatternFolder<'tcx>: Sized { |
e74abb32 | 714 | fn fold_pattern(&mut self, pattern: &Pat<'tcx>) -> Pat<'tcx> { |
c30ab7b3 SL |
715 | pattern.super_fold_with(self) |
716 | } | |
717 | ||
e74abb32 | 718 | fn fold_pattern_kind(&mut self, kind: &PatKind<'tcx>) -> PatKind<'tcx> { |
c30ab7b3 SL |
719 | kind.super_fold_with(self) |
720 | } | |
721 | } | |
722 | ||
c30ab7b3 SL |
723 | impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box<T> { |
724 | fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self { | |
725 | let content: T = (**self).fold_with(folder); | |
94222f64 | 726 | Box::new(content) |
c30ab7b3 SL |
727 | } |
728 | } | |
729 | ||
730 | impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Vec<T> { | |
731 | fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self { | |
732 | self.iter().map(|t| t.fold_with(folder)).collect() | |
733 | } | |
734 | } | |
735 | ||
f2b60f7d FG |
736 | impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box<[T]> { |
737 | fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self { | |
738 | self.iter().map(|t| t.fold_with(folder)).collect() | |
739 | } | |
740 | } | |
741 | ||
c30ab7b3 | 742 | impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option<T> { |
dfeec247 | 743 | fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self { |
c30ab7b3 SL |
744 | self.as_ref().map(|t| t.fold_with(folder)) |
745 | } | |
746 | } | |
747 | ||
923072b8 | 748 | macro_rules! ClonePatternFoldableImpls { |
476ff2be | 749 | (<$lt_tcx:tt> $($ty:ty),+) => { |
c30ab7b3 | 750 | $( |
476ff2be SL |
751 | impl<$lt_tcx> PatternFoldable<$lt_tcx> for $ty { |
752 | fn super_fold_with<F: PatternFolder<$lt_tcx>>(&self, _: &mut F) -> Self { | |
753 | Clone::clone(self) | |
c30ab7b3 SL |
754 | } |
755 | } | |
756 | )+ | |
757 | } | |
758 | } | |
759 | ||
923072b8 | 760 | ClonePatternFoldableImpls! { <'tcx> |
353b0b11 | 761 | Span, FieldIdx, Mutability, Symbol, LocalVarId, usize, |
5e7ed085 | 762 | Region<'tcx>, Ty<'tcx>, BindingMode, AdtDef<'tcx>, |
add651ee | 763 | GenericArgsRef<'tcx>, &'tcx GenericArg<'tcx>, UserType<'tcx>, |
923072b8 | 764 | UserTypeProjection, CanonicalUserTypeAnnotation<'tcx> |
476ff2be | 765 | } |
c30ab7b3 | 766 | |
e74abb32 | 767 | impl<'tcx> PatternFoldable<'tcx> for FieldPat<'tcx> { |
c30ab7b3 | 768 | fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self { |
dfeec247 | 769 | FieldPat { field: self.field.fold_with(folder), pattern: self.pattern.fold_with(folder) } |
c30ab7b3 SL |
770 | } |
771 | } | |
772 | ||
e74abb32 | 773 | impl<'tcx> PatternFoldable<'tcx> for Pat<'tcx> { |
c30ab7b3 SL |
774 | fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self { |
775 | folder.fold_pattern(self) | |
776 | } | |
777 | ||
778 | fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self { | |
e74abb32 | 779 | Pat { |
c30ab7b3 SL |
780 | ty: self.ty.fold_with(folder), |
781 | span: self.span.fold_with(folder), | |
dfeec247 | 782 | kind: self.kind.fold_with(folder), |
c30ab7b3 SL |
783 | } |
784 | } | |
785 | } | |
786 | ||
e74abb32 | 787 | impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> { |
c30ab7b3 SL |
788 | fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self { |
789 | folder.fold_pattern_kind(self) | |
790 | } | |
791 | ||
792 | fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self { | |
793 | match *self { | |
e74abb32 | 794 | PatKind::Wild => PatKind::Wild, |
ed00b5ec | 795 | PatKind::Error(e) => PatKind::Error(e), |
e74abb32 | 796 | PatKind::AscribeUserType { |
b7449926 | 797 | ref subpattern, |
923072b8 | 798 | ascription: Ascription { ref annotation, variance }, |
e74abb32 | 799 | } => PatKind::AscribeUserType { |
b7449926 | 800 | subpattern: subpattern.fold_with(folder), |
923072b8 | 801 | ascription: Ascription { annotation: annotation.fold_with(folder), variance }, |
b7449926 | 802 | }, |
f9f354fc | 803 | PatKind::Binding { mutability, name, mode, var, ty, ref subpattern, is_primary } => { |
dfeec247 XL |
804 | PatKind::Binding { |
805 | mutability: mutability.fold_with(folder), | |
806 | name: name.fold_with(folder), | |
807 | mode: mode.fold_with(folder), | |
808 | var: var.fold_with(folder), | |
809 | ty: ty.fold_with(folder), | |
810 | subpattern: subpattern.fold_with(folder), | |
f9f354fc | 811 | is_primary, |
dfeec247 XL |
812 | } |
813 | } | |
add651ee | 814 | PatKind::Variant { adt_def, args, variant_index, ref subpatterns } => { |
dfeec247 XL |
815 | PatKind::Variant { |
816 | adt_def: adt_def.fold_with(folder), | |
add651ee | 817 | args: args.fold_with(folder), |
dfeec247 XL |
818 | variant_index, |
819 | subpatterns: subpatterns.fold_with(folder), | |
820 | } | |
821 | } | |
822 | PatKind::Leaf { ref subpatterns } => { | |
823 | PatKind::Leaf { subpatterns: subpatterns.fold_with(folder) } | |
824 | } | |
825 | PatKind::Deref { ref subpattern } => { | |
826 | PatKind::Deref { subpattern: subpattern.fold_with(folder) } | |
827 | } | |
828 | PatKind::Constant { value } => PatKind::Constant { value }, | |
ed00b5ec FG |
829 | PatKind::InlineConstant { def, subpattern: ref pattern } => { |
830 | PatKind::InlineConstant { def, subpattern: pattern.fold_with(folder) } | |
831 | } | |
f2b60f7d | 832 | PatKind::Range(ref range) => PatKind::Range(range.clone()), |
dfeec247 | 833 | PatKind::Slice { ref prefix, ref slice, ref suffix } => PatKind::Slice { |
c30ab7b3 SL |
834 | prefix: prefix.fold_with(folder), |
835 | slice: slice.fold_with(folder), | |
dfeec247 | 836 | suffix: suffix.fold_with(folder), |
c30ab7b3 | 837 | }, |
dfeec247 | 838 | PatKind::Array { ref prefix, ref slice, ref suffix } => PatKind::Array { |
c30ab7b3 SL |
839 | prefix: prefix.fold_with(folder), |
840 | slice: slice.fold_with(folder), | |
dfeec247 | 841 | suffix: suffix.fold_with(folder), |
c30ab7b3 | 842 | }, |
e74abb32 | 843 | PatKind::Or { ref pats } => PatKind::Or { pats: pats.fold_with(folder) }, |
c30ab7b3 SL |
844 | } |
845 | } | |
846 | } |