hir_ty/infer/
pat.rs

1//! Type inference for patterns.
2
3use std::{cmp, iter};
4
5use hir_def::{
6    HasModule,
7    expr_store::{Body, path::Path},
8    hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, Literal, Pat, PatId},
9};
10use hir_expand::name::Name;
11use rustc_ast_ir::Mutability;
12use rustc_type_ir::inherent::{GenericArg as _, GenericArgs as _, IntoKind, SliceLike, Ty as _};
13use stdx::TupleExt;
14
15use crate::{
16    DeclContext, DeclOrigin, InferenceDiagnostic,
17    consteval::{self, try_const_usize, usize_const},
18    infer::{
19        AllowTwoPhase, BindingMode, Expectation, InferenceContext, TypeMismatch, expr::ExprIsRead,
20    },
21    lower::lower_mutability,
22    next_solver::{GenericArgs, Ty, TyKind, Tys, infer::traits::ObligationCause},
23};
24
25impl<'db> InferenceContext<'_, 'db> {
26    /// Infers type for tuple struct pattern or its corresponding assignee expression.
27    ///
28    /// Ellipses found in the original pattern or expression must be filtered out.
29    pub(super) fn infer_tuple_struct_pat_like(
30        &mut self,
31        path: Option<&Path>,
32        expected: Ty<'db>,
33        default_bm: BindingMode,
34        id: PatId,
35        ellipsis: Option<u32>,
36        subs: &[PatId],
37        decl: Option<DeclContext>,
38    ) -> Ty<'db> {
39        let (ty, def) = self.resolve_variant(id.into(), path, true);
40        let var_data = def.map(|it| it.fields(self.db));
41        if let Some(variant) = def {
42            self.write_variant_resolution(id.into(), variant);
43        }
44        if let Some(var) = &var_data {
45            let cmp = if ellipsis.is_some() { usize::gt } else { usize::ne };
46
47            if cmp(&subs.len(), &var.fields().len()) {
48                self.push_diagnostic(InferenceDiagnostic::MismatchedTupleStructPatArgCount {
49                    pat: id.into(),
50                    expected: var.fields().len(),
51                    found: subs.len(),
52                });
53            }
54        }
55
56        self.unify(ty, expected);
57
58        match def {
59            _ if subs.is_empty() => {}
60            Some(def) => {
61                let field_types = self.db.field_types(def);
62                let variant_data = def.fields(self.db);
63                let visibilities = self.db.field_visibilities(def);
64
65                let (pre, post) = match ellipsis {
66                    Some(idx) => subs.split_at(idx as usize),
67                    None => (subs, &[][..]),
68                };
69                let post_idx_offset = field_types.iter().count().saturating_sub(post.len());
70
71                let pre_iter = pre.iter().enumerate();
72                let post_iter = (post_idx_offset..).zip(post.iter());
73
74                let substs = ty.as_adt().map(TupleExt::tail);
75
76                for (i, &subpat) in pre_iter.chain(post_iter) {
77                    let expected_ty = {
78                        match variant_data.field(&Name::new_tuple_field(i)) {
79                            Some(local_id) => {
80                                if !visibilities[local_id]
81                                    .is_visible_from(self.db, self.resolver.module())
82                                {
83                                    // FIXME(DIAGNOSE): private tuple field
84                                }
85                                let f = field_types[local_id];
86                                let expected_ty = match substs {
87                                    Some(substs) => f.instantiate(self.interner(), substs),
88                                    None => f.instantiate(self.interner(), &[]),
89                                };
90                                self.process_remote_user_written_ty(expected_ty)
91                            }
92                            None => self.err_ty(),
93                        }
94                    };
95
96                    self.infer_pat(subpat, expected_ty, default_bm, decl);
97                }
98            }
99            None => {
100                let err_ty = self.err_ty();
101                for &inner in subs {
102                    self.infer_pat(inner, err_ty, default_bm, decl);
103                }
104            }
105        }
106
107        ty
108    }
109
110    /// Infers type for record pattern or its corresponding assignee expression.
111    pub(super) fn infer_record_pat_like(
112        &mut self,
113        path: Option<&Path>,
114        expected: Ty<'db>,
115        default_bm: BindingMode,
116        id: PatId,
117        subs: impl ExactSizeIterator<Item = (Name, PatId)>,
118        decl: Option<DeclContext>,
119    ) -> Ty<'db> {
120        let (ty, def) = self.resolve_variant(id.into(), path, false);
121        if let Some(variant) = def {
122            self.write_variant_resolution(id.into(), variant);
123        }
124
125        self.unify(ty, expected);
126
127        match def {
128            _ if subs.len() == 0 => {}
129            Some(def) => {
130                let field_types = self.db.field_types(def);
131                let variant_data = def.fields(self.db);
132                let visibilities = self.db.field_visibilities(def);
133
134                let substs = ty.as_adt().map(TupleExt::tail);
135
136                for (name, inner) in subs {
137                    let expected_ty = {
138                        match variant_data.field(&name) {
139                            Some(local_id) => {
140                                if !visibilities[local_id]
141                                    .is_visible_from(self.db, self.resolver.module())
142                                {
143                                    self.push_diagnostic(InferenceDiagnostic::NoSuchField {
144                                        field: inner.into(),
145                                        private: Some(local_id),
146                                        variant: def,
147                                    });
148                                }
149                                let f = field_types[local_id];
150                                let expected_ty = match substs {
151                                    Some(substs) => f.instantiate(self.interner(), substs),
152                                    None => f.instantiate(self.interner(), &[]),
153                                };
154                                self.process_remote_user_written_ty(expected_ty)
155                            }
156                            None => {
157                                self.push_diagnostic(InferenceDiagnostic::NoSuchField {
158                                    field: inner.into(),
159                                    private: None,
160                                    variant: def,
161                                });
162                                self.err_ty()
163                            }
164                        }
165                    };
166
167                    self.infer_pat(inner, expected_ty, default_bm, decl);
168                }
169            }
170            None => {
171                let err_ty = self.err_ty();
172                for (_, inner) in subs {
173                    self.infer_pat(inner, err_ty, default_bm, decl);
174                }
175            }
176        }
177
178        ty
179    }
180
181    /// Infers type for tuple pattern or its corresponding assignee expression.
182    ///
183    /// Ellipses found in the original pattern or expression must be filtered out.
184    pub(super) fn infer_tuple_pat_like(
185        &mut self,
186        pat: PatId,
187        expected: Ty<'db>,
188        default_bm: BindingMode,
189        ellipsis: Option<u32>,
190        elements: &[PatId],
191        decl: Option<DeclContext>,
192    ) -> Ty<'db> {
193        let mut expected_len = elements.len();
194        if ellipsis.is_some() {
195            // Require known type only when `..` is present.
196            if let TyKind::Tuple(tys) = self.table.structurally_resolve_type(expected).kind() {
197                expected_len = tys.len();
198            }
199        }
200        let max_len = cmp::max(expected_len, elements.len());
201
202        let element_tys_iter = (0..max_len).map(|_| self.table.next_ty_var());
203        let element_tys = Tys::new_from_iter(self.interner(), element_tys_iter);
204        let pat_ty = Ty::new(self.interner(), TyKind::Tuple(element_tys));
205        if self.demand_eqtype(pat.into(), expected, pat_ty).is_err()
206            && let TyKind::Tuple(expected) = expected.kind()
207        {
208            // Equate expected type with the infer vars, for better diagnostics.
209            for (expected, elem_ty) in iter::zip(expected, element_tys) {
210                _ = self
211                    .table
212                    .at(&ObligationCause::dummy())
213                    .eq(expected, elem_ty)
214                    .map(|infer_ok| self.table.register_infer_ok(infer_ok));
215            }
216        }
217        let (before_ellipsis, after_ellipsis) = match ellipsis {
218            Some(ellipsis) => {
219                let element_tys = element_tys.as_slice();
220                // Don't check patterns twice.
221                let from_end_start = cmp::max(
222                    element_tys.len().saturating_sub(elements.len() - ellipsis as usize),
223                    ellipsis as usize,
224                );
225                (
226                    element_tys.get(..ellipsis as usize).unwrap_or(element_tys),
227                    element_tys.get(from_end_start..).unwrap_or_default(),
228                )
229            }
230            None => (element_tys.as_slice(), &[][..]),
231        };
232        for (&elem, &elem_ty) in iter::zip(elements, before_ellipsis.iter().chain(after_ellipsis)) {
233            self.infer_pat(elem, elem_ty, default_bm, decl);
234        }
235        if let Some(uncovered) = elements.get(element_tys.len()..) {
236            for &elem in uncovered {
237                self.infer_pat(elem, self.types.error, default_bm, decl);
238            }
239        }
240        pat_ty
241    }
242
243    /// The resolver needs to be updated to the surrounding expression when inside assignment
244    /// (because there, `Pat::Path` can refer to a variable).
245    pub(super) fn infer_top_pat(
246        &mut self,
247        pat: PatId,
248        expected: Ty<'db>,
249        decl: Option<DeclContext>,
250    ) {
251        self.infer_pat(pat, expected, BindingMode::default(), decl);
252    }
253
254    fn infer_pat(
255        &mut self,
256        pat: PatId,
257        expected: Ty<'db>,
258        mut default_bm: BindingMode,
259        decl: Option<DeclContext>,
260    ) -> Ty<'db> {
261        let mut expected = self.table.structurally_resolve_type(expected);
262
263        if matches!(&self.body[pat], Pat::Ref { .. }) || self.inside_assignment {
264            cov_mark::hit!(match_ergonomics_ref);
265            // When you encounter a `&pat` pattern, reset to Move.
266            // This is so that `w` is by value: `let (_, &w) = &(1, &2);`
267            // Destructuring assignments also reset the binding mode and
268            // don't do match ergonomics.
269            default_bm = BindingMode::Move;
270        } else if self.is_non_ref_pat(self.body, pat) {
271            let mut pat_adjustments = Vec::new();
272            while let TyKind::Ref(_lifetime, inner, mutability) = expected.kind() {
273                pat_adjustments.push(expected);
274                expected = self.table.try_structurally_resolve_type(inner);
275                default_bm = match default_bm {
276                    BindingMode::Move => BindingMode::Ref(mutability),
277                    BindingMode::Ref(Mutability::Not) => BindingMode::Ref(Mutability::Not),
278                    BindingMode::Ref(Mutability::Mut) => BindingMode::Ref(mutability),
279                }
280            }
281
282            if !pat_adjustments.is_empty() {
283                pat_adjustments.shrink_to_fit();
284                self.result.pat_adjustments.insert(pat, pat_adjustments);
285            }
286        }
287
288        // Lose mutability.
289        let default_bm = default_bm;
290        let expected = expected;
291
292        let ty = match &self.body[pat] {
293            Pat::Tuple { args, ellipsis } => {
294                self.infer_tuple_pat_like(pat, expected, default_bm, *ellipsis, args, decl)
295            }
296            Pat::Or(pats) => {
297                for pat in pats.iter() {
298                    self.infer_pat(*pat, expected, default_bm, decl);
299                }
300                expected
301            }
302            &Pat::Ref { pat, mutability } => {
303                self.infer_ref_pat(pat, lower_mutability(mutability), expected, default_bm, decl)
304            }
305            Pat::TupleStruct { path: p, args: subpats, ellipsis } => self
306                .infer_tuple_struct_pat_like(
307                    p.as_deref(),
308                    expected,
309                    default_bm,
310                    pat,
311                    *ellipsis,
312                    subpats,
313                    decl,
314                ),
315            Pat::Record { path: p, args: fields, ellipsis: _ } => {
316                let subs = fields.iter().map(|f| (f.name.clone(), f.pat));
317                self.infer_record_pat_like(p.as_deref(), expected, default_bm, pat, subs, decl)
318            }
319            Pat::Path(path) => {
320                let ty = self.infer_path(path, pat.into()).unwrap_or_else(|| self.err_ty());
321                let ty_inserted_vars = self.insert_type_vars_shallow(ty);
322                match self.coerce(
323                    pat.into(),
324                    expected,
325                    ty_inserted_vars,
326                    AllowTwoPhase::No,
327                    ExprIsRead::No,
328                ) {
329                    Ok(coerced_ty) => {
330                        self.write_pat_ty(pat, coerced_ty);
331                        return self.pat_ty_after_adjustment(pat);
332                    }
333                    Err(_) => {
334                        self.result.type_mismatches.get_or_insert_default().insert(
335                            pat.into(),
336                            TypeMismatch { expected, actual: ty_inserted_vars },
337                        );
338                        self.write_pat_ty(pat, ty);
339                        // We return `expected` to prevent cascading errors. I guess an alternative is to
340                        // not emit type mismatches for error types and emit an error type here.
341                        return expected;
342                    }
343                }
344            }
345            Pat::Bind { id, subpat } => {
346                return self.infer_bind_pat(pat, *id, default_bm, *subpat, expected, decl);
347            }
348            Pat::Slice { prefix, slice, suffix } => {
349                self.infer_slice_pat(expected, prefix, *slice, suffix, default_bm, decl)
350            }
351            Pat::Wild => expected,
352            Pat::Range { start, end, range_type: _ } => {
353                if let Some(start) = *start {
354                    let start_ty = self.infer_expr(start, &Expectation::None, ExprIsRead::Yes);
355                    _ = self.demand_eqtype(start.into(), expected, start_ty);
356                }
357                if let Some(end) = *end {
358                    let end_ty = self.infer_expr(end, &Expectation::None, ExprIsRead::Yes);
359                    _ = self.demand_eqtype(end.into(), expected, end_ty);
360                }
361                expected
362            }
363            &Pat::Lit(expr) => {
364                // Don't emit type mismatches again, the expression lowering already did that.
365                let ty = self.infer_lit_pat(expr, expected);
366                self.write_pat_ty(pat, ty);
367                return self.pat_ty_after_adjustment(pat);
368            }
369            Pat::Box { inner } => match self.resolve_boxed_box() {
370                Some(box_adt) => {
371                    let (inner_ty, alloc_ty) = match expected.as_adt() {
372                        Some((adt, subst)) if adt == box_adt => {
373                            (subst.type_at(0), subst.as_slice().get(1).and_then(|a| a.as_type()))
374                        }
375                        _ => (self.types.error, None),
376                    };
377
378                    let inner_ty = self.infer_pat(*inner, inner_ty, default_bm, decl);
379                    Ty::new_adt(
380                        self.interner(),
381                        box_adt,
382                        GenericArgs::fill_with_defaults(
383                            self.interner(),
384                            box_adt.into(),
385                            iter::once(inner_ty.into()).chain(alloc_ty.map(Into::into)),
386                            |_, id, _| self.table.next_var_for_param(id),
387                        ),
388                    )
389                }
390                None => self.err_ty(),
391            },
392            Pat::ConstBlock(expr) => {
393                let old_inside_assign = std::mem::replace(&mut self.inside_assignment, false);
394                let result =
395                    self.infer_expr(*expr, &Expectation::has_type(expected), ExprIsRead::Yes);
396                self.inside_assignment = old_inside_assign;
397                result
398            }
399            Pat::Expr(expr) => {
400                let old_inside_assign = std::mem::replace(&mut self.inside_assignment, false);
401                // LHS of assignment doesn't constitute reads.
402                let expr_is_read = ExprIsRead::No;
403                let result =
404                    self.infer_expr_coerce(*expr, &Expectation::has_type(expected), expr_is_read);
405                // We are returning early to avoid the unifiability check below.
406                let lhs_ty = self.insert_type_vars_shallow(result);
407                let ty = match self.coerce(
408                    (*expr).into(),
409                    expected,
410                    lhs_ty,
411                    AllowTwoPhase::No,
412                    expr_is_read,
413                ) {
414                    Ok(ty) => ty,
415                    Err(_) => {
416                        self.result
417                            .type_mismatches
418                            .get_or_insert_default()
419                            .insert(pat.into(), TypeMismatch { expected, actual: lhs_ty });
420                        // `rhs_ty` is returned so no further type mismatches are
421                        // reported because of this mismatch.
422                        expected
423                    }
424                };
425                self.write_pat_ty(pat, ty);
426                self.inside_assignment = old_inside_assign;
427                return ty;
428            }
429            Pat::Missing => self.err_ty(),
430        };
431        // use a new type variable if we got error type here
432        let ty = self.insert_type_vars_shallow(ty);
433        // FIXME: This never check is odd, but required with out we do inference right now
434        if !expected.is_never() && !self.unify(ty, expected) {
435            self.result
436                .type_mismatches
437                .get_or_insert_default()
438                .insert(pat.into(), TypeMismatch { expected, actual: ty });
439        }
440        self.write_pat_ty(pat, ty);
441        self.pat_ty_after_adjustment(pat)
442    }
443
444    fn pat_ty_after_adjustment(&self, pat: PatId) -> Ty<'db> {
445        *self
446            .result
447            .pat_adjustments
448            .get(&pat)
449            .and_then(|it| it.last())
450            .unwrap_or(&self.result.type_of_pat[pat])
451    }
452
453    fn infer_ref_pat(
454        &mut self,
455        inner_pat: PatId,
456        mutability: Mutability,
457        expected: Ty<'db>,
458        default_bm: BindingMode,
459        decl: Option<DeclContext>,
460    ) -> Ty<'db> {
461        let (expectation_type, expectation_lt) = match expected.kind() {
462            TyKind::Ref(lifetime, inner_ty, _exp_mut) => (inner_ty, lifetime),
463            _ => {
464                let inner_ty = self.table.next_ty_var();
465                let inner_lt = self.table.next_region_var();
466                let ref_ty = Ty::new_ref(self.interner(), inner_lt, inner_ty, mutability);
467                // Unification failure will be reported by the caller.
468                self.unify(ref_ty, expected);
469                (inner_ty, inner_lt)
470            }
471        };
472        let subty = self.infer_pat(inner_pat, expectation_type, default_bm, decl);
473        Ty::new_ref(self.interner(), expectation_lt, subty, mutability)
474    }
475
476    fn infer_bind_pat(
477        &mut self,
478        pat: PatId,
479        binding: BindingId,
480        default_bm: BindingMode,
481        subpat: Option<PatId>,
482        expected: Ty<'db>,
483        decl: Option<DeclContext>,
484    ) -> Ty<'db> {
485        let Binding { mode, .. } = self.body[binding];
486        let mode = if mode == BindingAnnotation::Unannotated {
487            default_bm
488        } else {
489            BindingMode::convert(mode)
490        };
491        self.result.binding_modes.insert(pat, mode);
492
493        let inner_ty = match subpat {
494            Some(subpat) => self.infer_pat(subpat, expected, default_bm, decl),
495            None => expected,
496        };
497        let inner_ty = self.insert_type_vars_shallow(inner_ty);
498
499        let bound_ty = match mode {
500            BindingMode::Ref(mutability) => {
501                let inner_lt = self.table.next_region_var();
502                Ty::new_ref(self.interner(), inner_lt, expected, mutability)
503            }
504            BindingMode::Move => expected,
505        };
506        self.write_pat_ty(pat, inner_ty);
507        self.write_binding_ty(binding, bound_ty);
508        inner_ty
509    }
510
511    fn infer_slice_pat(
512        &mut self,
513        expected: Ty<'db>,
514        prefix: &[PatId],
515        slice: Option<PatId>,
516        suffix: &[PatId],
517        default_bm: BindingMode,
518        decl: Option<DeclContext>,
519    ) -> Ty<'db> {
520        let expected = self.table.structurally_resolve_type(expected);
521
522        // If `expected` is an infer ty, we try to equate it to an array if the given pattern
523        // allows it. See issue #16609
524        if self.pat_is_irrefutable(decl)
525            && expected.is_ty_var()
526            && let Some(resolved_array_ty) =
527                self.try_resolve_slice_ty_to_array_ty(prefix, suffix, slice)
528        {
529            self.unify(expected, resolved_array_ty);
530        }
531
532        let expected = self.table.try_structurally_resolve_type(expected);
533        let elem_ty = match expected.kind() {
534            TyKind::Array(st, _) | TyKind::Slice(st) => st,
535            _ => self.err_ty(),
536        };
537
538        for &pat_id in prefix.iter().chain(suffix.iter()) {
539            self.infer_pat(pat_id, elem_ty, default_bm, decl);
540        }
541
542        if let Some(slice_pat_id) = slice {
543            let rest_pat_ty = match expected.kind() {
544                TyKind::Array(_, length) => {
545                    let len = try_const_usize(self.db, length);
546                    let len =
547                        len.and_then(|len| len.checked_sub((prefix.len() + suffix.len()) as u128));
548                    Ty::new_array_with_const_len(
549                        self.interner(),
550                        elem_ty,
551                        usize_const(self.db, len, self.resolver.krate()),
552                    )
553                }
554                _ => Ty::new_slice(self.interner(), elem_ty),
555            };
556            self.infer_pat(slice_pat_id, rest_pat_ty, default_bm, decl);
557        }
558
559        match expected.kind() {
560            TyKind::Array(_, const_) => {
561                Ty::new_array_with_const_len(self.interner(), elem_ty, const_)
562            }
563            _ => Ty::new_slice(self.interner(), elem_ty),
564        }
565    }
566
567    fn infer_lit_pat(&mut self, expr: ExprId, expected: Ty<'db>) -> Ty<'db> {
568        // Like slice patterns, byte string patterns can denote both `&[u8; N]` and `&[u8]`.
569        if let Expr::Literal(Literal::ByteString(_)) = self.body[expr]
570            && let TyKind::Ref(_, inner, _) = expected.kind()
571        {
572            let inner = self.table.try_structurally_resolve_type(inner);
573            if matches!(inner.kind(), TyKind::Slice(_)) {
574                let elem_ty = self.types.u8;
575                let slice_ty = Ty::new_slice(self.interner(), elem_ty);
576                let ty =
577                    Ty::new_ref(self.interner(), self.types.re_static, slice_ty, Mutability::Not);
578                self.write_expr_ty(expr, ty);
579                return ty;
580            }
581        }
582
583        self.infer_expr(expr, &Expectation::has_type(expected), ExprIsRead::Yes)
584    }
585
586    fn is_non_ref_pat(&mut self, body: &hir_def::expr_store::Body, pat: PatId) -> bool {
587        match &body[pat] {
588            Pat::Tuple { .. }
589            | Pat::TupleStruct { .. }
590            | Pat::Record { .. }
591            | Pat::Range { .. }
592            | Pat::Slice { .. } => true,
593            Pat::Or(pats) => pats.iter().all(|p| self.is_non_ref_pat(body, *p)),
594            Pat::Path(path) => {
595                // A const is a reference pattern, but other value ns things aren't (see #16131).
596                let resolved = self.resolve_value_path_inner(path, pat.into(), true);
597                resolved.is_some_and(|it| !matches!(it.0, hir_def::resolver::ValueNs::ConstId(_)))
598            }
599            Pat::ConstBlock(..) => false,
600            Pat::Lit(expr) => !matches!(
601                body[*expr],
602                Expr::Literal(Literal::String(..) | Literal::CString(..) | Literal::ByteString(..))
603            ),
604            Pat::Wild
605            | Pat::Bind { .. }
606            | Pat::Ref { .. }
607            | Pat::Box { .. }
608            | Pat::Missing
609            | Pat::Expr(_) => false,
610        }
611    }
612
613    fn try_resolve_slice_ty_to_array_ty(
614        &mut self,
615        before: &[PatId],
616        suffix: &[PatId],
617        slice: Option<PatId>,
618    ) -> Option<Ty<'db>> {
619        if slice.is_some() {
620            return None;
621        }
622
623        let len = before.len() + suffix.len();
624        let size = consteval::usize_const(self.db, Some(len as u128), self.owner.krate(self.db));
625
626        let elem_ty = self.table.next_ty_var();
627        let array_ty = Ty::new_array_with_const_len(self.interner(), elem_ty, size);
628        Some(array_ty)
629    }
630
631    /// Used to determine whether we can infer the expected type in the slice pattern to be of type array.
632    /// This is only possible if we're in an irrefutable pattern. If we were to allow this in refutable
633    /// patterns we wouldn't e.g. report ambiguity in the following situation:
634    ///
635    /// ```ignore(rust)
636    ///    struct Zeroes;
637    ///    const ARR: [usize; 2] = [0; 2];
638    ///    const ARR2: [usize; 2] = [2; 2];
639    ///
640    ///    impl Into<&'static [usize; 2]> for Zeroes {
641    ///        fn into(self) -> &'static [usize; 2] {
642    ///            &ARR
643    ///        }
644    ///    }
645    ///
646    ///    impl Into<&'static [usize]> for Zeroes {
647    ///        fn into(self) -> &'static [usize] {
648    ///            &ARR2
649    ///        }
650    ///    }
651    ///
652    ///    fn main() {
653    ///        let &[a, b]: &[usize] = Zeroes.into() else {
654    ///           ..
655    ///        };
656    ///    }
657    /// ```
658    ///
659    /// If we're in an irrefutable pattern we prefer the array impl candidate given that
660    /// the slice impl candidate would be rejected anyway (if no ambiguity existed).
661    fn pat_is_irrefutable(&self, decl_ctxt: Option<DeclContext>) -> bool {
662        matches!(decl_ctxt, Some(DeclContext { origin: DeclOrigin::LocalDecl { has_else: false } }))
663    }
664}
665
666pub(super) fn contains_explicit_ref_binding(body: &Body, pat_id: PatId) -> bool {
667    let mut res = false;
668    body.walk_pats(pat_id, &mut |pat| {
669        res |= matches!(body[pat], Pat::Bind { id, .. } if body[id].mode == BindingAnnotation::Ref);
670    });
671    res
672}