aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/infer/pat.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src/infer/pat.rs')
-rw-r--r--crates/ra_hir_ty/src/infer/pat.rs42
1 files changed, 27 insertions, 15 deletions
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs
index 4006f595d..4dd4f9802 100644
--- a/crates/ra_hir_ty/src/infer/pat.rs
+++ b/crates/ra_hir_ty/src/infer/pat.rs
@@ -4,7 +4,7 @@ use std::iter::repeat;
4use std::sync::Arc; 4use std::sync::Arc;
5 5
6use hir_def::{ 6use hir_def::{
7 expr::{BindingAnnotation, Pat, PatId, RecordFieldPat}, 7 expr::{BindingAnnotation, Expr, Literal, Pat, PatId, RecordFieldPat},
8 path::Path, 8 path::Path,
9 type_ref::Mutability, 9 type_ref::Mutability,
10 FieldId, 10 FieldId,
@@ -90,18 +90,7 @@ impl<'a> InferenceContext<'a> {
90 ) -> Ty { 90 ) -> Ty {
91 let body = Arc::clone(&self.body); // avoid borrow checker problem 91 let body = Arc::clone(&self.body); // avoid borrow checker problem
92 92
93 let is_non_ref_pat = match &body[pat] { 93 if is_non_ref_pat(&body, pat) {
94 Pat::Tuple { .. }
95 | Pat::Or(..)
96 | Pat::TupleStruct { .. }
97 | Pat::Record { .. }
98 | Pat::Range { .. }
99 | Pat::Slice { .. } => true,
100 // FIXME: Path/Lit might actually evaluate to ref, but inference is unimplemented.
101 Pat::Path(..) | Pat::Lit(..) => true,
102 Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false,
103 };
104 if is_non_ref_pat {
105 while let Some((inner, mutability)) = expected.as_reference() { 94 while let Some((inner, mutability)) = expected.as_reference() {
106 expected = inner; 95 expected = inner;
107 default_bm = match default_bm { 96 default_bm = match default_bm {
@@ -195,7 +184,7 @@ impl<'a> InferenceContext<'a> {
195 self.write_pat_ty(pat, bound_ty); 184 self.write_pat_ty(pat, bound_ty);
196 return inner_ty; 185 return inner_ty;
197 } 186 }
198 Pat::Slice { prefix, slice: _slice, suffix } => { 187 Pat::Slice { prefix, slice, suffix } => {
199 let (container_ty, elem_ty) = match &expected { 188 let (container_ty, elem_ty) = match &expected {
200 ty_app!(TypeCtor::Array, st) => (TypeCtor::Array, st.as_single().clone()), 189 ty_app!(TypeCtor::Array, st) => (TypeCtor::Array, st.as_single().clone()),
201 ty_app!(TypeCtor::Slice, st) => (TypeCtor::Slice, st.as_single().clone()), 190 ty_app!(TypeCtor::Slice, st) => (TypeCtor::Slice, st.as_single().clone()),
@@ -206,7 +195,12 @@ impl<'a> InferenceContext<'a> {
206 self.infer_pat(*pat_id, &elem_ty, default_bm); 195 self.infer_pat(*pat_id, &elem_ty, default_bm);
207 } 196 }
208 197
209 Ty::apply_one(container_ty, elem_ty) 198 let pat_ty = Ty::apply_one(container_ty, elem_ty);
199 if let Some(slice_pat_id) = slice {
200 self.infer_pat(*slice_pat_id, &pat_ty, default_bm);
201 }
202
203 pat_ty
210 } 204 }
211 Pat::Wild => expected.clone(), 205 Pat::Wild => expected.clone(),
212 Pat::Range { start, end } => { 206 Pat::Range { start, end } => {
@@ -227,3 +221,21 @@ impl<'a> InferenceContext<'a> {
227 ty 221 ty
228 } 222 }
229} 223}
224
225fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool {
226 match &body[pat] {
227 Pat::Tuple { .. }
228 | Pat::TupleStruct { .. }
229 | Pat::Record { .. }
230 | Pat::Range { .. }
231 | Pat::Slice { .. } => true,
232 Pat::Or(pats) => pats.iter().all(|p| is_non_ref_pat(body, *p)),
233 // FIXME: Path/Lit might actually evaluate to ref, but inference is unimplemented.
234 Pat::Path(..) => true,
235 Pat::Lit(expr) => match body[*expr] {
236 Expr::Literal(Literal::String(..)) => false,
237 _ => true,
238 },
239 Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false,
240 }
241}