提交 39975077 编写于 作者: V Vadim Petrochenkov

Resolve `$crate` in all hygienic contexts for pretty-pringing

Stop visiting AST to discover those contexts, just iterate through hygiene data instead
上级 4344a903
...@@ -758,7 +758,10 @@ pub fn get_module(&mut self, def_id: DefId) -> Module<'a> { ...@@ -758,7 +758,10 @@ pub fn get_module(&mut self, def_id: DefId) -> Module<'a> {
} }
pub fn macro_def_scope(&mut self, expansion: Mark) -> Module<'a> { pub fn macro_def_scope(&mut self, expansion: Mark) -> Module<'a> {
let def_id = self.macro_defs[&expansion]; let def_id = match self.macro_defs.get(&expansion) {
Some(def_id) => *def_id,
None => return self.graph_root,
};
if let Some(id) = self.definitions.as_local_node_id(def_id) { if let Some(id) = self.definitions.as_local_node_id(def_id) {
self.local_macro_def_scopes[&id] self.local_macro_def_scopes[&id]
} else if def_id.krate == CrateNum::BuiltinMacros { } else if def_id.krate == CrateNum::BuiltinMacros {
......
...@@ -17,12 +17,11 @@ ...@@ -17,12 +17,11 @@
use syntax::ext::base::{self, Determinacy}; use syntax::ext::base::{self, Determinacy};
use syntax::ext::base::{MacroKind, SyntaxExtension}; use syntax::ext::base::{MacroKind, SyntaxExtension};
use syntax::ext::expand::{AstFragment, Invocation, InvocationKind}; use syntax::ext::expand::{AstFragment, Invocation, InvocationKind};
use syntax::ext::hygiene::Mark; use syntax::ext::hygiene::{self, Mark};
use syntax::ext::tt::macro_rules; use syntax::ext::tt::macro_rules;
use syntax::feature_gate::{feature_err, emit_feature_err, is_builtin_attr_name}; use syntax::feature_gate::{feature_err, emit_feature_err, is_builtin_attr_name};
use syntax::feature_gate::{AttributeGate, GateIssue, Stability, BUILTIN_ATTRIBUTES}; use syntax::feature_gate::{AttributeGate, GateIssue, Stability, BUILTIN_ATTRIBUTES};
use syntax::symbol::{Symbol, kw, sym}; use syntax::symbol::{Symbol, kw, sym};
use syntax::visit::Visitor;
use syntax::util::lev_distance::find_best_match_for_name; use syntax::util::lev_distance::find_best_match_for_name;
use syntax_pos::{Span, DUMMY_SP}; use syntax_pos::{Span, DUMMY_SP};
use errors::Applicability; use errors::Applicability;
...@@ -146,24 +145,14 @@ fn get_module_scope(&mut self, id: ast::NodeId) -> Mark { ...@@ -146,24 +145,14 @@ fn get_module_scope(&mut self, id: ast::NodeId) -> Mark {
mark mark
} }
fn resolve_dollar_crates(&mut self, fragment: &AstFragment) { fn resolve_dollar_crates(&mut self) {
struct ResolveDollarCrates<'a, 'b> { hygiene::update_dollar_crate_names(|ctxt| {
resolver: &'a mut Resolver<'b> let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt));
} match self.resolve_crate_root(ident).kind {
impl<'a> Visitor<'a> for ResolveDollarCrates<'a, '_> { ModuleKind::Def(.., name) if name != kw::Invalid => name,
fn visit_ident(&mut self, ident: Ident) { _ => kw::Crate,
if ident.name == kw::DollarCrate {
let name = match self.resolver.resolve_crate_root(ident).kind {
ModuleKind::Def(.., name) if name != kw::Invalid => name,
_ => kw::Crate,
};
ident.span.ctxt().set_dollar_crate_name(name);
}
} }
fn visit_mac(&mut self, _: &ast::Mac) {} });
}
fragment.visit_with(&mut ResolveDollarCrates { resolver: self });
} }
fn visit_ast_fragment_with_placeholders(&mut self, mark: Mark, fragment: &AstFragment, fn visit_ast_fragment_with_placeholders(&mut self, mark: Mark, fragment: &AstFragment,
......
...@@ -701,7 +701,7 @@ pub trait Resolver { ...@@ -701,7 +701,7 @@ pub trait Resolver {
fn get_module_scope(&mut self, id: ast::NodeId) -> Mark; fn get_module_scope(&mut self, id: ast::NodeId) -> Mark;
fn resolve_dollar_crates(&mut self, fragment: &AstFragment); fn resolve_dollar_crates(&mut self);
fn visit_ast_fragment_with_placeholders(&mut self, mark: Mark, fragment: &AstFragment, fn visit_ast_fragment_with_placeholders(&mut self, mark: Mark, fragment: &AstFragment,
derives: &[Mark]); derives: &[Mark]);
fn add_builtin(&mut self, ident: ast::Ident, ext: Lrc<SyntaxExtension>); fn add_builtin(&mut self, ident: ast::Ident, ext: Lrc<SyntaxExtension>);
......
...@@ -429,7 +429,7 @@ fn resolve_imports(&mut self) { ...@@ -429,7 +429,7 @@ fn resolve_imports(&mut self) {
fn collect_invocations(&mut self, mut fragment: AstFragment, derives: &[Mark]) fn collect_invocations(&mut self, mut fragment: AstFragment, derives: &[Mark])
-> (AstFragment, Vec<Invocation>) { -> (AstFragment, Vec<Invocation>) {
// Resolve `$crate`s in the fragment for pretty-printing. // Resolve `$crate`s in the fragment for pretty-printing.
self.cx.resolver.resolve_dollar_crates(&fragment); self.cx.resolver.resolve_dollar_crates();
let invocations = { let invocations = {
let mut collector = InvocationCollector { let mut collector = InvocationCollector {
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
use serialize::{Encodable, Decodable, Encoder, Decoder}; use serialize::{Encodable, Decodable, Encoder, Decoder};
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use std::{fmt, mem}; use std::fmt;
/// A SyntaxContext represents a chain of macro expansions (represented by marks). /// A SyntaxContext represents a chain of macro expansions (represented by marks).
#[derive(Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash)] #[derive(Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
...@@ -387,6 +387,23 @@ pub fn walk_chain(span: Span, to: SyntaxContext) -> Span { ...@@ -387,6 +387,23 @@ pub fn walk_chain(span: Span, to: SyntaxContext) -> Span {
HygieneData::with(|data| data.walk_chain(span, to)) HygieneData::with(|data| data.walk_chain(span, to))
} }
pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) {
// The new contexts that need updating are at the end of the list and have `$crate` as a name.
let (len, to_update) = HygieneData::with(|data| (
data.syntax_contexts.len(),
data.syntax_contexts.iter().rev()
.take_while(|scdata| scdata.dollar_crate_name == kw::DollarCrate).count()
));
// The callback must be called from outside of the `HygieneData` lock,
// since it will try to acquire it too.
let range_to_update = len - to_update .. len;
let names: Vec<_> =
range_to_update.clone().map(|idx| get_name(SyntaxContext::from_u32(idx as u32))).collect();
HygieneData::with(|data| range_to_update.zip(names.into_iter()).for_each(|(idx, name)| {
data.syntax_contexts[idx].dollar_crate_name = name;
}))
}
impl SyntaxContext { impl SyntaxContext {
#[inline] #[inline]
pub const fn empty() -> Self { pub const fn empty() -> Self {
...@@ -614,17 +631,6 @@ pub fn outer_and_expn_info(self) -> (Mark, Option<ExpnInfo>) { ...@@ -614,17 +631,6 @@ pub fn outer_and_expn_info(self) -> (Mark, Option<ExpnInfo>) {
pub fn dollar_crate_name(self) -> Symbol { pub fn dollar_crate_name(self) -> Symbol {
HygieneData::with(|data| data.syntax_contexts[self.0 as usize].dollar_crate_name) HygieneData::with(|data| data.syntax_contexts[self.0 as usize].dollar_crate_name)
} }
pub fn set_dollar_crate_name(self, dollar_crate_name: Symbol) {
HygieneData::with(|data| {
let prev_dollar_crate_name = mem::replace(
&mut data.syntax_contexts[self.0 as usize].dollar_crate_name, dollar_crate_name
);
assert!(dollar_crate_name == prev_dollar_crate_name ||
prev_dollar_crate_name == kw::DollarCrate,
"$crate name is reset for a syntax context");
})
}
} }
impl fmt::Debug for SyntaxContext { impl fmt::Debug for SyntaxContext {
......
//~ ERROR expected type, found `$` // check-pass
// edition:2018 // edition:2018
// aux-build:test-macros.rs // aux-build:test-macros.rs
......
error: expected type, found `$`
error: aborting due to previous error
PRINT-ATTR INPUT (DISPLAY): struct A(identity!($crate :: S)); PRINT-ATTR INPUT (DISPLAY): struct A(identity!(crate :: S));
PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ( identity ! ( $ crate :: S ) ) ; PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ( identity ! ( crate :: S ) ) ;
PRINT-ATTR INPUT (DEBUG): TokenStream [ PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident { Ident {
ident: "struct", ident: "struct",
span: #0 bytes(0..0), span: #2 bytes(LO..HI),
}, },
Ident { Ident {
ident: "A", ident: "A",
span: #0 bytes(0..0), span: #2 bytes(LO..HI),
}, },
Group { Group {
delimiter: Parenthesis, delimiter: Parenthesis,
stream: TokenStream [ stream: TokenStream [
Ident { Ident {
ident: "identity", ident: "identity",
span: #0 bytes(0..0), span: #2 bytes(LO..HI),
}, },
Punct { Punct {
ch: '!', ch: '!',
spacing: Alone, spacing: Alone,
span: #0 bytes(0..0), span: #2 bytes(LO..HI),
}, },
Group { Group {
delimiter: Parenthesis, delimiter: Parenthesis,
stream: TokenStream [ stream: TokenStream [
Punct {
ch: '$',
spacing: Alone,
span: #0 bytes(0..0),
},
Ident { Ident {
ident: "crate", ident: "$crate",
span: #0 bytes(0..0), span: #2 bytes(LO..HI),
}, },
Punct { Punct {
ch: ':', ch: ':',
spacing: Joint, spacing: Joint,
span: #0 bytes(0..0), span: #2 bytes(LO..HI),
}, },
Punct { Punct {
ch: ':', ch: ':',
spacing: Alone, spacing: Alone,
span: #0 bytes(0..0), span: #2 bytes(LO..HI),
}, },
Ident { Ident {
ident: "S", ident: "S",
span: #0 bytes(0..0), span: #2 bytes(LO..HI),
}, },
], ],
span: #0 bytes(0..0), span: #2 bytes(LO..HI),
}, },
], ],
span: #0 bytes(0..0), span: #2 bytes(LO..HI),
}, },
Punct { Punct {
ch: ';', ch: ';',
spacing: Alone, spacing: Alone,
span: #0 bytes(0..0), span: #2 bytes(LO..HI),
}, },
] ]
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册