Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer/pat.rs')
-rw-r--r--crates/hir-ty/src/infer/pat.rs59
1 files changed, 34 insertions, 25 deletions
diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs
index 5f839fc307..2480f8baba 100644
--- a/crates/hir-ty/src/infer/pat.rs
+++ b/crates/hir-ty/src/infer/pat.rs
@@ -5,7 +5,7 @@ use std::iter::repeat_with;
use chalk_ir::Mutability;
use hir_def::{
body::Body,
- expr::{Binding, BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, Literal, Pat, PatId},
+ hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, Literal, Pat, PatId},
path::Path,
};
use hir_expand::name::Name;
@@ -255,15 +255,15 @@ impl<'a> InferenceContext<'a> {
self.infer_slice_pat(&expected, prefix, slice, suffix, default_bm)
}
Pat::Wild => expected.clone(),
- Pat::Range { start, end } => {
- let start_ty = self.infer_expr(*start, &Expectation::has_type(expected.clone()));
- self.infer_expr(*end, &Expectation::has_type(start_ty))
+ Pat::Range { .. } => {
+ // FIXME: do some checks here.
+ expected.clone()
}
&Pat::Lit(expr) => {
// Don't emit type mismatches again, the expression lowering already did that.
let ty = self.infer_lit_pat(expr, &expected);
self.write_pat_ty(pat, ty.clone());
- return ty;
+ return self.pat_ty_after_adjustment(pat);
}
Pat::Box { inner } => match self.resolve_boxed_box() {
Some(box_adt) => {
@@ -298,22 +298,38 @@ impl<'a> InferenceContext<'a> {
.type_mismatches
.insert(pat.into(), TypeMismatch { expected, actual: ty.clone() });
}
- self.write_pat_ty(pat, ty.clone());
- ty
+ self.write_pat_ty(pat, ty);
+ self.pat_ty_after_adjustment(pat)
+ }
+
+ fn pat_ty_after_adjustment(&self, pat: PatId) -> Ty {
+ self.result
+ .pat_adjustments
+ .get(&pat)
+ .and_then(|x| x.first())
+ .unwrap_or(&self.result.type_of_pat[pat])
+ .clone()
}
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)
}
@@ -331,7 +347,7 @@ impl<'a> InferenceContext<'a> {
} else {
BindingMode::convert(mode)
};
- self.result.pat_binding_modes.insert(pat, mode);
+ self.result.binding_modes.insert(binding, mode);
let inner_ty = match subpat {
Some(subpat) => self.infer_pat(subpat, &expected, default_bm),
@@ -345,7 +361,7 @@ impl<'a> InferenceContext<'a> {
}
BindingMode::Move => inner_ty.clone(),
};
- self.write_pat_ty(pat, bound_ty.clone());
+ self.write_pat_ty(pat, inner_ty.clone());
self.write_binding_ty(binding, bound_ty);
return inner_ty;
}
@@ -370,7 +386,7 @@ impl<'a> InferenceContext<'a> {
if let &Some(slice_pat_id) = slice {
let rest_pat_ty = match expected.kind(Interner) {
TyKind::Array(_, length) => {
- let len = try_const_usize(length);
+ let len = try_const_usize(self.db, length);
let len =
len.and_then(|len| len.checked_sub((prefix.len() + suffix.len()) as u128));
TyKind::Array(elem_ty.clone(), usize_const(self.db, len, self.resolver.krate()))
@@ -419,17 +435,10 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool {
// FIXME: ConstBlock/Path/Lit might actually evaluate to ref, but inference is unimplemented.
Pat::Path(..) => true,
Pat::ConstBlock(..) => true,
- Pat::Lit(expr) => {
- !matches!(body[*expr], Expr::Literal(Literal::String(..) | Literal::ByteString(..)))
- }
- Pat::Bind { id, subpat: Some(subpat), .. }
- if matches!(
- body.bindings[*id].mode,
- BindingAnnotation::Mutable | BindingAnnotation::Unannotated
- ) =>
- {
- is_non_ref_pat(body, *subpat)
- }
+ Pat::Lit(expr) => !matches!(
+ body[*expr],
+ Expr::Literal(Literal::String(..) | Literal::CString(..) | Literal::ByteString(..))
+ ),
Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false,
}
}
@@ -437,7 +446,7 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool {
pub(super) fn contains_explicit_ref_binding(body: &Body, pat_id: PatId) -> bool {
let mut res = false;
body.walk_pats(pat_id, &mut |pat| {
- res |= matches!(pat, Pat::Bind { id, .. } if body.bindings[*id].mode == BindingAnnotation::Ref);
+ res |= matches!(body[pat], Pat::Bind { id, .. } if body.bindings[id].mode == BindingAnnotation::Ref);
});
res
}