Skip to content

Commit 14ab466

Browse files
committed
Equip infer_pat_* with declaration origin
1 parent fc6c6b4 commit 14ab466

File tree

4 files changed

+101
-26
lines changed

4 files changed

+101
-26
lines changed

src/tools/rust-analyzer/crates/hir-ty/src/infer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -943,7 +943,7 @@ impl<'a> InferenceContext<'a> {
943943
let ty = self.insert_type_vars(ty);
944944
let ty = self.normalize_associated_types_in(ty);
945945

946-
self.infer_top_pat(*pat, &ty);
946+
self.infer_top_pat(*pat, &ty, None);
947947
if ty
948948
.data(Interner)
949949
.flags

src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ use crate::{
4343
primitive::{self, UintTy},
4444
static_lifetime, to_chalk_trait_id,
4545
traits::FnTrait,
46-
Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, CallableSig, FnAbi, FnPointer,
47-
FnSig, FnSubst, Interner, Rawness, Scalar, Substitution, TraitEnvironment, TraitRef, Ty,
48-
TyBuilder, TyExt, TyKind,
46+
Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, CallableSig, DeclContext,
47+
DeclOrigin, FnAbi, FnPointer, FnSig, FnSubst, Interner, Rawness, Scalar, Substitution,
48+
TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
4949
};
5050

5151
use super::{
@@ -1633,7 +1633,12 @@ impl InferenceContext<'_> {
16331633
};
16341634

16351635
this.infer_top_pat(*pat, &ty);
1636+
let decl = DeclContext {
1637+
has_else: else_branch.is_some(),
1638+
origin: DeclOrigin::LocalDecl,
1639+
};
16361640

1641+
this.infer_top_pat(*pat, &ty, Some(decl));
16371642
if let Some(expr) = else_branch {
16381643
let previous_diverges =
16391644
mem::replace(&mut this.diverges, Diverges::Maybe);

src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs

Lines changed: 74 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ use crate::{
1919
},
2020
lower::lower_to_chalk_mutability,
2121
primitive::UintTy,
22-
static_lifetime, InferenceDiagnostic, Interner, Mutability, Scalar, Substitution, Ty,
23-
TyBuilder, TyExt, TyKind,
22+
static_lifetime, DeclContext, DeclOrigin, InferenceDiagnostic, Interner, Mutability, Scalar,
23+
Substitution, Ty, TyBuilder, TyExt, TyKind,
2424
};
2525

2626
impl InferenceContext<'_> {
@@ -35,6 +35,7 @@ impl InferenceContext<'_> {
3535
id: PatId,
3636
ellipsis: Option<u32>,
3737
subs: &[PatId],
38+
decl: Option<DeclContext>,
3839
) -> Ty {
3940
let (ty, def) = self.resolve_variant(id.into(), path, true);
4041
let var_data = def.map(|it| it.variant_data(self.db.upcast()));
@@ -93,13 +94,13 @@ impl InferenceContext<'_> {
9394
}
9495
};
9596

96-
self.infer_pat(subpat, &expected_ty, default_bm);
97+
self.infer_pat(subpat, &expected_ty, default_bm, decl);
9798
}
9899
}
99100
None => {
100101
let err_ty = self.err_ty();
101102
for &inner in subs {
102-
self.infer_pat(inner, &err_ty, default_bm);
103+
self.infer_pat(inner, &err_ty, default_bm, decl);
103104
}
104105
}
105106
}
@@ -115,6 +116,7 @@ impl InferenceContext<'_> {
115116
default_bm: BindingMode,
116117
id: PatId,
117118
subs: impl ExactSizeIterator<Item = (Name, PatId)>,
119+
decl: Option<DeclContext>,
118120
) -> Ty {
119121
let (ty, def) = self.resolve_variant(id.into(), path, false);
120122
if let Some(variant) = def {
@@ -163,13 +165,13 @@ impl InferenceContext<'_> {
163165
}
164166
};
165167

