1use 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 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 }
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 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 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 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 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 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 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 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 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 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 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 let expr_is_read = ExprIsRead::No;
403 let result =
404 self.infer_expr_coerce(*expr, &Expectation::has_type(expected), expr_is_read);
405 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 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 let ty = self.insert_type_vars_shallow(ty);
433 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 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 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 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 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 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}