aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty/tests.rs
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2018-12-24 14:40:11 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2018-12-24 14:40:11 +0000
commit67e768466ff2e2611eead0f30b2e9c4083c80c20 (patch)
tree8984028019837c91131fc30f60eecf8c2a457368 /crates/ra_hir/src/ty/tests.rs
parentabe09eb5edfe8f4c58baa16140acbd414635836f (diff)
parent4befde1eee5b1e2b7ddc9bf764b77f82b792c318 (diff)
Merge #327
327: Beginnings of type inference r=flodiebold a=flodiebold I was a bit bored, so I thought I'd try to start implementing the type system and see how far I come :wink: This is obviously still extremely WIP, only very basic stuff working, but I thought I'd post this now to get some feedback as to whether this approach makes sense at all. There's no user-visible effect yet, but the type inference has tests similar to the ones for the parser. My next step will probably be to implement struct types, after which this could probably be used to complete fields. I realize this may all get thrown away when/if the compiler query system gets usable, but I feel like there are lots of IDE features that could be implemented with somewhat working type inference in the meantime :smile: Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/ty/tests.rs')
-rw-r--r--crates/ra_hir/src/ty/tests.rs134
1 files changed, 134 insertions, 0 deletions
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}