Skip to content

Commit fc5912b

Browse files
Store patterns desugared from destructuring assignments in source map
And few more fixups. I was worried this will lead to more memory usage since `ExprOrPatId` is double the size of `ExprId`, but this does not regress `analysis-stats .`. If this turns out to be a problem, we can easily use the high bit to encode this information.
1 parent b4f0403 commit fc5912b

File tree

16 files changed

+280
-174
lines changed

16 files changed

+280
-174
lines changed

src/tools/rust-analyzer/crates/hir-def/src/body.rs

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use std::ops::{Deref, Index};
1010

1111
use base_db::CrateId;
1212
use cfg::{CfgExpr, CfgOptions};
13+
use either::Either;
1314
use hir_expand::{name::Name, ExpandError, InFile};
1415
use la_arena::{Arena, ArenaMap, Idx, RawIdx};
1516
use rustc_hash::FxHashMap;
@@ -22,8 +23,8 @@ use crate::{
2223
db::DefDatabase,
2324
expander::Expander,
2425
hir::{
25-
dummy_expr_id, Array, AsmOperand, Binding, BindingId, Expr, ExprId, Label, LabelId, Pat,
26-
PatId, RecordFieldPat, Statement,
26+
dummy_expr_id, Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, Label,
27+
LabelId, Pat, PatId, RecordFieldPat, Statement,
2728
},
2829
item_tree::AttrOwner,
2930
nameres::DefMap,
@@ -68,9 +69,12 @@ pub type LabelSource = InFile<LabelPtr>;
6869
pub type FieldPtr = AstPtr<ast::RecordExprField>;
6970
pub type FieldSource = InFile<FieldPtr>;
7071

71-
pub type PatFieldPtr = AstPtr<ast::RecordPatField>;
72+
pub type PatFieldPtr = AstPtr<Either<ast::RecordExprField, ast::RecordPatField>>;
7273
pub type PatFieldSource = InFile<PatFieldPtr>;
7374

75+
pub type ExprOrPatPtr = AstPtr<Either<ast::Expr, ast::Pat>>;
76+
pub type ExprOrPatSource = InFile<ExprOrPatPtr>;
77+
7478
/// An item body together with the mapping from syntax nodes to HIR expression
7579
/// IDs. This is needed to go from e.g. a position in a file to the HIR
7680
/// expression containing it; but for type inference etc., we want to operate on
@@ -84,11 +88,13 @@ pub type PatFieldSource = InFile<PatFieldPtr>;
8488
/// this properly for macros.
8589
#[derive(Default, Debug, Eq, PartialEq)]
8690
pub struct BodySourceMap {
87-
expr_map: FxHashMap<ExprSource, ExprId>,
91+
// AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map
92+
// to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected).
93+
expr_map: FxHashMap<ExprSource, ExprOrPatId>,
8894
expr_map_back: ArenaMap<ExprId, ExprSource>,
8995

9096
pat_map: FxHashMap<PatSource, PatId>,
91-
pat_map_back: ArenaMap<PatId, PatSource>,
97+
pat_map_back: ArenaMap<PatId, ExprOrPatSource>,
9298

9399
label_map: FxHashMap<LabelSource, LabelId>,
94100
label_map_back: ArenaMap<LabelId, LabelSource>,
@@ -372,7 +378,7 @@ impl Body {
372378
if let &Some(expr) = else_branch {
373379
f(expr);
374380
}
375-
walk_exprs_in_pat(self, *pat, &mut f);
381+
self.walk_exprs_in_pat(*pat, &mut f);
376382
}
377383
Statement::Expr { expr: expression, .. } => f(*expression),
378384
Statement::Item => (),
@@ -448,18 +454,18 @@ impl Body {
448454
}
449455
},
450456
&Expr::Assignment { target, value } => {
451-
walk_exprs_in_pat(self, target, &mut f);
457+
self.walk_exprs_in_pat(target, &mut f);
452458
f(value);
453459
}
454460
}
461+
}
455462

