From 2bd9f0f0205e03f95ab83e8f579742618b97a609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 24 Jun 2020 12:57:28 +0300 Subject: Fix string literal inference in match --- crates/ra_hir_ty/src/infer/pat.rs | 33 ++++++++++++-------- crates/ra_hir_ty/src/tests/patterns.rs | 57 ++++++++++++++++++++++++++++++++++ 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; use std::sync::Arc; use hir_def::{ - expr::{BindingAnnotation, Pat, PatId, RecordFieldPat}, + expr::{BindingAnnotation, Expr, Literal, Pat, PatId, RecordFieldPat}, path::Path, type_ref::Mutability, FieldId, @@ -90,18 +90,7 @@ impl<'a> InferenceContext<'a> { ) -> Ty { let body = Arc::clone(&self.body); // avoid borrow checker problem - let is_non_ref_pat = match &body[pat] { - Pat::Tuple { .. } - | Pat::Or(..) - | Pat::TupleStruct { .. } - | Pat::Record { .. } - | Pat::Range { .. } - | Pat::Slice { .. } => true, - // FIXME: Path/Lit might actually evaluate to ref, but inference is unimplemented. - Pat::Path(..) | Pat::Lit(..) => true, - Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false, - }; - if is_non_ref_pat { + if is_non_ref_pat(&body, pat) { while let Some((inner, mutability)) = expected.as_reference() { expected = inner; default_bm = match default_bm { @@ -227,3 +216,21 @@ impl<'a> InferenceContext<'a> { ty } } + +fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool { + match &body[pat] { + Pat::Tuple { .. } + | Pat::TupleStruct { .. } + | Pat::Record { .. } + | Pat::Range { .. } + | Pat::Slice { .. } => true, + Pat::Or(pats) => pats.iter().all(|p| is_non_ref_pat(body, *p)), + // FIXME: Path/Lit might actually evaluate to ref, but inference is unimplemented. + Pat::Path(..) => true, + Pat::Lit(expr) => match body[*expr] { + Expr::Literal(Literal::String(..)) => false, + _ => true, + }, + Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false, + } +} 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 @@ -270,6 +270,63 @@ fn test() { ); } +#[test] +fn infer_pattern_match_string_literal() { + assert_snapshot!( + infer_with_mismatches(r#" +fn test() { + let s: &str = "hello"; + match s { + "hello" => {} + _ => {} + } +} +"#, true), + @r###" + 10..98 '{ ... } }': () + 20..21 's': &str + 30..37 '"hello"': &str + 43..96 'match ... }': () + 49..50 's': &str + 61..68 '"hello"': &str + 61..68 '"hello"': &str + 72..74 '{}': () + 83..84 '_': &str + 88..90 '{}': () + "### + ); +} + +#[test] +fn infer_pattern_match_or() { + assert_snapshot!( + infer_with_mismatches(r#" +fn test() { + let s: &str = "hello"; + match s { + "hello" | "world" => {} + _ => {} + } +} +"#, true), + @r###" + 10..108 '{ ... } }': () + 20..21 's': &str + 30..37 '"hello"': &str + 43..106 'match ... }': () + 49..50 's': &str + 61..68 '"hello"': &str + 61..68 '"hello"': &str + 61..78 '"hello...world"': &str + 71..78 '"world"': &str + 71..78 '"world"': &str + 82..84 '{}': () + 93..94 '_': &str + 98..100 '{}': () + "### + ); +} + #[test] fn infer_pattern_match_arr() { assert_snapshot!( -- cgit v1.2.3