aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir_ty/src/infer/pat.rs33
-rw-r--r--crates/ra_hir_ty/src/tests/patterns.rs57
2 files changed, 77 insertions, 13 deletions
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs
index 4006f595d..23de2bd6b 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 {
@@ -227,3 +216,21 @@ impl<'a> InferenceContext<'a> {
227 ty 216 ty
228 } 217 }
229} 218}
219
220fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool {
221 match &body[pat] {
222 Pat::Tuple { .. }
223 | Pat::TupleStruct { .. }
224 | Pat::Record { .. }
225 | Pat::Range { .. }
226 | Pat::Slice { .. } => true,
227 Pat::Or(pats) => pats.iter().all(|p| is_non_ref_pat(body, *p)),
228 // FIXME: Path/Lit might actually evaluate to ref, but inference is unimplemented.
229 Pat::Path(..) => true,
230 Pat::Lit(expr) => match body[*expr] {
231 Expr::Literal(Literal::String(..)) => false,
232 _ => true,
233 },
234 Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false,
235 }
236}
diff --git a/crates/ra_hir_ty/src/tests/patterns.rs b/crates/ra_hir_ty/src/tests/patterns.rs
index 8fa296137..e5ef241ca 100644
--- a/crates/ra_hir_ty/src/tests/patterns.rs
+++ b/crates/ra_hir_ty/src/tests/patterns.rs
@@ -271,6 +271,63 @@ fn test() {
271} 271}
272 272
273#[test] 273#[test]
274fn infer_pattern_match_string_literal() {
275 assert_snapshot!(
276 infer_with_mismatches(r#"
277fn test() {
278 let s: &str = "hello";
279 match s {
280 "hello" => {}
281 _ => {}
282 }
283}
284"#, true),
285 @r###"
286 10..98 '{ ... } }': ()
287 20..21 's': &str
288 30..37 '"hello"': &str
289 43..96 'match ... }': ()
290 49..50 's': &str
291 61..68 '"hello"': &str
292 61..68 '"hello"': &str
293 72..74 '{}': ()
294 83..84 '_': &str
295 88..90 '{}': ()
296 "###
297 );
298}
299
300#[test]
301fn infer_pattern_match_or() {
302 assert_snapshot!(
303 infer_with_mismatches(r#"
304fn test() {
305 let s: &str = "hello";
306 match s {
307 "hello" | "world" => {}
308 _ => {}
309 }
310}
311"#, true),
312 @r###"
313 10..108 '{ ... } }': ()
314 20..21 's': &str
315 30..37 '"hello"': &str
316 43..106 'match ... }': ()
317 49..50 's': &str
318 61..68 '"hello"': &str
319 61..68 '"hello"': &str
320 61..78 '"hello...world"': &str
321 71..78 '"world"': &str
322 71..78 '"world"': &str
323 82..84 '{}': ()
324 93..94 '_': &str
325 98..100 '{}': ()
326 "###
327 );
328}
329
330#[test]
274fn infer_pattern_match_arr() { 331fn infer_pattern_match_arr() {
275 assert_snapshot!( 332 assert_snapshot!(
276 infer(r#" 333 infer(r#"