diff options
author | Aleksey Kladov <[email protected]> | 2021-03-15 12:02:48 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2021-03-15 12:12:39 +0000 |
commit | af2366acdf1321702e54e01c88052ed5a674716c (patch) | |
tree | 5a9d98a215a2adf82dbd2d3c9b74602e0c7debf8 /crates/hir/src | |
parent | 5138baf2ac742de601f29d22fc64e386da56c4c2 (diff) |
Goto definition works for `S { a: }` case
What happens here is that we lower `: ` to a missing expression, and
then correctly record that the corresponding field expression resolves
to a specific field. Where we fail is in the mapping of syntax to this
missing expression. Doing it via `ast_field.expr()` fails, as that
expression is `None`. Instead, we go in the opposite direcition and ask
each lowered field about its source.
This works, but has wrong complexity `O(N)` and, really, the
implementation is just too complex. We need some better management of
data here.
Diffstat (limited to 'crates/hir/src')
-rw-r--r-- | crates/hir/src/source_analyzer.rs | 25 |
1 files changed, 22 insertions, 3 deletions
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index d546512cb..055a3e5d0 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs | |||
@@ -24,7 +24,7 @@ use hir_ty::{ | |||
24 | }; | 24 | }; |
25 | use syntax::{ | 25 | use syntax::{ |
26 | ast::{self, AstNode}, | 26 | ast::{self, AstNode}, |
27 | SyntaxNode, TextRange, TextSize, | 27 | AstPtr, SyntaxNode, TextRange, TextSize, |
28 | }; | 28 | }; |
29 | 29 | ||
30 | use crate::{ | 30 | use crate::{ |
@@ -161,8 +161,27 @@ impl SourceAnalyzer { | |||
161 | db: &dyn HirDatabase, | 161 | db: &dyn HirDatabase, |
162 | field: &ast::RecordExprField, | 162 | field: &ast::RecordExprField, |
163 | ) -> Option<(Field, Option<Local>)> { | 163 | ) -> Option<(Field, Option<Local>)> { |
164 | let expr = field.expr()?; | 164 | let expr_id = { |
165 | let expr_id = self.expr_id(db, &expr)?; | 165 | let record_lit = field.parent_record_lit(); |
166 | let record_lit_expr = self.expr_id(db, &ast::Expr::from(record_lit))?; | ||
167 | let body = self.body.as_ref()?; | ||
168 | let body_source_map = self.body_source_map.as_ref()?; | ||
169 | match &body[record_lit_expr] { | ||
170 | hir_def::expr::Expr::RecordLit { fields, .. } => { | ||
171 | let field_ptr = InFile::new(self.file_id, AstPtr::new(field)); | ||
172 | fields.iter().enumerate().find_map(|(i, f)| { | ||
173 | let ptr = body_source_map.field_syntax(record_lit_expr, i); | ||
174 | if ptr == field_ptr { | ||
175 | Some(f.expr) | ||
176 | } else { | ||
177 | None | ||
178 | } | ||
179 | })? | ||
180 | } | ||
181 | _ => return None, | ||
182 | } | ||
183 | }; | ||
184 | |||
166 | let local = if field.name_ref().is_some() { | 185 | let local = if field.name_ref().is_some() { |
167 | None | 186 | None |
168 | } else { | 187 | } else { |