aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r--crates/ra_hir/src/ty/primitive.rs130
-rw-r--r--crates/ra_hir/src/ty/tests.rs134
-rw-r--r--crates/ra_hir/src/ty/tests/data/0001_basics.txt13
-rw-r--r--crates/ra_hir/src/ty/tests/data/0002_let.txt7
-rw-r--r--crates/ra_hir/src/ty/tests/data/0003_paths.txt9
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 @@
1use std::fmt;
2
3#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
4pub enum IntTy {
5 Isize,
6 I8,
7 I16,
8 I32,
9 I64,
10 I128,
11}
12
13impl fmt::Debug for IntTy {
14 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
15 fmt::Display::fmt(self, f)
16 }
17}
18
19impl fmt::Display for IntTy {
20 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
21 write!(f, "{}", self.ty_to_string())
22 }
23}
24
25impl 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)]
51pub enum UintTy {
52 Usize,
53 U8,
54 U16,
55 U32,
56 U64,
57 U128,
58}
59
60impl 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
85impl fmt::Debug for UintTy {
86 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
87 fmt::Display::fmt(self, f)
88 }
89}
90
91impl 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)]
98pub enum FloatTy {
99 F32,
100 F64,
101}
102
103impl fmt::Debug for FloatTy {
104 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
105 fmt::Display::fmt(self, f)
106 }
107}
108
109impl fmt::Display for FloatTy {
110 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
111 write!(f, "{}", self.ty_to_string())
112 }
113}
114
115impl 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 @@
1use std::fmt::Write;
2use std::path::{PathBuf, Path};
3use std::fs;
4
5use ra_db::{SyntaxDatabase};
6use ra_syntax::ast::{self, AstNode};
7use test_utils::{project_dir, assert_eq_text, read_text};
8
9use 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]
21fn infer_basics() {
22 check_inference(
23 r#"
24fn 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]
39fn infer_let() {
40 check_inference(
41 r#"
42fn 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]
53fn infer_paths() {
54 check_inference(
55 r#"
56fn a() -> u32 { 1 }
57
58mod b {
59 fn c() -> u32 { 1 }
60}
61
62fn test() {
63 a();
64 b::c();
65}
66}"#,
67 "0003_paths.txt",
68 );
69}
70
71fn 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
99fn 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
114fn 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
132fn 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