Skip to content

Commit 4db1874

Browse files
authored
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
2 parents 3cc3ad1 + c1a6ff2 commit 4db1874

File tree

10 files changed

+251
-806
lines changed

10 files changed

+251
-806
lines changed

src/librustc_driver/driver.rs

+13-57
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ use std::io::{self, Write};
5050
use std::path::{Path, PathBuf};
5151
use syntax::{ast, diagnostics, visit};
5252
use syntax::attr::{self, AttrMetaMethods};
53-
use syntax::fold::Folder;
5453
use syntax::parse::{self, PResult, token};
5554
use syntax::util::node_count::NodeCounter;
5655
use syntax;
@@ -695,6 +694,19 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
695694
sess.diagnostic())
696695
});
697696

697+
let resolver_arenas = Resolver::arenas();
698+
let mut resolver = Resolver::new(sess, make_glob_map, &resolver_arenas);
699+
700+
let krate = time(sess.time_passes(), "assigning node ids", || resolver.assign_node_ids(krate));
701+
702+
if sess.opts.debugging_opts.input_stats {
703+
println!("Post-expansion node count: {}", count_nodes(&krate));
704+
}
705+
706+
if sess.opts.debugging_opts.ast_json {
707+
println!("{}", json::as_json(&krate));
708+
}
709+
698710
time(time_passes,
699711
"checking for inline asm in case the target doesn't support it",
700712
|| no_asm::check_crate(sess, &krate));
@@ -710,15 +722,6 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
710722
})
711723
})?;
712724

713-
if sess.opts.debugging_opts.input_stats {
714-
println!("Post-expansion node count: {}", count_nodes(&krate));
715-
}
716-
717-
krate = assign_node_ids(sess, krate);
718-
719-
let resolver_arenas = Resolver::arenas();
720-
let mut resolver = Resolver::new(sess, make_glob_map, &resolver_arenas);
721-
722725
// Collect defintions for def ids.
723726
time(sess.time_passes(), "collecting defs", || resolver.definitions.collect(&krate));
724727

@@ -783,53 +786,6 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
783786
})
784787
}
785788

786-
pub fn assign_node_ids(sess: &Session, krate: ast::Crate) -> ast::Crate {
787-
use syntax::ptr::P;
788-
use syntax::util::move_map::MoveMap;
789-
790-
struct NodeIdAssigner<'a> {
791-
sess: &'a Session,
792-
}
793-
794-
impl<'a> Folder for NodeIdAssigner<'a> {
795-
fn new_id(&mut self, old_id: ast::NodeId) -> ast::NodeId {
796-
assert_eq!(old_id, ast::DUMMY_NODE_ID);
797-
self.sess.next_node_id()
798-
}
799-
800-
fn fold_block(&mut self, block: P<ast::Block>) -> P<ast::Block> {
801-
block.map(|mut block| {
802-
block.id = self.new_id(block.id);
803-
804-
let stmt = block.stmts.pop();
805-
block.stmts = block.stmts.move_flat_map(|s| self.fold_stmt(s).into_iter());
806-
if let Some(ast::Stmt { node: ast::StmtKind::Expr(expr), span, .. }) = stmt {
807-
let expr = self.fold_expr(expr);
808-
block.stmts.push(ast::Stmt {
809-
id: expr.id,
810-
node: ast::StmtKind::Expr(expr),
811-
span: span,
812-
});
813-
} else if let Some(stmt) = stmt {
814-
block.stmts.extend(self.fold_stmt(stmt));
815-
}
816-
817-
block
818-
})
819-
}
820-
}
821-
822-
let krate = time(sess.time_passes(),
823-
"assigning node ids",
824-
|| NodeIdAssigner { sess: sess }.fold_crate(krate));
825-
826-
if sess.opts.debugging_opts.ast_json {
827-
println!("{}", json::as_json(&krate));
828-
}
829-
830-
krate
831-
}
832-
833789
/// Run the resolution, typechecking, region checking and other
834790
/// miscellaneous analysis passes on the crate. Return various
835791
/// structures carrying the results of the analysis.

src/librustc_resolve/assign_ids.rs

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use Resolver;
12+
use rustc::session::Session;
13+
use syntax::ast;
14+
use syntax::ext::mtwt;
15+
use syntax::fold::{self, Folder};
16+
use syntax::ptr::P;
17+
use syntax::util::move_map::MoveMap;
18+
use syntax::util::small_vector::SmallVector;
19+
20+
use std::collections::HashMap;
21+
use std::mem;
22+
23+
impl<'a> Resolver<'a> {
24+
pub fn assign_node_ids(&mut self, krate: ast::Crate) -> ast::Crate {
25+
NodeIdAssigner {
26+
sess: self.session,
27+
macros_at_scope: &mut self.macros_at_scope,
28+
}.fold_crate(krate)
29+
}
30+
}
31+
32+
struct NodeIdAssigner<'a> {
33+
sess: &'a Session,
34+
macros_at_scope: &'a mut HashMap<ast::NodeId, Vec<ast::Mrk>>,
35+
}
36+
37+
impl<'a> Folder for NodeIdAssigner<'a> {
38+
fn new_id(&mut self, old_id: ast::NodeId) -> ast::NodeId {
39+
assert_eq!(old_id, ast::DUMMY_NODE_ID);
40+
self.sess.next_node_id()
41+
}
42+
43+
fn fold_block(&mut self, block: P<ast::Block>) -> P<ast::Block> {
44+
block.map(|mut block| {
45+
block.id = self.new_id(block.id);
46+
47+
let stmt = block.stmts.pop();
48+
let mut macros = Vec::new();
49+
block.stmts = block.stmts.move_flat_map(|stmt| {
50+
if let ast::StmtKind::Item(ref item) = stmt.node {
51+
if let ast::ItemKind::Mac(..) = item.node {
52+
macros.push(mtwt::outer_mark(item.ident.ctxt));
53+
return None;
54+
}
55+
}
56+
57+
let stmt = self.fold_stmt(stmt).pop().unwrap();
58+
if !macros.is_empty() {
59+
self.macros_at_scope.insert(stmt.id, mem::replace(&mut macros, Vec::new()));
60+
}
61+
Some(stmt)
62+
});
63+
64+
stmt.and_then(|mut stmt| {
65+
// Avoid wasting a node id on a trailing expression statement,
66+
// which shares a HIR node with the expression itself.
67+
if let ast::StmtKind::Expr(expr) = stmt.node {
68+
let expr = self.fold_expr(expr);
69+
stmt.id = expr.id;
70+
stmt.node = ast::StmtKind::Expr(expr);
71+
Some(stmt)
72+
} else {
73+
self.fold_stmt(stmt).pop()
74+
}
75+
}).map(|stmt| {
76+
if !macros.is_empty() {
77+
self.macros_at_scope.insert(stmt.id, mem::replace(&mut macros, Vec::new()));
78+
}
79+
block.stmts.push(stmt);
80+
});
81+
82+
block
83+
})
84+
}
85+
86+
fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
87+
match item.node {
88+
ast::ItemKind::Mac(..) => SmallVector::zero(),
89+
_ => fold::noop_fold_item(item, self),
90+
}
91+
}
92+
}

0 commit comments

Comments
 (0)