From b392a732d31f9be028e4b2dcf4752c5e4c7a9880 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Wed, 1 Apr 2020 20:27:47 +0200 Subject: [PATCH] Add inference for literal and range patterns --- crates/ra_hir_ty/src/infer/pat.rs | 11 ++- crates/ra_hir_ty/src/tests/coercion.rs | 6 ++ crates/ra_hir_ty/src/tests/patterns.rs | 85 ++++++++++++++++++++++++ crates/ra_hir_ty/src/tests/regression.rs | 3 +- crates/ra_hir_ty/src/tests/simple.rs | 2 + 5 files changed, 104 insertions(+), 3 deletions(-) diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs index baed6225b0..86acd27f8d 100644 --- a/crates/ra_hir_ty/src/infer/pat.rs +++ b/crates/ra_hir_ty/src/infer/pat.rs @@ -11,7 +11,7 @@ use hir_def::{ use hir_expand::name::Name; use test_utils::tested_by; -use super::{BindingMode, InferenceContext}; +use super::{BindingMode, Expectation, InferenceContext}; use crate::{utils::variant_data, Substs, Ty, TypeCtor}; impl<'a> InferenceContext<'a> { @@ -198,7 +198,14 @@ impl<'a> InferenceContext<'a> { Ty::apply_one(container_ty, elem_ty) } - _ => Ty::Unknown, + Pat::Wild => expected.clone(), + Pat::Range { start, end } => { + let start_ty = self.infer_expr(*start, &Expectation::has_type(expected.clone())); + let end_ty = self.infer_expr(*end, &Expectation::has_type(start_ty)); + end_ty + } + Pat::Lit(expr) => self.infer_expr(*expr, &Expectation::has_type(expected.clone())), + Pat::Missing => Ty::Unknown, }; // use a new type variable if we got Ty::Unknown here let ty = self.insert_type_vars_shallow(ty); diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index 1e303f5ce4..3e3d55c041 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs @@ -275,12 +275,14 @@ fn test(i: i32) { [70; 147) 'match ... }': &[i32] [76; 77) 'i': i32 [88; 89) '2': i32 + [88; 89) '2': i32 [93; 96) 'foo': fn foo(&[i32]) -> &[i32] [93; 102) 'foo(&[2])': &[i32] [97; 101) '&[2]': &[i32; _] [98; 101) '[2]': [i32; _] [99; 100) '2': i32 [112; 113) '1': i32 + [112; 113) '1': i32 [117; 121) '&[1]': &[i32; _] [118; 121) '[1]': [i32; _] [119; 120) '1': i32 @@ -316,10 +318,12 @@ fn test(i: i32) { [70; 147) 'match ... }': &[i32] [76; 77) 'i': i32 [88; 89) '1': i32 + [88; 89) '1': i32 [93; 97) '&[1]': &[i32; _] [94; 97) '[1]': [i32; _] [95; 96) '1': i32 [107; 108) '2': i32 + [107; 108) '2': i32 [112; 115) 'foo': fn foo(&[i32]) -> &[i32] [112; 121) 'foo(&[2])': &[i32] [116; 120) '&[2]': &[i32; _] @@ -357,9 +361,11 @@ fn test() { [45; 142) 'match ... }': *const i32 [51; 52) '1': i32 [63; 64) '1': i32 + [63; 64) '1': i32 [68; 69) 't': &mut i32 [68; 81) 't as *mut i32': *mut i32 [91; 92) '2': i32 + [91; 92) '2': i32 [96; 97) 't': &mut i32 [96; 105) 't as &i32': &i32 [115; 116) '_': i32 diff --git a/crates/ra_hir_ty/src/tests/patterns.rs b/crates/ra_hir_ty/src/tests/patterns.rs index 76aa320246..6e5d2247ca 100644 --- a/crates/ra_hir_ty/src/tests/patterns.rs +++ b/crates/ra_hir_ty/src/tests/patterns.rs @@ -81,6 +81,90 @@ fn test(x: &i32) { ); } +#[test] +fn infer_literal_pattern() { + assert_snapshot!( + infer_with_mismatches(r#" +fn any() -> T { loop {} } +fn test(x: &i32) { + if let "foo" = any() {} + if let 1 = any() {} + if let 1u32 = any() {} + if let 1f32 = any() {} + if let 1.0 = any() {} + if let true = any() {} +} +"#, true), + @r###" + [18; 29) '{ loop {} }': T + [20; 27) 'loop {}': ! + [25; 27) '{}': () + [38; 39) 'x': &i32 + [47; 209) '{ ...) {} }': () + [53; 76) 'if let...y() {}': () + [60; 65) '"foo"': &str + [60; 65) '"foo"': &str + [68; 71) 'any': fn any<&str>() -> &str + [68; 73) 'any()': &str + [74; 76) '{}': () + [81; 100) 'if let...y() {}': () + [88; 89) '1': i32 + [88; 89) '1': i32 + [92; 95) 'any': fn any() -> i32 + [92; 97) 'any()': i32 + [98; 100) '{}': () + [105; 127) 'if let...y() {}': () + [112; 116) '1u32': u32 + [112; 116) '1u32': u32 + [119; 122) 'any': fn any() -> u32 + [119; 124) 'any()': u32 + [125; 127) '{}': () + [132; 154) 'if let...y() {}': () + [139; 143) '1f32': f32 + [139; 143) '1f32': f32 + [146; 149) 'any': fn any() -> f32 + [146; 151) 'any()': f32 + [152; 154) '{}': () + [159; 180) 'if let...y() {}': () + [166; 169) '1.0': f64 + [166; 169) '1.0': f64 + [172; 175) 'any': fn any() -> f64 + [172; 177) 'any()': f64 + [178; 180) '{}': () + [185; 207) 'if let...y() {}': () + [192; 196) 'true': bool + [192; 196) 'true': bool + [199; 202) 'any': fn any() -> bool + [199; 204) 'any()': bool + [205; 207) '{}': () + "### + ); +} + +#[test] +fn infer_range_pattern() { + assert_snapshot!( + infer_with_mismatches(r#" +fn test(x: &i32) { + if let 1..76 = 2u32 {} + if let 1..=76 = 2u32 {} +} +"#, true), + @r###" + [9; 10) 'x': &i32 + [18; 76) '{ ...2 {} }': () + [24; 46) 'if let...u32 {}': () + [31; 36) '1..76': u32 + [39; 43) '2u32': u32 + [44; 46) '{}': () + [51; 74) 'if let...u32 {}': () + [58; 64) '1..=76': u32 + [67; 71) '2u32': u32 + [72; 74) '{}': () + "### + ); +} + #[test] fn infer_pattern_match_ergonomics() { assert_snapshot!( @@ -212,6 +296,7 @@ fn test() { [59; 62) 'arr': [f64; _] [73; 81) '[1.0, a]': [f64; _] [74; 77) '1.0': f64 + [74; 77) '1.0': f64 [79; 80) 'a': f64 [85; 111) '{ ... }': () [99; 100) 'a': f64 diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs index a02e3ee051..2ee9b8f101 100644 --- a/crates/ra_hir_ty/src/tests/regression.rs +++ b/crates/ra_hir_ty/src/tests/regression.rs @@ -206,7 +206,8 @@ pub fn compute() { [24; 106) 'match ... }': () [30; 37) 'nope!()': {unknown} [48; 94) 'SizeSk...tail }': {unknown} - [82; 86) 'true': {unknown} + [82; 86) 'true': bool + [82; 86) 'true': bool [88; 92) 'tail': {unknown} [98; 100) '{}': () "### diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index c140bd5130..a600b947d0 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs @@ -948,6 +948,7 @@ fn foo() { [165; 247) 'match ... }': i32 [171; 175) 'true': bool [186; 190) 'true': bool + [186; 190) 'true': bool [194; 195) '3': i32 [205; 206) '_': bool [210; 241) '{ ... }': ! @@ -956,6 +957,7 @@ fn foo() { [263; 320) 'match ... }': i32 [269; 273) 'true': bool [284; 288) 'true': bool + [284; 288) 'true': bool [292; 293) '4': i32 [303; 304) '_': bool [308; 314) 'return': !