Skip to content

Commit e355a33

Browse files
committed
Deduplicate identifier printing a bit
1 parent 9c230f3 commit e355a33

File tree

3 files changed

+66
-49
lines changed

3 files changed

+66
-49
lines changed

src/librustc_ast_pretty/pprust.rs

+4-38
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::pp::{self, Breaks};
33

44
use rustc_span::edition::Edition;
55
use rustc_span::source_map::{SourceMap, Spanned};
6-
use rustc_span::symbol::{kw, sym};
6+
use rustc_span::symbol::{kw, sym, IdentPrinter};
77
use rustc_span::{BytePos, FileName, Span};
88
use syntax::ast::{self, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
99
use syntax::ast::{Attribute, GenericArg, MacArgs};
@@ -196,40 +196,6 @@ pub fn literal_to_string(lit: token::Lit) -> String {
196196
out
197197
}
198198

199-
/// Print an ident from AST, `$crate` is converted into its respective crate name.
200-
pub fn ast_ident_to_string(ident: ast::Ident, is_raw: bool) -> String {
201-
ident_to_string(ident.name, is_raw, Some(ident.span))
202-
}
203-
204-
// AST pretty-printer is used as a fallback for turning AST structures into token streams for
205-
// proc macros. Additionally, proc macros may stringify their input and expect it survive the
206-
// stringification (especially true for proc macro derives written between Rust 1.15 and 1.30).
207-
// So we need to somehow pretty-print `$crate` in a way preserving at least some of its
208-
// hygiene data, most importantly name of the crate it refers to.
209-
// As a result we print `$crate` as `crate` if it refers to the local crate
210-
// and as `::other_crate_name` if it refers to some other crate.
211-
// Note, that this is only done if the ident token is printed from inside of AST pretty-pringing,
212-
// but not otherwise. Pretty-printing is the only way for proc macros to discover token contents,
213-
// so we should not perform this lossy conversion if the top level call to the pretty-printer was
214-
// done for a token stream or a single token.
215-
fn ident_to_string(name: ast::Name, is_raw: bool, convert_dollar_crate: Option<Span>) -> String {
216-
if is_raw {
217-
format!("r#{}", name)
218-
} else {
219-
if name == kw::DollarCrate {
220-
if let Some(span) = convert_dollar_crate {
221-
let converted = span.ctxt().dollar_crate_name();
222-
return if converted.is_path_segment_keyword() {
223-
converted.to_string()
224-
} else {
225-
format!("::{}", converted)
226-
};
227-
}
228-
}
229-
name.to_string()
230-
}
231-
}
232-
233199
/// Print the token kind precisely, without converting `$crate` into its respective crate name.
234200
pub fn token_kind_to_string(tok: &TokenKind) -> String {
235201
token_kind_to_string_ext(tok, None)
@@ -280,7 +246,7 @@ fn token_kind_to_string_ext(tok: &TokenKind, convert_dollar_crate: Option<Span>)
280246
token::Literal(lit) => literal_to_string(lit),
281247

282248
/* Name components */
283-
token::Ident(s, is_raw) => ident_to_string(s, is_raw, convert_dollar_crate),
249+
token::Ident(s, is_raw) => IdentPrinter::new(s, is_raw, convert_dollar_crate).to_string(),
284250
token::Lifetime(s) => s.to_string(),
285251

286252
/* Other */
@@ -315,7 +281,7 @@ pub fn nonterminal_to_string(nt: &Nonterminal) -> String {
315281
token::NtBlock(ref e) => block_to_string(e),
316282
token::NtStmt(ref e) => stmt_to_string(e),
317283
token::NtPat(ref e) => pat_to_string(e),
318-
token::NtIdent(e, is_raw) => ast_ident_to_string(e, is_raw),
284+
token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw).to_string(),
319285
token::NtLifetime(e) => e.to_string(),
320286
token::NtLiteral(ref e) => expr_to_string(e),
321287
token::NtTT(ref tree) => tt_to_string(tree.clone()),
@@ -819,7 +785,7 @@ impl<'a> PrintState<'a> for State<'a> {
819785
}
820786

821787
fn print_ident(&mut self, ident: ast::Ident) {
822-
self.s.word(ast_ident_to_string(ident, ident.is_raw_guess()));
788+
self.s.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string());
823789
self.ann.post(self, AnnNode::Ident(&ident))
824790
}
825791

