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.rs154
1 files changed, 72 insertions, 82 deletions
diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs
index dff3449098..049afa8227 100644
--- a/crates/hir-def/src/body/lower.rs
+++ b/crates/hir-def/src/body/lower.rs
@@ -13,7 +13,6 @@ use hir_expand::{
use la_arena::Arena;
use profile::Count;
use rustc_hash::FxHashMap;
-use smallvec::smallvec;
use syntax::{
ast::{
self, ArrayExprKind, AstChildren, HasArgList, HasLoopBody, HasName, LiteralKind,
@@ -97,7 +96,6 @@ pub(super) fn lower(
or_pats: Default::default(),
},
expander,
- statements_in_scope: Vec::new(),
name_to_pat_grouping: Default::default(),
is_lowering_inside_or_pat: false,
}
@@ -109,7 +107,6 @@ struct ExprCollector<'a> {
expander: Expander,
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,
@@ -514,27 +511,25 @@ impl ExprCollector<'_> {
ast::Expr::MacroExpr(e) => {
let e = e.macro_call()?;
let macro_ptr = AstPtr::new(&e);
- let id = self.collect_macro_call(e, macro_ptr.clone(), true, |this, expansion| {
+ let id = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
expansion.map(|it| this.collect_expr(it))
});
match id {
Some(id) => {
- self.source_map
- .macro_call_to_exprs
- .insert(self.expander.to_source(macro_ptr), smallvec![id]);
+ // Make the macro-call point to its expanded expression so we can query
+ // semantics on syntax pointers to the macro
+ let src = self.expander.to_source(syntax_ptr);
+ self.source_map.expr_map.insert(src, id);
id
}
- None => self.alloc_expr(Expr::Missing, syntax_ptr.clone()),
+ None => self.alloc_expr(Expr::Missing, syntax_ptr),
}
}
ast::Expr::MacroStmts(e) => {
- e.statements().for_each(|s| self.collect_stmt(s));
- let tail = e
- .expr()
- .map(|e| self.collect_expr(e))
- .unwrap_or_else(|| self.alloc_expr(Expr::Missing, syntax_ptr.clone()));
+ let statements = e.statements().filter_map(|s| self.collect_stmt(s)).collect();
+ let tail = e.expr().map(|e| self.collect_expr(e));
- self.alloc_expr(Expr::MacroStmts { tail }, syntax_ptr)
+ self.alloc_expr(Expr::MacroStmts { tail, statements }, syntax_ptr)
}
ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
})
@@ -607,11 +602,11 @@ impl ExprCollector<'_> {
}
}
- fn collect_stmt(&mut self, s: ast::Stmt) {
+ fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Statement> {
match s {
ast::Stmt::LetStmt(stmt) => {
if self.check_cfg(&stmt).is_none() {
- return;
+ return None;
}
let pat = self.collect_pat_opt(stmt.pat());
let type_ref =
@@ -621,70 +616,61 @@ impl ExprCollector<'_> {
.let_else()
.and_then(|let_else| let_else.block_expr())
.map(|block| self.collect_block(block));
- self.statements_in_scope.push(Statement::Let {
- pat,
- type_ref,
- initializer,
- else_branch,
- });
+ Some(Statement::Let { pat, type_ref, initializer, else_branch })
}
ast::Stmt::ExprStmt(stmt) => {
- if let Some(expr) = stmt.expr() {
- if self.check_cfg(&expr).is_none() {
- return;
+ let expr = stmt.expr();
+ if let Some(expr) = &expr {
+ if self.check_cfg(expr).is_none() {
+ return None;
}
}
let has_semi = stmt.semicolon_token().is_some();
- // Note that macro could be expended to multiple statements
- if let Some(ast::Expr::MacroExpr(e)) = stmt.expr() {
- let m = match e.macro_call() {
- Some(it) => it,
- None => return,
- };
- let macro_ptr = AstPtr::new(&m);
- let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
-
- let prev_stmt = self.statements_in_scope.len();
- self.collect_macro_call(m, macro_ptr.clone(), false, |this, expansion| {
- match expansion {
+ // Note that macro could be expanded to multiple statements
+ if let Some(expr @ ast::Expr::MacroExpr(mac)) = &expr {
+ let mac_call = mac.macro_call()?;
+ let syntax_ptr = AstPtr::new(expr);
+ let macro_ptr = AstPtr::new(&mac_call);
+ let stmt = self.collect_macro_call(
+ mac_call,
+ macro_ptr,
+ false,
+ |this, expansion: Option<ast::MacroStmts>| match expansion {
Some(expansion) => {
- let statements: ast::MacroStmts = expansion;
-
- statements.statements().for_each(|stmt| this.collect_stmt(stmt));
- if let Some(expr) = statements.expr() {
- let expr = this.collect_expr(expr);
- this.statements_in_scope
- .push(Statement::Expr { expr, has_semi });
- }
+ let statements = expansion
+ .statements()
+ .filter_map(|stmt| this.collect_stmt(stmt))
+ .collect();
+ let tail = expansion.expr().map(|expr| this.collect_expr(expr));
+
+ let mac_stmts = this.alloc_expr(
+ Expr::MacroStmts { tail, statements },
+ AstPtr::new(&ast::Expr::MacroStmts(expansion)),
+ );
+
+ Some(mac_stmts)
}
- None => {
- let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
- this.statements_in_scope.push(Statement::Expr { expr, has_semi });
- }
- }
- });
+ None => None,
+ },
+ );
- let mut macro_exprs = smallvec![];
- for stmt in &self.statements_in_scope[prev_stmt..] {
- match *stmt {
- Statement::Let { initializer, else_branch, .. } => {
- macro_exprs.extend(initializer);
- macro_exprs.extend(else_branch);
- }
- Statement::Expr { expr, .. } => macro_exprs.push(expr),
+ let expr = match stmt {
+ Some(expr) => {
+ // Make the macro-call point to its expanded expression so we can query
+ // semantics on syntax pointers to the macro
+ let src = self.expander.to_source(syntax_ptr);
+ self.source_map.expr_map.insert(src, expr);
+ expr
}
- }
- if !macro_exprs.is_empty() {
- self.source_map
- .macro_call_to_exprs
- .insert(self.expander.to_source(macro_ptr), macro_exprs);
- }
+ None => self.alloc_expr(Expr::Missing, syntax_ptr),
+ };
+ Some(Statement::Expr { expr, has_semi })
} else {
- let expr = self.collect_expr_opt(stmt.expr());
- self.statements_in_scope.push(Statement::Expr { expr, has_semi });
+ let expr = self.collect_expr_opt(expr);
+ Some(Statement::Expr { expr, has_semi })
}
}
- ast::Stmt::Item(_item) => {}
+ ast::Stmt::Item(_item) => None,
}
}
@@ -703,25 +689,27 @@ impl ExprCollector<'_> {
};
let prev_def_map = mem::replace(&mut self.expander.def_map, def_map);
let prev_local_module = mem::replace(&mut self.expander.module, module);
- let prev_statements = std::mem::take(&mut self.statements_in_scope);
- block.statements().for_each(|s| self.collect_stmt(s));
- block.tail_expr().and_then(|e| {
- let expr = self.maybe_collect_expr(e)?;
- self.statements_in_scope.push(Statement::Expr { expr, has_semi: false });
- Some(())
+ let mut statements: Vec<_> =
+ block.statements().filter_map(|s| self.collect_stmt(s)).collect();
+ let tail = block.tail_expr().and_then(|e| self.maybe_collect_expr(e));
+ let tail = tail.or_else(|| {
+ let stmt = statements.pop()?;
+ if let Statement::Expr { expr, has_semi: false } = stmt {
+ return Some(expr);
+ }
+ statements.push(stmt);
+ None
});
- let mut tail = None;
- if let Some(Statement::Expr { expr, has_semi: false }) = self.statements_in_scope.last() {
- tail = Some(*expr);
- self.statements_in_scope.pop();
- }
- let tail = tail;
- let statements = std::mem::replace(&mut self.statements_in_scope, prev_statements).into();
let syntax_node_ptr = AstPtr::new(&block.into());
let expr_id = self.alloc_expr(
- Expr::Block { id: block_id, statements, tail, label: None },
+ Expr::Block {
+ id: block_id,
+ statements: statements.into_boxed_slice(),
+ tail,
+ label: None,
+ },
syntax_node_ptr,
);
@@ -903,10 +891,12 @@ impl ExprCollector<'_> {
ast::Pat::MacroPat(mac) => match mac.macro_call() {
Some(call) => {
let macro_ptr = AstPtr::new(&call);
+ let src = self.expander.to_source(Either::Left(AstPtr::new(&pat)));
let pat =
self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
this.collect_pat_opt_(expanded_pat)
});
+ self.source_map.pat_map.insert(src, pat);
return pat;
}
None => Pat::Missing,