diff options
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r-- | crates/ra_hir/src/ty/primitive.rs | 130 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 134 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/0001_basics.txt | 13 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/0002_let.txt | 7 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/0003_paths.txt | 9 |
5 files changed, 293 insertions, 0 deletions
diff --git a/crates/ra_hir/src/ty/primitive.rs b/crates/ra_hir/src/ty/primitive.rs new file mode 100644 index 000000000..ad79b17e4 --- /dev/null +++ b/crates/ra_hir/src/ty/primitive.rs | |||
@@ -0,0 +1,130 @@ | |||
1 | use std::fmt; | ||
2 | |||
3 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] | ||
4 | pub enum IntTy { | ||
5 | Isize, | ||
6 | I8, | ||
7 | I16, | ||
8 | I32, | ||
9 | I64, | ||
10 | I128, | ||
11 | } | ||
12 | |||
13 | impl fmt::Debug for IntTy { | ||
14 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
15 | fmt::Display::fmt(self, f) | ||
16 | } | ||
17 | } | ||
18 | |||
19 | impl fmt::Display for IntTy { | ||
20 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
21 | write!(f, "{}", self.ty_to_string()) | ||
22 | } | ||
23 | } | ||
24 | |||
25 | impl IntTy { | ||
26 | pub fn ty_to_string(&self) -> &'static str { | ||
27 | match *self { | ||
28 | IntTy::Isize => "isize", | ||
29 | IntTy::I8 => "i8", | ||
30 | IntTy::I16 => "i16", | ||
31 | IntTy::I32 => "i32", | ||
32 | IntTy::I64 => "i64", | ||
33 | IntTy::I128 => "i128", | ||
34 | } | ||
35 | } | ||
36 | |||
37 | pub fn from_string(s: &str) -> Option<IntTy> { | ||
38 | match s { | ||
39 | "isize" => Some(IntTy::Isize), | ||
40 | "i8" => Some(IntTy::I8), | ||
41 | "i16" => Some(IntTy::I16), | ||
42 | "i32" => Some(IntTy::I32), | ||
43 | "i64" => Some(IntTy::I64), | ||
44 | "i128" => Some(IntTy::I128), | ||
45 | _ => None, | ||
46 | } | ||
47 | } | ||
48 | } | ||
49 | |||
50 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] | ||
51 | pub enum UintTy { | ||
52 | Usize, | ||
53 | U8, | ||
54 | U16, | ||
55 | U32, | ||
56 | U64, | ||
57 | U128, | ||
58 | } | ||
59 | |||
60 | impl UintTy { | ||
61 | pub fn ty_to_string(&self) -> &'static str { | ||
62 | match *self { | ||
63 | UintTy::Usize => "usize", | ||
64 | UintTy::U8 => "u8", | ||
65 | UintTy::U16 => "u16", | ||
66 | UintTy::U32 => "u32", | ||
67 | UintTy::U64 => "u64", | ||
68 | UintTy::U128 => "u128", | ||
69 | } | ||
70 | } | ||
71 | |||
72 | pub fn from_string(s: &str) -> Option<UintTy> { | ||
73 | match s { | ||
74 | "usize" => Some(UintTy::Usize), | ||
75 | "u8" => Some(UintTy::U8), | ||
76 | "u16" => Some(UintTy::U16), | ||
77 | "u32" => Some(UintTy::U32), | ||
78 | "u64" => Some(UintTy::U64), | ||
79 | "u128" => Some(UintTy::U128), | ||
80 | _ => None, | ||
81 | } | ||
82 | } | ||
83 | } | ||
84 | |||
85 | impl fmt::Debug for UintTy { | ||
86 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
87 | fmt::Display::fmt(self, f) | ||
88 | } | ||
89 | } | ||
90 | |||
91 | impl fmt::Display for UintTy { | ||
92 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
93 | write!(f, "{}", self.ty_to_string()) | ||
94 | } | ||
95 | } | ||
96 | |||
97 | #[derive(Clone, PartialEq, Eq, Hash, Copy, PartialOrd, Ord)] | ||
98 | pub enum FloatTy { | ||
99 | F32, | ||
100 | F64, | ||
101 | } | ||
102 | |||
103 | impl fmt::Debug for FloatTy { | ||
104 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
105 | fmt::Display::fmt(self, f) | ||
106 | } | ||
107 | } | ||
108 | |||
109 | impl fmt::Display for FloatTy { | ||
110 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
111 | write!(f, "{}", self.ty_to_string()) | ||
112 | } | ||
113 | } | ||
114 | |||
115 | impl FloatTy { | ||
116 | pub fn ty_to_string(self) -> &'static str { | ||
117 | match self { | ||
118 | FloatTy::F32 => "f32", | ||
119 | FloatTy::F64 => "f64", | ||
120 | } | ||
121 | } | ||
122 | |||
123 | pub fn from_string(s: &str) -> Option<FloatTy> { | ||
124 | match s { | ||
125 | "f32" => Some(FloatTy::F32), | ||
126 | "f64" => Some(FloatTy::F64), | ||
127 | _ => None, | ||
128 | } | ||
129 | } | ||
130 | } | ||
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs new file mode 100644 index 000000000..b6c02cd80 --- /dev/null +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -0,0 +1,134 @@ | |||
1 | use std::fmt::Write; | ||
2 | use std::path::{PathBuf, Path}; | ||
3 | use std::fs; | ||
4 | |||
5 | use ra_db::{SyntaxDatabase}; | ||
6 | use ra_syntax::ast::{self, AstNode}; | ||
7 | use test_utils::{project_dir, assert_eq_text, read_text}; | ||
8 | |||
9 | use crate::{ | ||
10 | source_binder, | ||
11 | mock::MockDatabase, | ||
12 | }; | ||
13 | |||
14 | // These tests compare the inference results for all expressions in a file | ||
15 | // against snapshots of the current results. If you change something and these | ||
16 | // tests fail expectedly, you can update the comparison files by deleting them | ||
17 | // and running the tests again. Similarly, to add a new test, just write the | ||
18 | // test here in the same pattern and it will automatically write the snapshot. | ||
19 | |||
20 | #[test] | ||
21 | fn infer_basics() { | ||
22 | check_inference( | ||
23 | r#" | ||
24 | fn test(a: u32, b: isize, c: !, d: &str) { | ||
25 | a; | ||
26 | b; | ||
27 | c; | ||
28 | d; | ||
29 | 1usize; | ||
30 | 1isize; | ||
31 | "test"; | ||
32 | 1.0f32; | ||
33 | }"#, | ||
34 | "0001_basics.txt", | ||
35 | ); | ||
36 | } | ||
37 | |||
38 | #[test] | ||
39 | fn infer_let() { | ||
40 | check_inference( | ||
41 | r#" | ||
42 | fn test() { | ||
43 | let a = 1isize; | ||
44 | let b: usize = 1; | ||
45 | let c = b; | ||
46 | } | ||
47 | }"#, | ||
48 | "0002_let.txt", | ||
49 | ); | ||
50 | } | ||
51 | |||
52 | #[test] | ||
53 | fn infer_paths() { | ||
54 | check_inference( | ||
55 | r#" | ||
56 | fn a() -> u32 { 1 } | ||
57 | |||
58 | mod b { | ||
59 | fn c() -> u32 { 1 } | ||
60 | } | ||
61 | |||
62 | fn test() { | ||
63 | a(); | ||
64 | b::c(); | ||
65 | } | ||
66 | }"#, | ||
67 | "0003_paths.txt", | ||
68 | ); | ||
69 | } | ||
70 | |||
71 | fn infer(content: &str) -> String { | ||
72 | let (db, _, file_id) = MockDatabase::with_single_file(content); | ||
73 | let source_file = db.source_file(file_id); | ||
74 | let mut acc = String::new(); | ||
75 | for fn_def in source_file | ||
76 | .syntax() | ||
77 | .descendants() | ||
78 | .filter_map(ast::FnDef::cast) | ||
79 | { | ||
80 | let func = source_binder::function_from_source(&db, file_id, fn_def) | ||
81 | .unwrap() | ||
82 | .unwrap(); | ||
83 | let inference_result = func.infer(&db).unwrap(); | ||
84 | for (syntax_ptr, ty) in &inference_result.type_of { | ||
85 | let node = syntax_ptr.resolve(&source_file); | ||
86 | write!( | ||
87 | acc, | ||
88 | "{} '{}': {}\n", | ||
89 | syntax_ptr.range(), | ||
90 | ellipsize(node.text().to_string().replace("\n", " "), 15), | ||
91 | ty | ||
92 | ) | ||
93 | .unwrap(); | ||
94 | } | ||
95 | } | ||
96 | acc | ||
97 | } | ||
98 | |||
99 | fn check_inference(content: &str, data_file: impl AsRef<Path>) { | ||
100 | let data_file_path = test_data_dir().join(data_file); | ||
101 | let result = infer(content); | ||
102 | |||
103 | if !data_file_path.exists() { | ||
104 | println!("File with expected result doesn't exist, creating...\n"); | ||
105 | println!("{}\n{}", content, result); | ||
106 | fs::write(&data_file_path, &result).unwrap(); | ||
107 | panic!("File {:?} with expected result was created", data_file_path); | ||
108 | } | ||
109 | |||
110 | let expected = read_text(&data_file_path); | ||
111 | assert_eq_text!(&expected, &result); | ||
112 | } | ||
113 | |||
114 | fn ellipsize(mut text: String, max_len: usize) -> String { | ||
115 | if text.len() <= max_len { | ||
116 | return text; | ||
117 | } | ||
118 | let ellipsis = "..."; | ||
119 | let e_len = ellipsis.len(); | ||
120 | let mut prefix_len = (max_len - e_len) / 2; | ||
121 | while !text.is_char_boundary(prefix_len) { | ||
122 | prefix_len += 1; | ||
123 | } | ||
124 | let mut suffix_len = max_len - e_len - prefix_len; | ||
125 | while !text.is_char_boundary(text.len() - suffix_len) { | ||
126 | suffix_len += 1; | ||
127 | } | ||
128 | text.replace_range(prefix_len..text.len() - suffix_len, ellipsis); | ||
129 | text | ||
130 | } | ||
131 | |||
132 | fn test_data_dir() -> PathBuf { | ||
133 | project_dir().join("crates/ra_hir/src/ty/tests/data") | ||
134 | } | ||
diff --git a/crates/ra_hir/src/ty/tests/data/0001_basics.txt b/crates/ra_hir/src/ty/tests/data/0001_basics.txt new file mode 100644 index 000000000..0c46f243a --- /dev/null +++ b/crates/ra_hir/src/ty/tests/data/0001_basics.txt | |||
@@ -0,0 +1,13 @@ | |||
1 | [33; 34) 'd': [unknown] | ||
2 | [88; 94) '1isize': [unknown] | ||
3 | [48; 49) 'a': u32 | ||
4 | [55; 56) 'b': isize | ||
5 | [112; 118) '1.0f32': [unknown] | ||
6 | [76; 82) '1usize': [unknown] | ||
7 | [9; 10) 'a': u32 | ||
8 | [27; 28) 'c': ! | ||
9 | [62; 63) 'c': ! | ||
10 | [17; 18) 'b': isize | ||
11 | [100; 106) '"test"': [unknown] | ||
12 | [42; 121) '{ ...f32; }': () | ||
13 | [69; 70) 'd': [unknown] | ||
diff --git a/crates/ra_hir/src/ty/tests/data/0002_let.txt b/crates/ra_hir/src/ty/tests/data/0002_let.txt new file mode 100644 index 000000000..2d0d1f57b --- /dev/null +++ b/crates/ra_hir/src/ty/tests/data/0002_let.txt | |||
@@ -0,0 +1,7 @@ | |||
1 | [21; 22) 'a': [unknown] | ||
2 | [52; 53) '1': [unknown] | ||
3 | [11; 71) '{ ...= b; }': () | ||
4 | [63; 64) 'c': usize | ||
5 | [25; 31) '1isize': [unknown] | ||
6 | [41; 42) 'b': usize | ||
7 | [67; 68) 'b': usize | ||
diff --git a/crates/ra_hir/src/ty/tests/data/0003_paths.txt b/crates/ra_hir/src/ty/tests/data/0003_paths.txt new file mode 100644 index 000000000..dcb5456ae --- /dev/null +++ b/crates/ra_hir/src/ty/tests/data/0003_paths.txt | |||
@@ -0,0 +1,9 @@ | |||
1 | [15; 20) '{ 1 }': [unknown] | ||
2 | [17; 18) '1': [unknown] | ||
3 | [50; 51) '1': [unknown] | ||
4 | [48; 53) '{ 1 }': [unknown] | ||
5 | [82; 88) 'b::c()': u32 | ||
6 | [67; 91) '{ ...c(); }': () | ||
7 | [73; 74) 'a': fn() -> u32 | ||
8 | [73; 76) 'a()': u32 | ||
9 | [82; 86) 'b::c': fn() -> u32 | ||