src/librustc_hir/print.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent};
22
use rustc_ast_pretty::pp::{self, Breaks};
3-
use rustc_ast_pretty::pprust::{self, Comments, PrintState};
3+
use rustc_ast_pretty::pprust::{Comments, PrintState};
44
use rustc_span::source_map::{SourceMap, Spanned};
5-
use rustc_span::symbol::kw;
5+
use rustc_span::symbol::{kw, IdentPrinter};
66
use rustc_span::{self, BytePos, FileName};
77
use rustc_target::spec::abi::Abi;
88
use syntax::ast;
@@ -126,7 +126,7 @@ impl<'a> PrintState<'a> for State<'a> {
126126
}
127127

128128
fn print_ident(&mut self, ident: ast::Ident) {
129-
self.s.word(pprust::ast_ident_to_string(ident, ident.is_raw_guess()));
129+
self.s.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string());
130130
self.ann.post(self, AnnNode::Name(&ident.name))
131131
}
132132

src/librustc_span/symbol.rs

+59-8
Original file line numberDiff line numberDiff line change
@@ -893,19 +893,17 @@ impl Hash for Ident {
893893

894894
impl fmt::Debug for Ident {
895895
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
896-
if self.is_raw_guess() {
897-
write!(f, "r#")?;
898-
}
899-
write!(f, "{}{:?}", self.name, self.span.ctxt())
896+
fmt::Display::fmt(self, f)?;
897+
fmt::Debug::fmt(&self.span.ctxt(), f)
900898
}
901899
}
902900

901+
/// This implementation is supposed to be used in error messages, so it's expected to be identical
902+
/// to printing the original identifier token written in source code (`token_to_string`),
903+
/// except that AST identifiers don't keep the rawness flag, so we have to guess it.
903904
impl fmt::Display for Ident {
904905
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
905-
if self.is_raw_guess() {
906-
write!(f, "r#")?;
907-
}
908-
fmt::Display::fmt(&self.name, f)
906+
fmt::Display::fmt(&IdentPrinter::new(self.name, self.is_raw_guess(), None), f)
909907
}
910908
}
911909

@@ -929,6 +927,59 @@ impl UseSpecializedDecodable for Ident {
929927
}
930928
}
931929

930+
/// This is the most general way to print identifiers.
931+
/// AST pretty-printer is used as a fallback for turning AST structures into token streams for
932+
/// proc macros. Additionally, proc macros may stringify their input and expect it survive the
933+
/// stringification (especially true for proc macro derives written between Rust 1.15 and 1.30).
934+
/// So we need to somehow pretty-print `$crate` in a way preserving at least some of its
935+
/// hygiene data, most importantly name of the crate it refers to.
936+
/// As a result we print `$crate` as `crate` if it refers to the local crate
937+
/// and as `::other_crate_name` if it refers to some other crate.
938+
/// Note, that this is only done if the ident token is printed from inside of AST pretty-pringing,
939+
/// but not otherwise. Pretty-printing is the only way for proc macros to discover token contents,
940+
/// so we should not perform this lossy conversion if the top level call to the pretty-printer was
941+
/// done for a token stream or a single token.
942+
pub struct IdentPrinter {
943+
symbol: Symbol,
944+
is_raw: bool,
945+
/// Span used for retrieving the crate name to which `$crate` refers to,
946+
/// if this field is `None` then the `$crate` conversion doesn't happen.
947+
convert_dollar_crate: Option<Span>,
948+
}
949+
950+
impl IdentPrinter {
951+
/// The most general `IdentPrinter` constructor. Do not use this.
952+
pub fn new(symbol: Symbol, is_raw: bool, convert_dollar_crate: Option<Span>) -> IdentPrinter {
953+
IdentPrinter { symbol, is_raw, convert_dollar_crate }
954+
}
955+
956+
/// This implementation is supposed to be used when printing identifiers
957+
/// as a part of pretty-printing for larger AST pieces.
958+
/// Do not use this either.
959+
pub fn for_ast_ident(ident: Ident, is_raw: bool) -> IdentPrinter {
960+
IdentPrinter::new(ident.name, is_raw, Some(ident.span))
961+
}
962+
}
963+
964+
impl fmt::Display for IdentPrinter {
965+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
966+
if self.is_raw {
967+
f.write_str("r#")?;
968+
} else {
969+
if self.symbol == kw::DollarCrate {
970+
if let Some(span) = self.convert_dollar_crate {
971+
let converted = span.ctxt().dollar_crate_name();
972+
if !converted.is_path_segment_keyword() {
973+
f.write_str("::")?;
974+
}
975+
return fmt::Display::fmt(&converted, f);
976+
}
977+
}
978+
}
979+
fmt::Display::fmt(&self.symbol, f)
980+
}
981+
}
982+
932983
/// An interned string.
933984
///
934985
/// Internally, a `Symbol` is implemented as an index, and all operations

0 commit comments

Comments
 (0)