Auto merge of #12355 - ruabmbua:fix-inference-pattern-wildcards, r=flodiebold

Fix inference when pattern matching a tuple field with a wildcard

This should fix the following issue:  https://github.com/rust-lang/rust-analyzer/issues/12331

* Replaced the `err_ty` in `infer_pat()` with a new type variable.
* Had to change the iterator code a bit, to get around multiple mutable borrows of `self` in `infer_pat()`.
Also added a test
* Also added a test
This commit is contained in:
bors 2022-05-23 10:38:19 +00:00
commit 238253c22d
2 changed files with 41 additions and 8 deletions

View File

@ -1,6 +1,6 @@
//! Type inference for patterns.
use std::iter::repeat;
use std::iter::repeat_with;
use chalk_ir::Mutability;
use hir_def::{
@ -140,15 +140,28 @@ impl<'a> InferenceContext<'a> {
}
None => ((&args[..], &[][..]), 0),
};
let err_ty = self.err_ty();
let mut expectations_iter =
expectations.iter().map(|a| a.assert_ty_ref(Interner)).chain(repeat(&err_ty));
let mut infer_pat = |(&pat, ty)| self.infer_pat(pat, ty, default_bm);
let mut expectations_iter = expectations
.iter()
.cloned()
.map(|a| a.assert_ty_ref(Interner).clone())
.chain(repeat_with(|| self.table.new_type_var()));
let mut inner_tys = Vec::with_capacity(n_uncovered_patterns + args.len());
inner_tys.extend(pre.iter().zip(expectations_iter.by_ref()).map(&mut infer_pat));
inner_tys.extend(expectations_iter.by_ref().take(n_uncovered_patterns).cloned());
inner_tys.extend(post.iter().zip(expectations_iter).map(infer_pat));
inner_tys
.extend(expectations_iter.by_ref().take(n_uncovered_patterns + args.len()));
// Process pre
for (ty, pat) in inner_tys.iter_mut().zip(pre) {
*ty = self.infer_pat(*pat, ty, default_bm);
}
// Process post
for (ty, pat) in
inner_tys.iter_mut().skip(pre.len() + n_uncovered_patterns).zip(post)
{
*ty = self.infer_pat(*pat, ty, default_bm);
}
TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys))
.intern(Interner)

View File

@ -969,3 +969,23 @@ fn main() {
"#,
);
}
#[test]
fn tuple_wildcard() {
check_types(
r#"
fn main() {
enum Option<T> {Some(T), None}
use Option::*;
let mut x = None;
x;
//^ Option<(i32, i32)>
if let Some((_, _a)) = x {}
x = Some((1, 2));
}
"#,
);
}