summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/hir-def/src/body.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir-def/src/body.rs')
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body.rs71
1 files changed, 54 insertions, 17 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
index 8fd9255b8..b70e658ef 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
@@ -24,7 +24,9 @@ use syntax::{ast, AstPtr, SyntaxNode, SyntaxNodePtr};
use crate::{
attr::Attrs,
db::DefDatabase,
- expr::{dummy_expr_id, Expr, ExprId, Label, LabelId, Pat, PatId},
+ expr::{
+ dummy_expr_id, Binding, BindingId, Expr, ExprId, Label, LabelId, Pat, PatId, RecordFieldPat,
+ },
item_scope::BuiltinShadowMode,
macro_id_to_def_id,
nameres::DefMap,
@@ -270,7 +272,7 @@ pub struct Mark {
pub struct Body {
pub exprs: Arena<Expr>,
pub pats: Arena<Pat>,
- pub or_pats: FxHashMap<PatId, Arc<[PatId]>>,
+ pub bindings: Arena<Binding>,
pub labels: Arena<Label>,
/// The patterns for the function's parameters. While the parameter types are
/// part of the function signature, the patterns are not (they don't change
@@ -409,18 +411,6 @@ impl Body {
.map(move |&block| (block, db.block_def_map(block).expect("block ID without DefMap")))
}
- pub fn pattern_representative(&self, pat: PatId) -> PatId {
- self.or_pats.get(&pat).and_then(|pats| pats.first().copied()).unwrap_or(pat)
- }
-
- /// Retrieves all ident patterns this pattern shares the ident with.
- pub fn ident_patterns_for<'slf>(&'slf self, pat: &'slf PatId) -> &'slf [PatId] {
- match self.or_pats.get(pat) {
- Some(pats) => pats,
- None => std::slice::from_ref(pat),
- }
- }
-
pub fn pretty_print(&self, db: &dyn DefDatabase, owner: DefWithBodyId) -> String {
pretty::print_body_hir(db, self, owner)
}
@@ -435,13 +425,52 @@ impl Body {
}
fn shrink_to_fit(&mut self) {
- let Self { _c: _, body_expr: _, block_scopes, or_pats, exprs, labels, params, pats } = self;
+ let Self { _c: _, body_expr: _, block_scopes, exprs, labels, params, pats, bindings } =
+ self;
block_scopes.shrink_to_fit();
- or_pats.shrink_to_fit();
exprs.shrink_to_fit();
labels.shrink_to_fit();
params.shrink_to_fit();
pats.shrink_to_fit();
+ bindings.shrink_to_fit();
+ }
+
+ pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) {
+ self.walk_pats(pat_id, &mut |pat| {
+ if let Pat::Bind { id, .. } = pat {
+ f(*id);
+ }
+ });
+ }
+
+ pub fn walk_pats(&self, pat_id: PatId, f: &mut impl FnMut(&Pat)) {
+ let pat = &self[pat_id];
+ f(pat);
+ match pat {
+ Pat::Range { .. }
+ | Pat::Lit(..)
+ | Pat::Path(..)
+ | Pat::ConstBlock(..)
+ | Pat::Wild
+ | Pat::Missing => {}
+ &Pat::Bind { subpat, .. } => {
+ if let Some(subpat) = subpat {
+ self.walk_pats(subpat, f);
+ }
+ }
+ Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => {
+ args.iter().copied().for_each(|p| self.walk_pats(p, f));
+ }
+ Pat::Ref { pat, .. } => self.walk_pats(*pat, f),
+ Pat::Slice { prefix, slice, suffix } => {
+ let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter());
+ total_iter.copied().for_each(|p| self.walk_pats(p, f));
+ }
+ Pat::Record { args, .. } => {
+ args.iter().for_each(|RecordFieldPat { pat, .. }| self.walk_pats(*pat, f));
+ }
+ Pat::Box { inner } => self.walk_pats(*inner, f),
+ }
}
}
@@ -451,7 +480,7 @@ impl Default for Body {
body_expr: dummy_expr_id(),
exprs: Default::default(),
pats: Default::default(),
- or_pats: Default::default(),
+ bindings: Default::default(),
labels: Default::default(),
params: Default::default(),
block_scopes: Default::default(),
@@ -484,6 +513,14 @@ impl Index<LabelId> for Body {
}
}
+impl Index<BindingId> for Body {
+ type Output = Binding;
+
+ fn index(&self, b: BindingId) -> &Binding {
+ &self.bindings[b]
+ }
+}
+
// FIXME: Change `node_` prefix to something more reasonable.
// Perhaps `expr_syntax` and `expr_id`?
impl BodySourceMap {