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/autoderef.rs21
-rw-r--r--crates/ra_hir/src/ty/tests.rs33
-rw-r--r--crates/ra_hir/src/ty/tests/data/field_autoderef.txt43
3 files changed, 96 insertions, 1 deletions
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs
new file mode 100644
index 000000000..24a386558
--- /dev/null
+++ b/crates/ra_hir/src/ty/autoderef.rs
@@ -0,0 +1,21 @@
1//! In certain situations, rust automatically inserts derefs as necessary: For
2//! example, field accesses `foo.bar` still work when `foo` is actually a
3//! reference to a type with the field `bar`. This is an approximation of the
4//! logic in rustc (which lives in librustc_typeck/check/autoderef.rs).
5
6use ra_syntax::algo::generate;
7
8use crate::HirDatabase;
9use super::Ty;
10
11impl Ty {
12 /// Iterates over the possible derefs of `ty`.
13 pub fn autoderef<'a>(self, db: &'a impl HirDatabase) -> impl Iterator<Item = Ty> + 'a {
14 generate(Some(self), move |ty| ty.autoderef_step(db))
15 }
16
17 fn autoderef_step(&self, _db: &impl HirDatabase) -> Option<Ty> {
18 // TODO Deref::deref
19 self.builtin_deref()
20 }
21}
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 83aedaa00..e6c7e225b 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -95,7 +95,7 @@ fn test() {
95} 95}
96 96
97#[test] 97#[test]
98fn infer_refs_and_ptrs() { 98fn infer_refs() {
99 check_inference( 99 check_inference(
100 r#" 100 r#"
101fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { 101fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
@@ -180,6 +180,37 @@ fn test() {
180 ); 180 );
181} 181}
182 182
183#[test]
184fn infer_field_autoderef() {
185 check_inference(
186 r#"
187struct A {
188 b: B,
189}
190struct B;
191
192fn test1(a: A) {
193 let a1 = a;
194 a1.b;
195 let a2 = &a;
196 a2.b;
197 let a3 = &mut a;
198 a3.b;
199 let a4 = &&&&&&&a;
200 a4.b;
201 let a5 = &mut &&mut &&mut a;
202 a5.b;
203}
204
205fn test2(a1: *const A, a2: *mut A) {
206 a1.b;
207 a2.b;
208}
209"#,
210 "field_autoderef.txt",
211 );
212}
213
183fn infer(content: &str) -> String { 214fn infer(content: &str) -> String {
184 let (db, _, file_id) = MockDatabase::with_single_file(content); 215 let (db, _, file_id) = MockDatabase::with_single_file(content);
185 let source_file = db.source_file(file_id); 216 let source_file = db.source_file(file_id);
diff --git a/crates/ra_hir/src/ty/tests/data/field_autoderef.txt b/crates/ra_hir/src/ty/tests/data/field_autoderef.txt
new file mode 100644
index 000000000..e1db1db40
--- /dev/null
+++ b/crates/ra_hir/src/ty/tests/data/field_autoderef.txt
@@ -0,0 +1,43 @@
1[44; 45) 'a': A
2[50; 213) '{ ...5.b; }': ()
3[60; 62) 'a1': A
4[65; 66) 'a': A
5[72; 74) 'a1': A
6[72; 76) 'a1.b': B
7[86; 88) 'a2': &A
8[91; 93) '&a': &A
9[92; 93) 'a': A
10[99; 101) 'a2': &A
11[99; 103) 'a2.b': B
12[113; 115) 'a3': &mut A
13[118; 124) '&mut a': &mut A
14[123; 124) 'a': A
15[130; 132) 'a3': &mut A
16[130; 134) 'a3.b': B
17[144; 146) 'a4': &&&&&&&A
18[149; 157) '&&&&&&&a': &&&&&&&A
19[150; 157) '&&&&&&a': &&&&&&A
20[151; 157) '&&&&&a': &&&&&A
21[152; 157) '&&&&a': &&&&A
22[153; 157) '&&&a': &&&A
23[154; 157) '&&a': &&A
24[155; 157) '&a': &A
25[156; 157) 'a': A
26[163; 165) 'a4': &&&&&&&A
27[163; 167) 'a4.b': B
28[177; 179) 'a5': &mut &&mut &&mut A
29[182; 200) '&mut &...&mut a': &mut &&mut &&mut A
30[187; 200) '&&mut &&mut a': &&mut &&mut A
31[188; 200) '&mut &&mut a': &mut &&mut A
32[193; 200) '&&mut a': &&mut A
33[194; 200) '&mut a': &mut A
34[199; 200) 'a': A
35[206; 208) 'a5': &mut &&mut &&mut A
36[206; 210) 'a5.b': B
37[224; 226) 'a1': *const A
38[238; 240) 'a2': *mut A
39[250; 273) '{ ...2.b; }': ()
40[256; 258) 'a1': *const A
41[256; 260) 'a1.b': B
42[266; 268) 'a2': *mut A
43[266; 270) 'a2.b': B