456-
fn walk_exprs_in_pat(this: &Body, pat_id: PatId, f: &mut impl FnMut(ExprId)) {
457-
this.walk_pats(pat_id, &mut |pat| {
458-
if let Pat::Expr(expr) | Pat::ConstBlock(expr) = this[pat] {
459-
f(expr);
460-
}
461-
});
462-
}
463+
pub fn walk_exprs_in_pat(&self, pat_id: PatId, f: &mut impl FnMut(ExprId)) {
464+
self.walk_pats(pat_id, &mut |pat| {
465+
if let Pat::Expr(expr) | Pat::ConstBlock(expr) = self[pat] {
466+
f(expr);
467+
}
468+
});
463469
}
464470
}
465471

@@ -514,11 +520,18 @@ impl Index<BindingId> for Body {
514520
// FIXME: Change `node_` prefix to something more reasonable.
515521
// Perhaps `expr_syntax` and `expr_id`?
516522
impl BodySourceMap {
523+
pub fn expr_or_pat_syntax(&self, id: ExprOrPatId) -> Result<ExprOrPatSource, SyntheticSyntax> {
524+
match id {
525+
ExprOrPatId::ExprId(id) => self.expr_syntax(id).map(|it| it.map(AstPtr::wrap_left)),
526+
ExprOrPatId::PatId(id) => self.pat_syntax(id),
527+
}
528+
}
529+
517530
pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> {
518531
self.expr_map_back.get(expr).cloned().ok_or(SyntheticSyntax)
519532
}
520533

521-
pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> {
534+
pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprOrPatId> {
522535
let src = node.map(AstPtr::new);
523536
self.expr_map.get(&src).cloned()
524537
}
@@ -534,7 +547,7 @@ impl BodySourceMap {
534547
self.expansions.iter().map(|(&a, &b)| (a, b))
535548
}
536549

537-
pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> {
550+
pub fn pat_syntax(&self, pat: PatId) -> Result<ExprOrPatSource, SyntheticSyntax> {
538551
self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax)
539552
}
540553

@@ -567,7 +580,7 @@ impl BodySourceMap {
567580
self.pat_field_map_back[&pat]
568581
}
569582

570-
pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroExpr>) -> Option<ExprId> {
583+
pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroExpr>) -> Option<ExprOrPatId> {
571584
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::MacroExpr>).map(AstPtr::upcast);
572585
self.expr_map.get(&src).copied()
573586
}
@@ -583,16 +596,20 @@ impl BodySourceMap {
583596
node: InFile<&ast::FormatArgsExpr>,
584597
) -> Option<&[(syntax::TextRange, Name)]> {
585598
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
586-
self.template_map.as_ref()?.0.get(self.expr_map.get(&src)?).map(std::ops::Deref::deref)
599+
self.template_map
600+
.as_ref()?
601+
.0
602+
.get(&self.expr_map.get(&src)?.as_expr()?)
603+
.map(std::ops::Deref::deref)
587604
}
588605

589606
pub fn asm_template_args(
590607
&self,
591608
node: InFile<&ast::AsmExpr>,
592609
) -> Option<(ExprId, &[Vec<(syntax::TextRange, usize)>])> {
593610
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
594-
let expr = self.expr_map.get(&src)?;
595-
Some(*expr).zip(self.template_map.as_ref()?.1.get(expr).map(std::ops::Deref::deref))
611+
let expr = self.expr_map.get(&src)?.as_expr()?;
612+
Some(expr).zip(self.template_map.as_ref()?.1.get(&expr).map(std::ops::Deref::deref))
596613
}
597614

598615
/// Get a reference to the body source map's diagnostics.

src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ impl ExprCollector<'_> {
424424
let inner = self.collect_expr_opt(e.expr());
425425
// make the paren expr point to the inner expression as well for IDE resolution
426426
let src = self.expander.in_file(syntax_ptr);
427-
self.source_map.expr_map.insert(src, inner);
427+
self.source_map.expr_map.insert(src, inner.into());
428428
inner
429429
}
430430
ast::Expr::ReturnExpr(e) => {
@@ -660,7 +660,7 @@ impl ExprCollector<'_> {
660660
// Make the macro-call point to its expanded expression so we can query
661661
// semantics on syntax pointers to the macro
662662
let src = self.expander.in_file(syntax_ptr);
663-
self.source_map.expr_map.insert(src, id);
663+
self.source_map.expr_map.insert(src, id.into());
664664
id
665665
}
666666
None => self.alloc_expr(Expr::Missing, syntax_ptr),
@@ -686,9 +686,12 @@ impl ExprCollector<'_> {
686686

