diff options
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r-- | crates/ra_hir/src/ty/autoderef.rs | 21 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 33 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/field_autoderef.txt | 43 |
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 | |||
6 | use ra_syntax::algo::generate; | ||
7 | |||
8 | use crate::HirDatabase; | ||
9 | use super::Ty; | ||
10 | |||
11 | impl 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] |
98 | fn infer_refs_and_ptrs() { | 98 | fn infer_refs() { |
99 | check_inference( | 99 | check_inference( |
100 | r#" | 100 | r#" |
101 | fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { | 101 | fn 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] | ||
184 | fn infer_field_autoderef() { | ||
185 | check_inference( | ||
186 | r#" | ||
187 | struct A { | ||
188 | b: B, | ||
189 | } | ||
190 | struct B; | ||
191 | |||
192 | fn 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 | |||
205 | fn test2(a1: *const A, a2: *mut A) { | ||
206 | a1.b; | ||
207 | a2.b; | ||
208 | } | ||
209 | "#, | ||
210 | "field_autoderef.txt", | ||
211 | ); | ||
212 | } | ||
213 | |||
183 | fn infer(content: &str) -> String { | 214 | fn 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 | ||