aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty/src/diagnostics/pattern/deconstruct_pat.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_ty/src/diagnostics/pattern/deconstruct_pat.rs')
-rw-r--r--crates/hir_ty/src/diagnostics/pattern/deconstruct_pat.rs627
1 files changed, 627 insertions, 0 deletions
diff --git a/crates/hir_ty/src/diagnostics/pattern/deconstruct_pat.rs b/crates/hir_ty/src/diagnostics/pattern/deconstruct_pat.rs
new file mode 100644
index 000000000..cde04409e
--- /dev/null
+++ b/crates/hir_ty/src/diagnostics/pattern/deconstruct_pat.rs
@@ -0,0 +1,627 @@
1use hir_def::{
2 expr::{Pat, PatId},
3 AttrDefId, EnumVariantId, HasModule, VariantId,
4};
5
6use smallvec::{smallvec, SmallVec};
7
8use crate::{AdtId, Interner, Scalar, Ty, TyExt, TyKind};
9
10use super::usefulness::{MatchCheckCtx, PatCtxt};
11
12use self::Constructor::*;
13
14#[derive(Copy, Clone, Debug, PartialEq, Eq)]
15pub(super) enum ToDo {}
16
17#[derive(Clone, Debug, PartialEq, Eq)]
18pub(super) struct IntRange {
19 range: ToDo,
20}
21
22impl IntRange {
23 #[inline]
24 fn is_integral(ty: &Ty) -> bool {
25 match ty.kind(&Interner) {
26 TyKind::Scalar(Scalar::Char)
27 | TyKind::Scalar(Scalar::Int(_))
28 | TyKind::Scalar(Scalar::Uint(_))
29 | TyKind::Scalar(Scalar::Bool) => true,
30 _ => false,
31 }
32 }
33
34 /// See `Constructor::is_covered_by`
35 fn is_covered_by(&self, other: &Self) -> bool {
36 todo!()
37 }
38}
39
40/// A constructor for array and slice patterns.
41#[derive(Copy, Clone, Debug, PartialEq, Eq)]
42pub(super) struct Slice {
43 todo: ToDo,
44}
45
46impl Slice {
47 /// See `Constructor::is_covered_by`
48 fn is_covered_by(self, other: Self) -> bool {
49 todo!()
50 }
51}
52
53/// A value can be decomposed into a constructor applied to some fields. This struct represents
54/// the constructor. See also `Fields`.
55///
56/// `pat_constructor` retrieves the constructor corresponding to a pattern.
57/// `specialize_constructor` returns the list of fields corresponding to a pattern, given a
58/// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and
59/// `Fields`.
60#[derive(Clone, Debug, PartialEq)]
61pub(super) enum Constructor {
62 /// The constructor for patterns that have a single constructor, like tuples, struct patterns
63 /// and fixed-length arrays.
64 Single,
65 /// Enum variants.
66 Variant(EnumVariantId),
67 /// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
68 IntRange(IntRange),
69 /// Array and slice patterns.
70 Slice(Slice),
71 /// Stands for constructors that are not seen in the matrix, as explained in the documentation
72 /// for [`SplitWildcard`].
73 Missing,
74 /// Wildcard pattern.
75 Wildcard,
76}
77
78impl Constructor {
79 pub(super) fn is_wildcard(&self) -> bool {
80 matches!(self, Wildcard)
81 }
82
83 fn as_int_range(&self) -> Option<&IntRange> {
84 match self {
85 IntRange(range) => Some(range),
86 _ => None,
87 }
88 }
89
90 fn as_slice(&self) -> Option<Slice> {
91 match self {
92 Slice(slice) => Some(*slice),
93 _ => None,
94 }
95 }
96
97 fn variant_id_for_adt(&self, adt: hir_def::AdtId, cx: &MatchCheckCtx<'_>) -> VariantId {
98 match *self {
99 Variant(id) => id.into(),
100 Single => {
101 assert!(!matches!(adt, hir_def::AdtId::EnumId(_)));
102 match adt {
103 hir_def::AdtId::EnumId(_) => unreachable!(),
104 hir_def::AdtId::StructId(id) => id.into(),
105 hir_def::AdtId::UnionId(id) => id.into(),
106 }
107 }
108 _ => panic!("bad constructor {:?} for adt {:?}", self, adt),
109 }
110 }
111
112 pub(super) fn from_pat(cx: &MatchCheckCtx<'_>, pat: PatId) -> Self {
113 match &cx.pattern_arena.borrow()[pat] {
114 Pat::Bind { .. } | Pat::Wild => Wildcard,
115 Pat::Tuple { .. } | Pat::Ref { .. } | Pat::Box { .. } => Single,
116
117 pat => todo!("Constructor::from_pat {:?}", pat),
118 // Pat::Missing => {}
119 // Pat::Or(_) => {}
120 // Pat::Record { path, args, ellipsis } => {}
121 // Pat::Range { start, end } => {}
122 // Pat::Slice { prefix, slice, suffix } => {}
123 // Pat::Path(_) => {}
124 // Pat::Lit(_) => {}
125 // Pat::TupleStruct { path, args, ellipsis } => {}
126 // Pat::ConstBlock(_) => {}
127 }
128 }
129
130 /// Some constructors (namely `Wildcard`, `IntRange` and `Slice`) actually stand for a set of actual
131 /// constructors (like variants, integers or fixed-sized slices). When specializing for these
132 /// constructors, we want to be specialising for the actual underlying constructors.
133 /// Naively, we would simply return the list of constructors they correspond to. We instead are
134 /// more clever: if there are constructors that we know will behave the same wrt the current
135 /// matrix, we keep them grouped. For example, all slices of a sufficiently large length
136 /// will either be all useful or all non-useful with a given matrix.
137 ///
138 /// See the branches for details on how the splitting is done.
139 ///
140 /// This function may discard some irrelevant constructors if this preserves behavior and
141 /// diagnostics. Eg. for the `_` case, we ignore the constructors already present in the
142 /// matrix, unless all of them are.
143 pub(super) fn split<'a>(
144 &self,
145 pcx: &PatCtxt<'_>,
146 ctors: impl Iterator<Item = &'a Constructor> + Clone,
147 ) -> SmallVec<[Self; 1]> {
148 match self {
149 Wildcard => {
150 let mut split_wildcard = SplitWildcard::new(pcx);
151 split_wildcard.split(pcx, ctors);
152 split_wildcard.into_ctors(pcx)
153 }
154 // Fast-track if the range is trivial. In particular, we don't do the overlapping
155 // ranges check.
156 IntRange(_) => todo!("Constructor::split IntRange"),
157 Slice(_) => todo!("Constructor::split Slice"),
158 // Any other constructor can be used unchanged.
159 _ => smallvec![self.clone()],
160 }
161 }
162
163 /// Returns whether `self` is covered by `other`, i.e. whether `self` is a subset of `other`.
164 /// For the simple cases, this is simply checking for equality. For the "grouped" constructors,
165 /// this checks for inclusion.
166 // We inline because this has a single call site in `Matrix::specialize_constructor`.
167 #[inline]
168 pub(super) fn is_covered_by(&self, pcx: &PatCtxt<'_>, other: &Self) -> bool {
169 // This must be kept in sync with `is_covered_by_any`.
170 match (self, other) {
171 // Wildcards cover anything
172 (_, Wildcard) => true,
173 // The missing ctors are not covered by anything in the matrix except wildcards.
174 (Missing, _) | (Wildcard, _) => false,
175
176 (Single, Single) => true,
177 (Variant(self_id), Variant(other_id)) => self_id == other_id,
178
179 (Constructor::IntRange(_), Constructor::IntRange(_)) => todo!(),
180
181 (Constructor::Slice(_), Constructor::Slice(_)) => todo!(),
182
183 _ => panic!("bug"),
184 }
185 }
186
187 /// Faster version of `is_covered_by` when applied to many constructors. `used_ctors` is
188 /// assumed to be built from `matrix.head_ctors()` with wildcards filtered out, and `self` is
189 /// assumed to have been split from a wildcard.
190 fn is_covered_by_any(&self, pcx: &PatCtxt<'_>, used_ctors: &[Constructor]) -> bool {
191 if used_ctors.is_empty() {
192 return false;
193 }
194
195 // This must be kept in sync with `is_covered_by`.
196 match self {
197 // If `self` is `Single`, `used_ctors` cannot contain anything else than `Single`s.
198 Single => !used_ctors.is_empty(),
199 Variant(_) => used_ctors.iter().any(|c| c == self),
200 IntRange(range) => used_ctors
201 .iter()
202 .filter_map(|c| c.as_int_range())
203 .any(|other| range.is_covered_by(other)),
204 Slice(slice) => used_ctors
205 .iter()
206 .filter_map(|c| c.as_slice())
207 .any(|other| slice.is_covered_by(other)),
208
209 _ => todo!(),
210 }
211 }
212}
213
214/// A wildcard constructor that we split relative to the constructors in the matrix, as explained
215/// at the top of the file.
216///
217/// A constructor that is not present in the matrix rows will only be covered by the rows that have
218/// wildcards. Thus we can group all of those constructors together; we call them "missing
219/// constructors". Splitting a wildcard would therefore list all present constructors individually
220/// (or grouped if they are integers or slices), and then all missing constructors together as a
221/// group.
222///
223/// However we can go further: since any constructor will match the wildcard rows, and having more
224/// rows can only reduce the amount of usefulness witnesses, we can skip the present constructors
225/// and only try the missing ones.
226/// This will not preserve the whole list of witnesses, but will preserve whether the list is empty
227/// or not. In fact this is quite natural from the point of view of diagnostics too. This is done
228/// in `to_ctors`: in some cases we only return `Missing`.
229#[derive(Debug)]
230pub(super) struct SplitWildcard {
231 /// Constructors seen in the matrix.
232 matrix_ctors: Vec<Constructor>,
233 /// All the constructors for this type
234 all_ctors: SmallVec<[Constructor; 1]>,
235}
236
237impl SplitWildcard {
238 pub(super) fn new(pcx: &PatCtxt<'_>) -> Self {
239 // let cx = pcx.cx;
240 // let make_range = |start, end| IntRange(todo!());
241
242 // This determines the set of all possible constructors for the type `pcx.ty`. For numbers,
243 // arrays and slices we use ranges and variable-length slices when appropriate.
244 //
245 // If the `exhaustive_patterns` feature is enabled, we make sure to omit constructors that
246 // are statically impossible. E.g., for `Option<!>`, we do not include `Some(_)` in the
247 // returned list of constructors.
248 // Invariant: this is empty if and only if the type is uninhabited (as determined by
249 // `cx.is_uninhabited()`).
250 let all_ctors = match pcx.ty.kind(&Interner) {
251 TyKind::Adt(AdtId(hir_def::AdtId::EnumId(_)), _) => todo!(),
252 TyKind::Adt(..) | TyKind::Tuple(..) | TyKind::Ref(..) => smallvec![Single],
253 _ => todo!(),
254 };
255 SplitWildcard { matrix_ctors: Vec::new(), all_ctors }
256 }
257
258 /// Pass a set of constructors relative to which to split this one. Don't call twice, it won't
259 /// do what you want.
260 pub(super) fn split<'a>(
261 &mut self,
262 pcx: &PatCtxt<'_>,
263 ctors: impl Iterator<Item = &'a Constructor> + Clone,
264 ) {
265 // Since `all_ctors` never contains wildcards, this won't recurse further.
266 self.all_ctors =
267 self.all_ctors.iter().flat_map(|ctor| ctor.split(pcx, ctors.clone())).collect();
268 self.matrix_ctors = ctors.filter(|c| !c.is_wildcard()).cloned().collect();
269 }
270
271 /// Whether there are any value constructors for this type that are not present in the matrix.
272 fn any_missing(&self, pcx: &PatCtxt<'_>) -> bool {
273 self.iter_missing(pcx).next().is_some()
274 }
275
276 /// Iterate over the constructors for this type that are not present in the matrix.
277 pub(super) fn iter_missing<'a>(
278 &'a self,
279 pcx: &'a PatCtxt<'_>,
280 ) -> impl Iterator<Item = &'a Constructor> {
281 self.all_ctors.iter().filter(move |ctor| !ctor.is_covered_by_any(pcx, &self.matrix_ctors))
282 }
283
284 /// Return the set of constructors resulting from splitting the wildcard. As explained at the
285 /// top of the file, if any constructors are missing we can ignore the present ones.
286 fn into_ctors(self, pcx: &PatCtxt<'_>) -> SmallVec<[Constructor; 1]> {
287 if self.any_missing(pcx) {
288 // Some constructors are missing, thus we can specialize with the special `Missing`
289 // constructor, which stands for those constructors that are not seen in the matrix,
290 // and matches the same rows as any of them (namely the wildcard rows). See the top of
291 // the file for details.
292 // However, when all constructors are missing we can also specialize with the full
293 // `Wildcard` constructor. The difference will depend on what we want in diagnostics.
294
295 // If some constructors are missing, we typically want to report those constructors,
296 // e.g.:
297 // ```
298 // enum Direction { N, S, E, W }
299 // let Direction::N = ...;
300 // ```
301 // we can report 3 witnesses: `S`, `E`, and `W`.
302 //
303 // However, if the user didn't actually specify a constructor
304 // in this arm, e.g., in
305 // ```
306 // let x: (Direction, Direction, bool) = ...;
307 // let (_, _, false) = x;
308 // ```
309 // we don't want to show all 16 possible witnesses `(<direction-1>, <direction-2>,
310 // true)` - we are satisfied with `(_, _, true)`. So if all constructors are missing we
311 // prefer to report just a wildcard `_`.
312 //
313 // The exception is: if we are at the top-level, for example in an empty match, we
314 // sometimes prefer reporting the list of constructors instead of just `_`.
315
316 let report_when_all_missing = pcx.is_top_level && !IntRange::is_integral(&pcx.ty);
317 let ctor = if !self.matrix_ctors.is_empty() || report_when_all_missing {
318 Missing
319 } else {
320 Wildcard
321 };
322 return smallvec![ctor];
323 }
324
325 // All the constructors are present in the matrix, so we just go through them all.
326 self.all_ctors
327 }
328}
329
330#[test]
331fn it_works2() {}
332
333/// Some fields need to be explicitly hidden away in certain cases; see the comment above the
334/// `Fields` struct. This struct represents such a potentially-hidden field.
335#[derive(Debug, Copy, Clone)]
336pub(super) enum FilteredField {
337 Kept(PatId),
338 Hidden,
339}
340
341impl FilteredField {
342 fn kept(self) -> Option<PatId> {
343 match self {
344 FilteredField::Kept(p) => Some(p),
345 FilteredField::Hidden => None,
346 }
347 }
348}
349
350/// A value can be decomposed into a constructor applied to some fields. This struct represents
351/// those fields, generalized to allow patterns in each field. See also `Constructor`.
352/// This is constructed from a constructor using [`Fields::wildcards()`].
353///
354/// If a private or `non_exhaustive` field is uninhabited, the code mustn't observe that it is
355/// uninhabited. For that, we filter these fields out of the matrix. This is handled automatically
356/// in `Fields`. This filtering is uncommon in practice, because uninhabited fields are rarely used,
357/// so we avoid it when possible to preserve performance.
358#[derive(Debug, Clone)]
359pub(super) enum Fields {
360 /// Lists of patterns that don't contain any filtered fields.
361 /// `Slice` and `Vec` behave the same; the difference is only to avoid allocating and
362 /// triple-dereferences when possible. Frankly this is premature optimization, I (Nadrieril)
363 /// have not measured if it really made a difference.
364 Vec(SmallVec<[PatId; 2]>),
365}
366
367impl Fields {
368 /// Internal use. Use `Fields::wildcards()` instead.
369 /// Must not be used if the pattern is a field of a struct/tuple/variant.
370 fn from_single_pattern(pat: PatId) -> Self {
371 Fields::Vec(smallvec![pat])
372 }
373
374 /// Convenience; internal use.
375 fn wildcards_from_tys<'a>(
376 cx: &MatchCheckCtx<'_>,
377 tys: impl IntoIterator<Item = &'a Ty>,
378 ) -> Self {
379 let wilds = tys.into_iter().map(|ty| (Pat::Wild, ty));
380 let pats = wilds.map(|(pat, ty)| cx.alloc_pat(pat, ty)).collect();
381 Fields::Vec(pats)
382 }
383
384 pub(crate) fn wildcards(pcx: &PatCtxt<'_>, constructor: &Constructor) -> Self {
385 let ty = &pcx.ty;
386 let cx = pcx.cx;
387 let wildcard_from_ty = |ty| cx.alloc_pat(Pat::Wild, ty);
388
389 let ret = match constructor {
390 Single | Variant(_) => match ty.kind(&Interner) {
391 TyKind::Tuple(_, substs) => {
392 let tys = substs.iter(&Interner).map(|ty| ty.assert_ty_ref(&Interner));
393 Fields::wildcards_from_tys(cx, tys)
394 }
395 TyKind::Ref(.., rty) => Fields::from_single_pattern(wildcard_from_ty(rty)),
396 TyKind::Adt(AdtId(adt), substs) => {
397 let adt_is_box = false; // TODO(iDawer): handle box patterns
398 if adt_is_box {
399 // Use T as the sub pattern type of Box<T>.
400 let ty = substs.at(&Interner, 0).assert_ty_ref(&Interner);
401 Fields::from_single_pattern(wildcard_from_ty(ty))
402 } else {
403 let variant_id = constructor.variant_id_for_adt(*adt, cx);
404 let variant = variant_id.variant_data(cx.db.upcast());
405 let adt_is_local = variant_id.module(cx.db.upcast()).krate() == cx.krate;
406 // Whether we must not match the fields of this variant exhaustively.
407 let is_non_exhaustive =
408 is_field_list_non_exhaustive(variant_id, cx) && !adt_is_local;
409 let field_ty_arena = cx.db.field_types(variant_id);
410 let field_tys =
411 || field_ty_arena.iter().map(|(_, binders)| binders.skip_binders());
412 // In the following cases, we don't need to filter out any fields. This is
413 // the vast majority of real cases, since uninhabited fields are uncommon.
414 let has_no_hidden_fields = (matches!(adt, hir_def::AdtId::EnumId(_))
415 && !is_non_exhaustive)
416 || !field_tys().any(|ty| cx.is_uninhabited(ty));
417
418 if has_no_hidden_fields {
419 Fields::wildcards_from_tys(cx, field_tys())
420 } else {
421 //FIXME(iDawer): see MatchCheckCtx::is_uninhabited
422 unimplemented!("exhaustive_patterns feature")
423 }
424 }
425 }
426 _ => panic!("Unexpected type for `Single` constructor: {:?}", ty),
427 },
428 Missing | Wildcard => Fields::Vec(Default::default()),
429 _ => todo!(),
430 };
431 ret
432 }
433
434 /// Apply a constructor to a list of patterns, yielding a new pattern. `self`
435 /// must have as many elements as this constructor's arity.
436 ///
437 /// This is roughly the inverse of `specialize_constructor`.
438 ///
439 /// Examples:
440 /// `ctor`: `Constructor::Single`
441 /// `ty`: `Foo(u32, u32, u32)`
442 /// `self`: `[10, 20, _]`
443 /// returns `Foo(10, 20, _)`
444 ///
445 /// `ctor`: `Constructor::Variant(Option::Some)`
446 /// `ty`: `Option<bool>`
447 /// `self`: `[false]`
448 /// returns `Some(false)`
449 pub(super) fn apply(self, pcx: &PatCtxt<'_>, ctor: &Constructor) -> Pat {
450 let subpatterns_and_indices = self.patterns_and_indices();
451 let mut subpatterns = subpatterns_and_indices.iter().map(|&(_, p)| p);
452
453 match ctor {
454 Single | Variant(_) => match pcx.ty.kind(&Interner) {
455 TyKind::Adt(..) | TyKind::Tuple(..) => {
456 // We want the real indices here.
457 // TODO indices
458 let subpatterns = subpatterns_and_indices.iter().map(|&(_, pat)| pat).collect();
459
460 if let Some((adt, substs)) = pcx.ty.as_adt() {
461 if let hir_def::AdtId::EnumId(_) = adt {
462 todo!()
463 } else {
464 todo!()
465 }
466 } else {
467 // TODO ellipsis
468 Pat::Tuple { args: subpatterns, ellipsis: None }
469 }
470 }
471
472 _ => todo!(),
473 // TyKind::AssociatedType(_, _) => {}
474 // TyKind::Scalar(_) => {}
475 // TyKind::Array(_, _) => {}
476 // TyKind::Slice(_) => {}
477 // TyKind::Raw(_, _) => {}
478 // TyKind::Ref(_, _, _) => {}
479 // TyKind::OpaqueType(_, _) => {}
480 // TyKind::FnDef(_, _) => {}
481 // TyKind::Str => {}
482 // TyKind::Never => {}
483 // TyKind::Closure(_, _) => {}
484 // TyKind::Generator(_, _) => {}
485 // TyKind::GeneratorWitness(_, _) => {}
486 // TyKind::Foreign(_) => {}
487 // TyKind::Error => {}
488 // TyKind::Placeholder(_) => {}
489 // TyKind::Dyn(_) => {}
490 // TyKind::Alias(_) => {}
491 // TyKind::Function(_) => {}
492 // TyKind::BoundVar(_) => {}
493 // TyKind::InferenceVar(_, _) => {}
494 },
495
496 _ => todo!(),
497 // Constructor::IntRange(_) => {}
498 // Constructor::Slice(_) => {}
499 // Missing => {}
500 // Wildcard => {}
501 }
502 }
503
504 /// Returns the number of patterns. This is the same as the arity of the constructor used to
505 /// construct `self`.
506 pub(super) fn len(&self) -> usize {
507 match self {
508 Fields::Vec(pats) => pats.len(),
509 }
510 }
511
512 /// Returns the list of patterns along with the corresponding field indices.
513 fn patterns_and_indices(&self) -> SmallVec<[(usize, PatId); 2]> {
514 match self {
515 Fields::Vec(pats) => pats.iter().copied().enumerate().collect(),
516 }
517 }
518
519 pub(super) fn into_patterns(self) -> SmallVec<[PatId; 2]> {
520 match self {
521 Fields::Vec(pats) => pats,
522 }
523 }
524
525 /// Overrides some of the fields with the provided patterns. Exactly like
526 /// `replace_fields_indexed`, except that it takes `FieldPat`s as input.
527 fn replace_with_fieldpats(&self, new_pats: impl IntoIterator<Item = PatId>) -> Self {
528 self.replace_fields_indexed(new_pats.into_iter().enumerate())
529 }
530
531 /// Overrides some of the fields with the provided patterns. This is used when a pattern
532 /// defines some fields but not all, for example `Foo { field1: Some(_), .. }`: here we start
533 /// with a `Fields` that is just one wildcard per field of the `Foo` struct, and override the
534 /// entry corresponding to `field1` with the pattern `Some(_)`. This is also used for slice
535 /// patterns for the same reason.
536 fn replace_fields_indexed(&self, new_pats: impl IntoIterator<Item = (usize, PatId)>) -> Self {
537 let mut fields = self.clone();
538
539 match &mut fields {
540 Fields::Vec(pats) => {
541 for (i, pat) in new_pats {
542 if let Some(p) = pats.get_mut(i) {
543 *p = pat;
544 }
545 }
546 }
547 }
548 fields
549 }
550
551 /// Replaces contained fields with the given list of patterns. There must be `len()` patterns
552 /// in `pats`.
553 pub(super) fn replace_fields(
554 &self,
555 cx: &MatchCheckCtx<'_>,
556 pats: impl IntoIterator<Item = Pat>,
557 ) -> Self {
558 let pats = {
559 let mut arena = cx.pattern_arena.borrow_mut();
560 pats.into_iter().map(move |pat| /* arena.alloc(pat) */ todo!()).collect()
561 };
562
563 match self {
564 Fields::Vec(_) => Fields::Vec(pats),
565 }
566 }
567
568 /// Replaces contained fields with the arguments of the given pattern. Only use on a pattern
569 /// that is compatible with the constructor used to build `self`.
570 /// This is meant to be used on the result of `Fields::wildcards()`. The idea is that
571 /// `wildcards` constructs a list of fields where all entries are wildcards, and the pattern
572 /// provided to this function fills some of the fields with non-wildcards.
573 /// In the following example `Fields::wildcards` would return `[_, _, _, _]`. If we call
574 /// `replace_with_pattern_arguments` on it with the pattern, the result will be `[Some(0), _,
575 /// _, _]`.
576 /// ```rust
577 /// let x: [Option<u8>; 4] = foo();
578 /// match x {
579 /// [Some(0), ..] => {}
580 /// }
581 /// ```
582 /// This is guaranteed to preserve the number of patterns in `self`.
583 pub(super) fn replace_with_pattern_arguments(
584 &self,
585 pat: PatId,
586 cx: &MatchCheckCtx<'_>,
587 ) -> Self {
588 match &cx.pattern_arena.borrow()[pat] {
589 Pat::Ref { pat: subpattern, .. } => {
590 assert_eq!(self.len(), 1);
591 Fields::from_single_pattern(*subpattern)
592 }
593 Pat::Tuple { args: subpatterns, ellipsis } => {
594 // FIXME(iDawer) handle ellipsis.
595 // XXX(iDawer): in rustc, this is handled by HIR->TypedHIR lowering
596 // rustc_mir_build::thir::pattern::PatCtxt::lower_tuple_subpats(..)
597 self.replace_with_fieldpats(subpatterns.iter().copied())
598 }
599
600 Pat::Wild => self.clone(),
601 pat => todo!("Fields::replace_with_pattern_arguments({:?})", pat),
602 // Pat::Missing => {}
603 // Pat::Or(_) => {}
604 // Pat::Record { path, args, ellipsis } => {}
605 // Pat::Range { start, end } => {}
606 // Pat::Slice { prefix, slice, suffix } => {}
607 // Pat::Path(_) => {}
608 // Pat::Lit(_) => {}
609 // Pat::Bind { mode, name, subpat } => {}
610 // Pat::TupleStruct { path, args, ellipsis } => {}
611 // Pat::Box { inner } => {}
612 // Pat::ConstBlock(_) => {}
613 }
614 }
615}
616
617fn is_field_list_non_exhaustive(variant_id: VariantId, cx: &MatchCheckCtx<'_>) -> bool {
618 let attr_def_id = match variant_id {
619 VariantId::EnumVariantId(id) => id.into(),
620 VariantId::StructId(id) => id.into(),
621 VariantId::UnionId(id) => id.into(),
622 };
623 cx.db.attrs(attr_def_id).by_key("non_exhaustive").exists()
624}
625
626#[test]
627fn it_works() {}