687687
fn collect_expr_as_pat(&mut self, expr: ast::Expr) -> PatId {
688688
self.maybe_collect_expr_as_pat(&expr).unwrap_or_else(|| {
689-
let syntax_ptr = AstPtr::new(&expr);
689+
let src = self.expander.in_file(AstPtr::new(&expr).wrap_left());
690690
let expr = self.collect_expr(expr);
691-
self.alloc_pat_from_expr(Pat::Expr(expr), syntax_ptr)
691+
// Do not use `alloc_pat_from_expr()` here, it will override the entry in `expr_map`.
692+
let id = self.body.pats.alloc(Pat::Expr(expr));
693+
self.source_map.pat_map_back.insert(id, src);
694+
id
692695
})
693696
}
694697

@@ -743,16 +746,12 @@ impl ExprCollector<'_> {
743746
ast::Expr::MacroExpr(e) => {
744747
let e = e.macro_call()?;
745748
let macro_ptr = AstPtr::new(&e);
749+
let src = self.expander.in_file(AstPtr::new(expr));
746750
let id = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
747-
expansion.map(|it| this.collect_expr_as_pat(it))
751+
this.collect_expr_as_pat_opt(expansion)
748752
});
749-
match id {
750-
Some(id) => {
751-
// FIXME: Insert pat into source map.
752-
id
753-
}
754-
None => self.alloc_pat_from_expr(Pat::Missing, syntax_ptr),
755-
}
753+
self.source_map.expr_map.insert(src, id.into());
754+
id
756755
}
757756
ast::Expr::RecordExpr(e) => {
758757
let path =
@@ -767,9 +766,8 @@ impl ExprCollector<'_> {
767766
let field_expr = f.expr()?;
768767
let pat = self.collect_expr_as_pat(field_expr);
769768
let name = f.field_name()?.as_name();
770-
// FIXME: Enable this.
771-
// let src = self.expander.in_file(AstPtr::new(&f));
772-
// self.source_map.pat_field_map_back.insert(pat, src);
769+
let src = self.expander.in_file(AstPtr::new(&f).wrap_left());
770+
self.source_map.pat_field_map_back.insert(pat, src);
773771
Some(RecordFieldPat { name, pat })
774772
})
775773
.collect();
@@ -813,7 +811,10 @@ impl ExprCollector<'_> {
813811
None => Either::Left(this.missing_pat()),
814812
},
815813
);
816-
// FIXME: Insert pat into source map.
814+
if let Either::Left(pat) = pat {
815+
let src = this.expander.in_file(AstPtr::new(&expr).wrap_left());
816+
this.source_map.pat_map_back.insert(pat, src);
817+
}
817818
pat
818819
}
819820
None => {
@@ -1236,7 +1237,7 @@ impl ExprCollector<'_> {
12361237
// Make the macro-call point to its expanded expression so we can query
12371238
// semantics on syntax pointers to the macro
12381239
let src = self.expander.in_file(syntax_ptr);
1239-
self.source_map.expr_map.insert(src, tail);
1240+
self.source_map.expr_map.insert(src, tail.into());
12401241
})
12411242
}
12421243