166-
self.infer_pat(inner, &expected_ty, default_bm);
168+
self.infer_pat(inner, &expected_ty, default_bm, decl);
167169
}
168170
}
169171
None => {
170172
let err_ty = self.err_ty();
171173
for (_, inner) in subs {
172-
self.infer_pat(inner, &err_ty, default_bm);
174+
self.infer_pat(inner, &err_ty, default_bm, decl);
173175
}
174176
}
175177
}
@@ -186,6 +188,7 @@ impl InferenceContext<'_> {
186188
default_bm: BindingMode,
187189
ellipsis: Option<u32>,
188190
subs: &[PatId],
191+
decl: Option<DeclContext>,
189192
) -> Ty {
190193
let expected = self.resolve_ty_shallow(expected);
191194
let expectations = match expected.as_tuple() {
@@ -210,12 +213,12 @@ impl InferenceContext<'_> {
210213

211214
// Process pre
212215
for (ty, pat) in inner_tys.iter_mut().zip(pre) {
213-
*ty = self.infer_pat(*pat, ty, default_bm);
216+
*ty = self.infer_pat(*pat, ty, default_bm, decl);
214217
}
215218

216219
// Process post
217220
for (ty, pat) in inner_tys.iter_mut().skip(pre.len() + n_uncovered_patterns).zip(post) {
218-
*ty = self.infer_pat(*pat, ty, default_bm);
221+
*ty = self.infer_pat(*pat, ty, default_bm, decl);
219222
}
220223

221224
TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys))
@@ -224,11 +227,17 @@ impl InferenceContext<'_> {
224227

