From 7bb279b365e54ee0051e09ead5aa157ff6be917b Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 6 Jan 2019 19:51:42 +0100 Subject: Implement autoderef for field accesses --- crates/ra_hir/src/ty/autoderef.rs | 21 +++++++++++ crates/ra_hir/src/ty/tests.rs | 33 ++++++++++++++++- .../ra_hir/src/ty/tests/data/field_autoderef.txt | 43 ++++++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 crates/ra_hir/src/ty/autoderef.rs create mode 100644 crates/ra_hir/src/ty/tests/data/field_autoderef.txt (limited to 'crates/ra_hir/src/ty') 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 @@ +//! In certain situations, rust automatically inserts derefs as necessary: For +//! example, field accesses `foo.bar` still work when `foo` is actually a +//! reference to a type with the field `bar`. This is an approximation of the +//! logic in rustc (which lives in librustc_typeck/check/autoderef.rs). + +use ra_syntax::algo::generate; + +use crate::HirDatabase; +use super::Ty; + +impl Ty { + /// Iterates over the possible derefs of `ty`. + pub fn autoderef<'a>(self, db: &'a impl HirDatabase) -> impl Iterator + 'a { + generate(Some(self), move |ty| ty.autoderef_step(db)) + } + + fn autoderef_step(&self, _db: &impl HirDatabase) -> Option { + // TODO Deref::deref + self.builtin_deref() + } +} 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() { } #[test] -fn infer_refs_and_ptrs() { +fn infer_refs() { check_inference( r#" fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { @@ -180,6 +180,37 @@ fn test() { ); } +#[test] +fn infer_field_autoderef() { + check_inference( + r#" +struct A { + b: B, +} +struct B; + +fn test1(a: A) { + let a1 = a; + a1.b; + let a2 = &a; + a2.b; + let a3 = &mut a; + a3.b; + let a4 = &&&&&&&a; + a4.b; + let a5 = &mut &&mut &&mut a; + a5.b; +} + +fn test2(a1: *const A, a2: *mut A) { + a1.b; + a2.b; +} +"#, + "field_autoderef.txt", + ); +} + fn infer(content: &str) -> String { let (db, _, file_id) = MockDatabase::with_single_file(content); 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 @@ +[44; 45) 'a': A +[50; 213) '{ ...5.b; }': () +[60; 62) 'a1': A +[65; 66) 'a': A +[72; 74) 'a1': A +[72; 76) 'a1.b': B +[86; 88) 'a2': &A +[91; 93) '&a': &A +[92; 93) 'a': A +[99; 101) 'a2': &A +[99; 103) 'a2.b': B +[113; 115) 'a3': &mut A +[118; 124) '&mut a': &mut A +[123; 124) 'a': A +[130; 132) 'a3': &mut A +[130; 134) 'a3.b': B +[144; 146) 'a4': &&&&&&&A +[149; 157) '&&&&&&&a': &&&&&&&A +[150; 157) '&&&&&&a': &&&&&&A +[151; 157) '&&&&&a': &&&&&A +[152; 157) '&&&&a': &&&&A +[153; 157) '&&&a': &&&A +[154; 157) '&&a': &&A +[155; 157) '&a': &A +[156; 157) 'a': A +[163; 165) 'a4': &&&&&&&A +[163; 167) 'a4.b': B +[177; 179) 'a5': &mut &&mut &&mut A +[182; 200) '&mut &...&mut a': &mut &&mut &&mut A +[187; 200) '&&mut &&mut a': &&mut &&mut A +[188; 200) '&mut &&mut a': &mut &&mut A +[193; 200) '&&mut a': &&mut A +[194; 200) '&mut a': &mut A +[199; 200) 'a': A +[206; 208) 'a5': &mut &&mut &&mut A +[206; 210) 'a5.b': B +[224; 226) 'a1': *const A +[238; 240) 'a2': *mut A +[250; 273) '{ ...2.b; }': () +[256; 258) 'a1': *const A +[256; 260) 'a1.b': B +[266; 268) 'a2': *mut A +[266; 270) 'a2.b': B -- cgit v1.2.3