@@ -1500,7 +1501,7 @@ impl ExprCollector<'_> {
15001501
let ast_pat = f.pat()?;
15011502
let pat = self.collect_pat(ast_pat, binding_list);
15021503
let name = f.field_name()?.as_name();
1503-
let src = self.expander.in_file(AstPtr::new(&f));
1504+
let src = self.expander.in_file(AstPtr::new(&f).wrap_right());
15041505
self.source_map.pat_field_map_back.insert(pat, src);
15051506
Some(RecordFieldPat { name, pat })
15061507
})
@@ -2187,7 +2188,7 @@ impl ExprCollector<'_> {
21872188
let src = self.expander.in_file(ptr);
21882189
let id = self.body.exprs.alloc(expr);
21892190
self.source_map.expr_map_back.insert(id, src);
2190-
self.source_map.expr_map.insert(src, id);
2191+
self.source_map.expr_map.insert(src, id.into());
21912192
id
21922193
}
21932194
// FIXME: desugared exprs don't have ptr, that's wrong and should be fixed.
@@ -2215,14 +2216,17 @@ impl ExprCollector<'_> {
22152216
binding
22162217
}
22172218

2218-
fn alloc_pat_from_expr(&mut self, pat: Pat, _ptr: ExprPtr) -> PatId {
2219-
// FIXME: Insert into source map.
2220-
self.body.pats.alloc(pat)
2219+
fn alloc_pat_from_expr(&mut self, pat: Pat, ptr: ExprPtr) -> PatId {
2220+
let src = self.expander.in_file(ptr);
2221+
let id = self.body.pats.alloc(pat);
2222+
self.source_map.expr_map.insert(src, id.into());
2223+
self.source_map.pat_map_back.insert(id, src.map(AstPtr::wrap_left));
2224+
id
22212225
}
22222226
fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
22232227
let src = self.expander.in_file(ptr);
22242228
let id = self.body.pats.alloc(pat);
2225-
self.source_map.pat_map_back.insert(id, src);
2229+
self.source_map.pat_map_back.insert(id, src.map(AstPtr::wrap_right));
22262230
self.source_map.pat_map.insert(src, id);
22272231
id
22282232
}

src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,8 @@ mod tests {
333333

334334
let expr_id = source_map
335335
.node_expr(InFile { file_id: file_id.into(), value: &marker.into() })
336+
.unwrap()
337+
.as_expr()
336338
.unwrap();
337339
let scope = scopes.scope_for(expr_id);
338340

@@ -488,8 +490,11 @@ fn foo() {
488490

489491
let expr_scope = {
490492
let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap();
491-
let expr_id =
492-
source_map.node_expr(InFile { file_id: file_id.into(), value: &expr_ast }).unwrap();
493+
let expr_id = source_map
494+
.node_expr(InFile { file_id: file_id.into(), value: &expr_ast })
495+
.unwrap()
496+
.as_expr()
497+
.unwrap();
493498
scopes.scope_for(expr_id).unwrap()
494499
};
495500

src/tools/rust-analyzer/crates/hir-def/src/hir.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,22 @@ pub enum ExprOrPatId {
4848
ExprId(ExprId),
4949
PatId(PatId),
5050
}
51+
52+
impl ExprOrPatId {
53+
pub fn as_expr(self) -> Option<ExprId> {
54+
match self {
55+
Self::ExprId(v) => Some(v),
56+
_ => None,
57+
}
58+
}
59+
60+
pub fn as_pat(self) -> Option<PatId> {
61+
match self {
62+
Self::PatId(v) => Some(v),
63+
_ => None,
64+
}
65+
}
66+
}
5167
stdx::impl_from!(ExprId, PatId for ExprOrPatId);
5268

5369
#[derive(Debug, Clone, Eq, PartialEq)]

src/tools/rust-analyzer/crates/hir-def/src/test_db.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,10 @@ impl TestDB {
198198
.filter_map(|node| {
199199
let block = ast::BlockExpr::cast(node)?;
200200
let expr = ast::Expr::from(block);
201-
let expr_id = source_map.node_expr(InFile::new(position.file_id.into(), &expr))?;
201+
let expr_id = source_map
202+
.node_expr(InFile::new(position.file_id.into(), &expr))?
203+
.as_expr()
204+
.unwrap();
202205
let scope = scopes.scope_for(expr_id).unwrap();
203206
Some(scope)
204207
});

0 commit comments

Comments
 (0)