Fix string literal inference in match

This commit is contained in:
Laurențiu Nicola 2020-06-24 12:57:28 +03:00
parent 7c28d060b5
commit 2bd9f0f020
2 changed files with 77 additions and 13 deletions

View file

@ -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,
}
}

View file

@ -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!(