Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir_def/src/body/lower.rs')
-rw-r--r--crates/hir_def/src/body/lower.rs60
1 files changed, 47 insertions, 13 deletions
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 06ad7ce4cd..46b2ba8a25 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -12,6 +12,7 @@ use hir_expand::{
};
use la_arena::Arena;
use profile::Count;
+use rustc_hash::FxHashMap;
use syntax::{
ast::{
self, ArrayExprKind, AstChildren, HasArgList, HasLoopBody, HasName, LiteralKind,
@@ -92,9 +93,12 @@ pub(super) fn lower(
body_expr: dummy_expr_id(),
block_scopes: Vec::new(),
_c: Count::new(),
+ or_pats: Default::default(),
},
expander,
statements_in_scope: Vec::new(),
+ name_to_pat_grouping: Default::default(),
+ is_lowering_inside_or_pat: false,
}
.collect(params, body)
}
@@ -105,6 +109,9 @@ struct ExprCollector<'a> {
body: Body,
source_map: BodySourceMap,
statements_in_scope: Vec<Statement>,
+ // a poor-mans union-find?
+ name_to_pat_grouping: FxHashMap<Name, Vec<PatId>>,
+ is_lowering_inside_or_pat: bool,
}
impl ExprCollector<'_> {
@@ -704,13 +711,32 @@ impl ExprCollector<'_> {
}
fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
+ let pat_id = self.collect_pat_(pat);
+ for (_, pats) in self.name_to_pat_grouping.drain() {
+ let pats = Arc::<[_]>::from(pats);
+ self.body.or_pats.extend(pats.iter().map(|&pat| (pat, pats.clone())));
+ }
+ self.is_lowering_inside_or_pat = false;
+ pat_id
+ }
+
+ fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
+ match pat {
+ Some(pat) => self.collect_pat(pat),
+ None => self.missing_pat(),
+ }
+ }
+
+ fn collect_pat_(&mut self, pat: ast::Pat) -> PatId {
let pattern = match &pat {
ast::Pat::IdentPat(bp) => {
let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
+
+ let key = self.is_lowering_inside_or_pat.then(|| name.clone());
let annotation =
BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some());
- let subpat = bp.pat().map(|subpat| self.collect_pat(subpat));
- if annotation == BindingAnnotation::Unannotated && subpat.is_none() {
+ let subpat = bp.pat().map(|subpat| self.collect_pat_(subpat));
+ let pattern = if annotation == BindingAnnotation::Unannotated && subpat.is_none() {
// This could also be a single-segment path pattern. To
// decide that, we need to try resolving the name.
let (resolved, _) = self.expander.def_map.resolve_path(
@@ -740,7 +766,14 @@ impl ExprCollector<'_> {
}
} else {
Pat::Bind { name, mode: annotation, subpat }
+ };
+
+ let ptr = AstPtr::new(&pat);
+ let pat = self.alloc_pat(pattern, Either::Left(ptr));
+ if let Some(key) = key {
+ self.name_to_pat_grouping.entry(key).or_default().push(pat);
}
+ return pat;
}
ast::Pat::TupleStructPat(p) => {
let path =
@@ -759,10 +792,11 @@ impl ExprCollector<'_> {
path.map(Pat::Path).unwrap_or(Pat::Missing)
}
ast::Pat::OrPat(p) => {
- let pats = p.pats().map(|p| self.collect_pat(p)).collect();
+ self.is_lowering_inside_or_pat = true;
+ let pats = p.pats().map(|p| self.collect_pat_(p)).collect();
Pat::Or(pats)
}
- ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat()),
+ ast::Pat::ParenPat(p) => return self.collect_pat_opt_(p.pat()),
ast::Pat::TuplePat(p) => {
let (args, ellipsis) = self.collect_tuple_pat(p.fields());
Pat::Tuple { args, ellipsis }
@@ -777,7 +811,7 @@ impl ExprCollector<'_> {
.fields()
.filter_map(|f| {
let ast_pat = f.pat()?;
- let pat = self.collect_pat(ast_pat);
+ let pat = self.collect_pat_(ast_pat);
let name = f.field_name()?.as_name();
Some(RecordFieldPat { name, pat })
})
@@ -796,9 +830,9 @@ impl ExprCollector<'_> {
// FIXME properly handle `RestPat`
Pat::Slice {
- prefix: prefix.into_iter().map(|p| self.collect_pat(p)).collect(),
- slice: slice.map(|p| self.collect_pat(p)),
- suffix: suffix.into_iter().map(|p| self.collect_pat(p)).collect(),
+ prefix: prefix.into_iter().map(|p| self.collect_pat_(p)).collect(),
+ slice: slice.map(|p| self.collect_pat_(p)),
+ suffix: suffix.into_iter().map(|p| self.collect_pat_(p)).collect(),
}
}
ast::Pat::LiteralPat(lit) => {
@@ -821,7 +855,7 @@ impl ExprCollector<'_> {
Pat::Missing
}
ast::Pat::BoxPat(boxpat) => {
- let inner = self.collect_pat_opt(boxpat.pat());
+ let inner = self.collect_pat_opt_(boxpat.pat());
Pat::Box { inner }
}
ast::Pat::ConstBlockPat(const_block_pat) => {
@@ -837,7 +871,7 @@ impl ExprCollector<'_> {
let macro_ptr = AstPtr::new(&call);
let mut pat = None;
self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
- pat = Some(this.collect_pat_opt(expanded_pat));
+ pat = Some(this.collect_pat_opt_(expanded_pat));
});
match pat {
@@ -854,9 +888,9 @@ impl ExprCollector<'_> {
self.alloc_pat(pattern, Either::Left(ptr))
}
- fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
+ fn collect_pat_opt_(&mut self, pat: Option<ast::Pat>) -> PatId {
match pat {
- Some(pat) => self.collect_pat(pat),
+ Some(pat) => self.collect_pat_(pat),
None => self.missing_pat(),
}
}
@@ -868,7 +902,7 @@ impl ExprCollector<'_> {
// We want to skip the `..` pattern here, since we account for it above.
let args = args
.filter(|p| !matches!(p, ast::Pat::RestPat(_)))
- .map(|p| self.collect_pat(p))
+ .map(|p| self.collect_pat_(p))
.collect();
(args, ellipsis)