225228
/// The resolver needs to be updated to the surrounding expression when inside assignment
226229
/// (because there, `Pat::Path` can refer to a variable).
227-
pub(super) fn infer_top_pat(&mut self, pat: PatId, expected: &Ty) {
228-
self.infer_pat(pat, expected, BindingMode::default());
230+
pub(super) fn infer_top_pat(&mut self, pat: PatId, expected: &Ty, decl: Option<DeclContext>) {
231+
self.infer_pat(pat, expected, BindingMode::default(), decl);
229232
}
230233

231-
fn infer_pat(&mut self, pat: PatId, expected: &Ty, mut default_bm: BindingMode) -> Ty {
234+
fn infer_pat(
235+
&mut self,
236+
pat: PatId,
237+
expected: &Ty,
238+
mut default_bm: BindingMode,
239+
decl: Option<DeclContext>,
240+
) -> Ty {
232241
let mut expected = self.resolve_ty_shallow(expected);
233242

234243
if matches!(&self.body[pat], Pat::Ref { .. }) || self.inside_assignment {
@@ -262,11 +271,11 @@ impl InferenceContext<'_> {
262271

263272
let ty = match &self.body[pat] {
264273
Pat::Tuple { args, ellipsis } => {
265-
self.infer_tuple_pat_like(&expected, default_bm, *ellipsis, args)
274+
self.infer_tuple_pat_like(&expected, default_bm, *ellipsis, args, decl)
266275
}
267276
Pat::Or(pats) => {
268277
for pat in pats.iter() {
269-
self.infer_pat(*pat, &expected, default_bm);
278+
self.infer_pat(*pat, &expected, default_bm, decl);
270279
}
271280
expected.clone()
272281
}
@@ -275,6 +284,7 @@ impl InferenceContext<'_> {
275284
lower_to_chalk_mutability(mutability),
276285
&expected,
277286
default_bm,
287+
decl,
278288
),
279289
Pat::TupleStruct { path: p, args: subpats, ellipsis } => self
280290
.infer_tuple_struct_pat_like(
@@ -284,10 +294,11 @@ impl InferenceContext<'_> {
284294
pat,
285295
*ellipsis,
286296
subpats,
297+
decl,
287298
),
288299
Pat::Record { path: p, args: fields, ellipsis: _ } => {
289300
let subs = fields.iter().map(|f| (f.name.clone(), f.pat));
290-
self.infer_record_pat_like(p.as_deref(), &expected, default_bm, pat, subs)
301+
self.infer_record_pat_like(p.as_deref(), &expected, default_bm, pat, subs, decl)
291302
}
292303
Pat::Path(path) => {
293304
let ty = self.infer_path(path, pat.into()).unwrap_or_else(|| self.err_ty());
@@ -320,10 +331,10 @@ impl InferenceContext<'_> {
320331
}
321332
}
322333
Pat::Bind { id, subpat } => {
323-
return self.infer_bind_pat(pat, *id, default_bm, *subpat, &expected);
334+
return self.infer_bind_pat(pat, *id, default_bm, *subpat, &expected, decl);
324335
}
325336
Pat::Slice { prefix, slice, suffix } => {
326-
self.infer_slice_pat(&expected, prefix, slice, suffix, default_bm)
337+
self.infer_slice_pat(&expected, prefix, slice, suffix, default_bm, decl)
327338
}
328339
Pat::Wild => expected.clone(),
329340
Pat::Range { .. } => {
@@ -346,7 +357,7 @@ impl InferenceContext<'_> {
346357
_ => (self.result.standard_types.unknown.clone(), None),
347358
};
348359

349-
let inner_ty = self.infer_pat(*inner, &inner_ty, default_bm);
360+
let inner_ty = self.infer_pat(*inner, &inner_ty, default_bm, decl);
350361
let mut b = TyBuilder::adt(self.db, box_adt).push(inner_ty);
351362

352363
if let Some(alloc_ty) = alloc_ty {
@@ -421,6 +432,7 @@ impl InferenceContext<'_> {
421432
mutability: Mutability,
422433
expected: &Ty,
423434
default_bm: BindingMode,
435+
decl: Option<DeclContext>,
424436
) -> Ty {
425437
let (expectation_type, expectation_lt) = match expected.as_reference() {
426438
Some((inner_ty, lifetime, _exp_mut)) => (inner_ty.clone(), lifetime.clone()),
@@ -434,7 +446,7 @@ impl InferenceContext<'_> {
434446
(inner_ty, inner_lt)
435447
}
436448
};
437-
let subty = self.infer_pat(inner_pat, &expectation_type, default_bm);
449+
let subty = self.infer_pat(inner_pat, &expectation_type, default_bm, decl);
438450
TyKind::Ref(mutability, expectation_lt, subty).intern(Interner)
439451
}
440452

@@ -445,6 +457,7 @@ impl InferenceContext<'_> {
445457
default_bm: BindingMode,
446458
subpat: Option<PatId>,
447459
expected: &Ty,
460+
decl: Option<DeclContext>,
448461
) -> Ty {
449462
let Binding { mode, .. } = self.body.bindings[binding];
450463
let mode = if mode == BindingAnnotation::Unannotated {
@@ -455,7 +468,7 @@ impl InferenceContext<'_> {
455468
self.result.binding_modes.insert(pat, mode);
456469

457470
let inner_ty = match subpat {
458-
Some(subpat) => self.infer_pat(subpat, expected, default_bm),
471+
Some(subpat) => self.infer_pat(subpat, expected, default_bm, decl),
459472
None => expected.clone(),
460473
};
461474
let inner_ty = self.insert_type_vars_shallow(inner_ty);
@@ -479,12 +492,13 @@ impl InferenceContext<'_> {
479492
slice: &Option<PatId>,
480493
suffix: &[PatId],
481494
default_bm: BindingMode,
495+
decl: Option<DeclContext>,
482496
) -> Ty {
483497
let expected = self.resolve_ty_shallow(expected);
484498

485499
// If `expected` is an infer ty, we try to equate it to an array if the given pattern
486500
// allows it. See issue #16609
487-
if expected.is_ty_var() {
501+
if self.decl_allows_array_type_infer(decl) && expected.is_ty_var() {
488502
if let Some(resolved_array_ty) =
489503
self.try_resolve_slice_ty_to_array_ty(prefix, suffix, slice)
490504
{
@@ -499,7 +513,7 @@ impl InferenceContext<'_> {
499513
};
500514

501515
for &pat_id in prefix.iter().chain(suffix.iter()) {
502-
self.infer_pat(pat_id, &elem_ty, default_bm);
516+
self.infer_pat(pat_id, &elem_ty, default_bm, decl);
503517
}
504518

505519
if let &Some(slice_pat_id) = slice {
@@ -513,7 +527,7 @@ impl InferenceContext<'_> {
513527
_ => TyKind::Slice(elem_ty.clone()),
514528
}
515529
.intern(Interner);
516-
self.infer_pat(slice_pat_id, &rest_pat_ty, default_bm);
530+
self.infer_pat(slice_pat_id, &rest_pat_ty, default_bm, decl);
517531
}
518532

519533
match expected.kind(Interner) {
@@ -586,6 +600,44 @@ impl InferenceContext<'_> {
586600
let array_ty = TyKind::Array(elem_ty.clone(), size).intern(Interner);
587601
Some(array_ty)
588602
}
603+
604+
/// Determines whether we can infer the expected type in the slice pattern to be of type array.
605+
/// This is only possible if we're in an irrefutable pattern. If we were to allow this in refutable
606+
/// patterns we wouldn't e.g. report ambiguity in the following situation:
607+
///
608+
/// ```ignore(rust)
609+
/// struct Zeroes;
610+
/// const ARR: [usize; 2] = [0; 2];
611+
/// const ARR2: [usize; 2] = [2; 2];
612+
///
613+
/// impl Into<&'static [usize; 2]> for Zeroes {
614+
/// fn into(self) -> &'static [usize; 2] {
615+
/// &ARR
616+
/// }
617+
/// }
618+
///
619+
/// impl Into<&'static [usize]> for Zeroes {
620+
/// fn into(self) -> &'static [usize] {
621+
/// &ARR2
622+
/// }
623+
/// }
624+
///
625+
/// fn main() {
626+
/// let &[a, b]: &[usize] = Zeroes.into() else {
627+
/// ..
628+
/// };
629+
/// }
630+
/// ```
631+
///
632+
/// If we're in an irrefutable pattern we prefer the array impl candidate given that
633+
/// the slice impl candidate would be be rejected anyway (if no ambiguity existed).
634+
fn decl_allows_array_type_infer(&self, decl_ctxt: Option<DeclContext>) -> bool {
635+
if let Some(decl_ctxt) = decl_ctxt {
636+
!decl_ctxt.has_else && matches!(decl_ctxt.origin, DeclOrigin::LocalDecl)
637+
} else {
638+
false
639+
}
640+
}
589641
}
590642

591643
pub(super) fn contains_explicit_ref_binding(body: &Body, pat_id: PatId) -> bool {

src/tools/rust-analyzer/crates/hir-ty/src/lib.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,3 +1049,21 @@ pub fn known_const_to_ast(
10491049
}
10501050
Some(make::expr_const_value(konst.display(db, edition).to_string().as_str()))
10511051
}
1052+
1053+
#[derive(Debug, Copy, Clone)]
1054+
pub(crate) enum DeclOrigin {
1055+
// from an `if let` expression
1056+
LetExpr,
1057+
// from `let x = ..`
1058+
LocalDecl,
1059+
}
1060+
1061+
/// Provides context for checking patterns in declarations. More specifically this
1062+
/// allows us to infer array types if the pattern is irrefutable and allows us to infer
1063+
/// the size of the array. See issue #76342.
1064+
#[derive(Debug, Copy, Clone)]
1065+
pub(crate) struct DeclContext {
1066+
// whether we're in a let-else context
1067+
pub(crate) has_else: bool,
1068+
pub(crate) origin: DeclOrigin,
1069+
}

0 commit comments

Comments
 (0)