Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #14872 - lowr:fix/ref-pat-with-type-var, r=HKalbasi
fix: introduce new type var when expectation for ref pat is not ref
Fixes #14840
When we infer the type of ref patterns, its expected type may not be reference type: 1) expected type is an unresolved inference variable, or 2) expected type is erroneously other kind of type. In either case, we should produce a reference type with a new type variable rather than an error type so that we can continue inferring the inner patterns without further errors because of the (possible) type mismatch of this pattern.
| -rw-r--r-- | crates/hir-ty/src/infer/pat.rs | 13 | ||||
| -rw-r--r-- | crates/hir-ty/src/tests/patterns.rs | 17 |
2 files changed, 26 insertions, 4 deletions
diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs index 05f6fcaead..0c2b179a10 100644 --- a/crates/hir-ty/src/infer/pat.rs +++ b/crates/hir-ty/src/infer/pat.rs @@ -313,16 +313,23 @@ impl<'a> InferenceContext<'a> { fn infer_ref_pat( &mut self, - pat: PatId, + inner_pat: PatId, mutability: Mutability, expected: &Ty, default_bm: BindingMode, ) -> Ty { let expectation = match expected.as_reference() { Some((inner_ty, _lifetime, _exp_mut)) => inner_ty.clone(), - _ => self.result.standard_types.unknown.clone(), + None => { + let inner_ty = self.table.new_type_var(); + let ref_ty = + TyKind::Ref(mutability, static_lifetime(), inner_ty.clone()).intern(Interner); + // Unification failure will be reported by the caller. + self.unify(&ref_ty, expected); + inner_ty + } }; - let subty = self.infer_pat(pat, &expectation, default_bm); + let subty = self.infer_pat(inner_pat, &expectation, default_bm); TyKind::Ref(mutability, static_lifetime(), subty).intern(Interner) } diff --git a/crates/hir-ty/src/tests/patterns.rs b/crates/hir-ty/src/tests/patterns.rs index c8c31bdea5..b73f0d72a3 100644 --- a/crates/hir-ty/src/tests/patterns.rs +++ b/crates/hir-ty/src/tests/patterns.rs @@ -1,6 +1,6 @@ use expect_test::expect; -use super::{check, check_infer, check_infer_with_mismatches, check_types}; +use super::{check, check_infer, check_infer_with_mismatches, check_no_mismatches, check_types}; #[test] fn infer_pattern() { @@ -241,6 +241,21 @@ fn infer_pattern_match_ergonomics_ref() { } #[test] +fn ref_pat_with_inference_variable() { + check_no_mismatches( + r#" +enum E { A } +fn test() { + let f = |e| match e { + &E::A => {} + }; + f(&E::A); +} +"#, + ); +} + +#[test] fn infer_pattern_match_slice() { check_infer( r#" |