-
Notifications
You must be signed in to change notification settings - Fork 13k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of #34570 - jseyfried:no_rename, r=nrc
Simplify the macro hygiene algorithm This PR removes renaming from the hygiene algorithm and treats differently marked identifiers as unequal. This change makes the scope of identifiers in `macro_rules!` items empty. That is, identifiers in `macro_rules!` definitions do not inherit any semantics from the `macro_rules!`'s scope. Since `macro_rules!` macros are items, the scope of their identifiers "should" be the same as that of other items; in particular, the scope should contain only items. Since all items are unhygienic today, this would mean the scope should be empty. However, the scope of an identifier in a `macro_rules!` statement today is the scope that the identifier would have if it replaced the `macro_rules!` (excluding anything unhygienic, i.e. locals only). To continue to support this, this PR tracks the scope of each `macro_rules!` and uses it in `resolve` to ensure that an identifier expanded from a `macro_rules!` gets a chance to resolve to the locals in the `macro_rules!`'s scope. This PR is a pure refactoring. After this PR, - `syntax::ext::expand` is much simpler. - We can expand macros in any order without causing problems for hygiene (needed for macro modularization). - We can deprecate or remove today's `macro_rules!` scope easily. - Expansion performance improves by 25%, post-expansion memory usage decreases by ~5%. - Expanding a block is no longer quadratic in the number of `let` statements (fixes #10607). r? @nrc
- Loading branch information
Showing
10 changed files
with
251 additions
and
806 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
use Resolver; | ||
use rustc::session::Session; | ||
use syntax::ast; | ||
use syntax::ext::mtwt; | ||
use syntax::fold::{self, Folder}; | ||
use syntax::ptr::P; | ||
use syntax::util::move_map::MoveMap; | ||
use syntax::util::small_vector::SmallVector; | ||
|
||
use std::collections::HashMap; | ||
use std::mem; | ||
|
||
impl<'a> Resolver<'a> { | ||
pub fn assign_node_ids(&mut self, krate: ast::Crate) -> ast::Crate { | ||
NodeIdAssigner { | ||
sess: self.session, | ||
macros_at_scope: &mut self.macros_at_scope, | ||
}.fold_crate(krate) | ||
} | ||
} | ||
|
||
struct NodeIdAssigner<'a> { | ||
sess: &'a Session, | ||
macros_at_scope: &'a mut HashMap<ast::NodeId, Vec<ast::Mrk>>, | ||
} | ||
|
||
impl<'a> Folder for NodeIdAssigner<'a> { | ||
fn new_id(&mut self, old_id: ast::NodeId) -> ast::NodeId { | ||
assert_eq!(old_id, ast::DUMMY_NODE_ID); | ||
self.sess.next_node_id() | ||
} | ||
|
||
fn fold_block(&mut self, block: P<ast::Block>) -> P<ast::Block> { | ||
block.map(|mut block| { | ||
block.id = self.new_id(block.id); | ||
|
||
let stmt = block.stmts.pop(); | ||
let mut macros = Vec::new(); | ||
block.stmts = block.stmts.move_flat_map(|stmt| { | ||
if let ast::StmtKind::Item(ref item) = stmt.node { | ||
if let ast::ItemKind::Mac(..) = item.node { | ||
macros.push(mtwt::outer_mark(item.ident.ctxt)); | ||
return None; | ||
} | ||
} | ||
|
||
let stmt = self.fold_stmt(stmt).pop().unwrap(); | ||
if !macros.is_empty() { | ||
self.macros_at_scope.insert(stmt.id, mem::replace(&mut macros, Vec::new())); | ||
} | ||
Some(stmt) | ||
}); | ||
|
||
stmt.and_then(|mut stmt| { | ||
// Avoid wasting a node id on a trailing expression statement, | ||
// which shares a HIR node with the expression itself. | ||
if let ast::StmtKind::Expr(expr) = stmt.node { | ||
let expr = self.fold_expr(expr); | ||
stmt.id = expr.id; | ||
stmt.node = ast::StmtKind::Expr(expr); | ||
Some(stmt) | ||
} else { | ||
self.fold_stmt(stmt).pop() | ||
} | ||
}).map(|stmt| { | ||
if !macros.is_empty() { | ||
self.macros_at_scope.insert(stmt.id, mem::replace(&mut macros, Vec::new())); | ||
} | ||
block.stmts.push(stmt); | ||
}); | ||
|
||
block | ||
}) | ||
} | ||
|
||
fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> { | ||
match item.node { | ||
ast::ItemKind::Mac(..) => SmallVector::zero(), | ||
_ => fold::noop_fold_item(item, self), | ||
} | ||
} | ||
} |
Oops, something went wrong.