Use Symbol for named arguments in fmt_macros
This commit is contained in:
parent
7795b155e0
commit
dc13072b7b
7 changed files with 79 additions and 61 deletions
|
@ -910,6 +910,9 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fmt_macros"
|
name = "fmt_macros"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"syntax_pos 0.0.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
|
|
|
@ -8,3 +8,6 @@ edition = "2018"
|
||||||
name = "fmt_macros"
|
name = "fmt_macros"
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
crate-type = ["dylib"]
|
crate-type = ["dylib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
syntax_pos = { path = "../libsyntax_pos" }
|
||||||
|
|
|
@ -24,6 +24,8 @@ use std::str;
|
||||||
use std::string;
|
use std::string;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
|
use syntax_pos::Symbol;
|
||||||
|
|
||||||
/// A piece is a portion of the format string which represents the next part
|
/// A piece is a portion of the format string which represents the next part
|
||||||
/// to emit. These are emitted as a stream by the `Parser` class.
|
/// to emit. These are emitted as a stream by the `Parser` class.
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
@ -39,7 +41,7 @@ pub enum Piece<'a> {
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub struct Argument<'a> {
|
pub struct Argument<'a> {
|
||||||
/// Where to find this argument
|
/// Where to find this argument
|
||||||
pub position: Position<'a>,
|
pub position: Position,
|
||||||
/// How to format the argument
|
/// How to format the argument
|
||||||
pub format: FormatSpec<'a>,
|
pub format: FormatSpec<'a>,
|
||||||
}
|
}
|
||||||
|
@ -54,9 +56,9 @@ pub struct FormatSpec<'a> {
|
||||||
/// Packed version of various flags provided
|
/// Packed version of various flags provided
|
||||||
pub flags: u32,
|
pub flags: u32,
|
||||||
/// The integer precision to use
|
/// The integer precision to use
|
||||||
pub precision: Count<'a>,
|
pub precision: Count,
|
||||||
/// The string width requested for the resulting format
|
/// The string width requested for the resulting format
|
||||||
pub width: Count<'a>,
|
pub width: Count,
|
||||||
/// The descriptor string representing the name of the format desired for
|
/// The descriptor string representing the name of the format desired for
|
||||||
/// this argument, this can be empty or any number of characters, although
|
/// this argument, this can be empty or any number of characters, although
|
||||||
/// it is required to be one word.
|
/// it is required to be one word.
|
||||||
|
@ -65,16 +67,16 @@ pub struct FormatSpec<'a> {
|
||||||
|
|
||||||
/// Enum describing where an argument for a format can be located.
|
/// Enum describing where an argument for a format can be located.
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub enum Position<'a> {
|
pub enum Position {
|
||||||
/// The argument is implied to be located at an index
|
/// The argument is implied to be located at an index
|
||||||
ArgumentImplicitlyIs(usize),
|
ArgumentImplicitlyIs(usize),
|
||||||
/// The argument is located at a specific index given in the format
|
/// The argument is located at a specific index given in the format
|
||||||
ArgumentIs(usize),
|
ArgumentIs(usize),
|
||||||
/// The argument has a name.
|
/// The argument has a name.
|
||||||
ArgumentNamed(&'a str),
|
ArgumentNamed(Symbol),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Position<'_> {
|
impl Position {
|
||||||
pub fn index(&self) -> Option<usize> {
|
pub fn index(&self) -> Option<usize> {
|
||||||
match self {
|
match self {
|
||||||
ArgumentIs(i) | ArgumentImplicitlyIs(i) => Some(*i),
|
ArgumentIs(i) | ArgumentImplicitlyIs(i) => Some(*i),
|
||||||
|
@ -119,11 +121,11 @@ pub enum Flag {
|
||||||
/// A count is used for the precision and width parameters of an integer, and
|
/// A count is used for the precision and width parameters of an integer, and
|
||||||
/// can reference either an argument or a literal integer.
|
/// can reference either an argument or a literal integer.
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub enum Count<'a> {
|
pub enum Count {
|
||||||
/// The count is specified explicitly.
|
/// The count is specified explicitly.
|
||||||
CountIs(usize),
|
CountIs(usize),
|
||||||
/// The count is specified by the argument with the given name.
|
/// The count is specified by the argument with the given name.
|
||||||
CountIsName(&'a str),
|
CountIsName(Symbol),
|
||||||
/// The count is specified by the argument at the given index.
|
/// The count is specified by the argument at the given index.
|
||||||
CountIsParam(usize),
|
CountIsParam(usize),
|
||||||
/// The count is implied and cannot be explicitly specified.
|
/// The count is implied and cannot be explicitly specified.
|
||||||
|
@ -431,12 +433,14 @@ impl<'a> Parser<'a> {
|
||||||
/// integer index of an argument, a named argument, or a blank string.
|
/// integer index of an argument, a named argument, or a blank string.
|
||||||
/// Returns `Some(parsed_position)` if the position is not implicitly
|
/// Returns `Some(parsed_position)` if the position is not implicitly
|
||||||
/// consuming a macro argument, `None` if it's the case.
|
/// consuming a macro argument, `None` if it's the case.
|
||||||
fn position(&mut self) -> Option<Position<'a>> {
|
fn position(&mut self) -> Option<Position> {
|
||||||
if let Some(i) = self.integer() {
|
if let Some(i) = self.integer() {
|
||||||
Some(ArgumentIs(i))
|
Some(ArgumentIs(i))
|
||||||
} else {
|
} else {
|
||||||
match self.cur.peek() {
|
match self.cur.peek() {
|
||||||
Some(&(_, c)) if c.is_alphabetic() => Some(ArgumentNamed(self.word())),
|
Some(&(_, c)) if c.is_alphabetic() => {
|
||||||
|
Some(ArgumentNamed(Symbol::intern(self.word())))
|
||||||
|
}
|
||||||
Some(&(pos, c)) if c == '_' => {
|
Some(&(pos, c)) if c == '_' => {
|
||||||
let invalid_name = self.string(pos);
|
let invalid_name = self.string(pos);
|
||||||
self.err_with_note(format!("invalid argument name `{}`", invalid_name),
|
self.err_with_note(format!("invalid argument name `{}`", invalid_name),
|
||||||
|
@ -444,7 +448,7 @@ impl<'a> Parser<'a> {
|
||||||
"argument names cannot start with an underscore",
|
"argument names cannot start with an underscore",
|
||||||
self.to_span_index(pos),
|
self.to_span_index(pos),
|
||||||
self.to_span_index(pos + invalid_name.len()));
|
self.to_span_index(pos + invalid_name.len()));
|
||||||
Some(ArgumentNamed(invalid_name))
|
Some(ArgumentNamed(Symbol::intern(invalid_name)))
|
||||||
},
|
},
|
||||||
|
|
||||||
// This is an `ArgumentNext`.
|
// This is an `ArgumentNext`.
|
||||||
|
@ -552,7 +556,7 @@ impl<'a> Parser<'a> {
|
||||||
/// Parses a Count parameter at the current position. This does not check
|
/// Parses a Count parameter at the current position. This does not check
|
||||||
/// for 'CountIsNextParam' because that is only used in precision, not
|
/// for 'CountIsNextParam' because that is only used in precision, not
|
||||||
/// width.
|
/// width.
|
||||||
fn count(&mut self) -> Count<'a> {
|
fn count(&mut self) -> Count {
|
||||||
if let Some(i) = self.integer() {
|
if let Some(i) = self.integer() {
|
||||||
if self.consume('$') {
|
if self.consume('$') {
|
||||||
CountIsParam(i)
|
CountIsParam(i)
|
||||||
|
@ -566,7 +570,7 @@ impl<'a> Parser<'a> {
|
||||||
self.cur = tmp;
|
self.cur = tmp;
|
||||||
CountImplied
|
CountImplied
|
||||||
} else if self.consume('$') {
|
} else if self.consume('$') {
|
||||||
CountIsName(word)
|
CountIsName(Symbol::intern(word))
|
||||||
} else {
|
} else {
|
||||||
self.cur = tmp;
|
self.cur = tmp;
|
||||||
CountImplied
|
CountImplied
|
||||||
|
@ -756,6 +760,8 @@ mod tests {
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn format_counts() {
|
fn format_counts() {
|
||||||
|
use syntax_pos::{GLOBALS, Globals, edition};
|
||||||
|
GLOBALS.set(&Globals::new(edition::DEFAULT_EDITION), || {
|
||||||
same("{:10s}",
|
same("{:10s}",
|
||||||
&[NextArgument(Argument {
|
&[NextArgument(Argument {
|
||||||
position: ArgumentImplicitlyIs(0),
|
position: ArgumentImplicitlyIs(0),
|
||||||
|
@ -811,11 +817,12 @@ mod tests {
|
||||||
fill: None,
|
fill: None,
|
||||||
align: AlignUnknown,
|
align: AlignUnknown,
|
||||||
flags: 0,
|
flags: 0,
|
||||||
precision: CountIsName("b"),
|
precision: CountIsName(Symbol::intern("b")),
|
||||||
width: CountIsName("a"),
|
width: CountIsName(Symbol::intern("a")),
|
||||||
ty: "s",
|
ty: "s",
|
||||||
},
|
},
|
||||||
})]);
|
})]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn format_flags() {
|
fn format_flags() {
|
||||||
|
|
|
@ -353,7 +353,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||||
_ => {
|
_ => {
|
||||||
// this is a "direct", user-specified, rather than derived,
|
// this is a "direct", user-specified, rather than derived,
|
||||||
// obligation.
|
// obligation.
|
||||||
flags.push(("direct".to_owned(), None));
|
flags.push((sym::direct, None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,27 +365,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||||
// Currently I'm leaving it for what I need for `try`.
|
// Currently I'm leaving it for what I need for `try`.
|
||||||
if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) {
|
if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) {
|
||||||
let method = self.tcx.item_name(item);
|
let method = self.tcx.item_name(item);
|
||||||
flags.push(("from_method".to_owned(), None));
|
flags.push((sym::from_method, None));
|
||||||
flags.push(("from_method".to_owned(), Some(method.to_string())));
|
flags.push((sym::from_method, Some(method.to_string())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(t) = self.get_parent_trait_ref(&obligation.cause.code) {
|
if let Some(t) = self.get_parent_trait_ref(&obligation.cause.code) {
|
||||||
flags.push(("parent_trait".to_owned(), Some(t)));
|
flags.push((sym::parent_trait, Some(t)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(k) = obligation.cause.span.compiler_desugaring_kind() {
|
if let Some(k) = obligation.cause.span.compiler_desugaring_kind() {
|
||||||
flags.push(("from_desugaring".to_owned(), None));
|
flags.push((sym::from_desugaring, None));
|
||||||
flags.push(("from_desugaring".to_owned(), Some(k.name().to_string())));
|
flags.push((sym::from_desugaring, Some(k.name().to_string())));
|
||||||
}
|
}
|
||||||
let generics = self.tcx.generics_of(def_id);
|
let generics = self.tcx.generics_of(def_id);
|
||||||
let self_ty = trait_ref.self_ty();
|
let self_ty = trait_ref.self_ty();
|
||||||
// This is also included through the generics list as `Self`,
|
// This is also included through the generics list as `Self`,
|
||||||
// but the parser won't allow you to use it
|
// but the parser won't allow you to use it
|
||||||
flags.push(("_Self".to_owned(), Some(self_ty.to_string())));
|
flags.push((sym::_Self, Some(self_ty.to_string())));
|
||||||
if let Some(def) = self_ty.ty_adt_def() {
|
if let Some(def) = self_ty.ty_adt_def() {
|
||||||
// We also want to be able to select self's original
|
// We also want to be able to select self's original
|
||||||
// signature with no type arguments resolved
|
// signature with no type arguments resolved
|
||||||
flags.push(("_Self".to_owned(), Some(self.tcx.type_of(def.did).to_string())));
|
flags.push((sym::_Self, Some(self.tcx.type_of(def.did).to_string())));
|
||||||
}
|
}
|
||||||
|
|
||||||
for param in generics.params.iter() {
|
for param in generics.params.iter() {
|
||||||
|
@ -396,38 +396,38 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||||
},
|
},
|
||||||
GenericParamDefKind::Lifetime => continue,
|
GenericParamDefKind::Lifetime => continue,
|
||||||
};
|
};
|
||||||
let name = param.name.to_string();
|
let name = param.name.as_symbol();
|
||||||
flags.push((name, Some(value)));
|
flags.push((name, Some(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) {
|
if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) {
|
||||||
flags.push(("crate_local".to_owned(), None));
|
flags.push((sym::crate_local, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow targeting all integers using `{integral}`, even if the exact type was resolved
|
// Allow targeting all integers using `{integral}`, even if the exact type was resolved
|
||||||
if self_ty.is_integral() {
|
if self_ty.is_integral() {
|
||||||
flags.push(("_Self".to_owned(), Some("{integral}".to_owned())));
|
flags.push((sym::_Self, Some("{integral}".to_owned())));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let ty::Array(aty, len) = self_ty.sty {
|
if let ty::Array(aty, len) = self_ty.sty {
|
||||||
flags.push(("_Self".to_owned(), Some("[]".to_owned())));
|
flags.push((sym::_Self, Some("[]".to_owned())));
|
||||||
flags.push(("_Self".to_owned(), Some(format!("[{}]", aty))));
|
flags.push((sym::_Self, Some(format!("[{}]", aty))));
|
||||||
if let Some(def) = aty.ty_adt_def() {
|
if let Some(def) = aty.ty_adt_def() {
|
||||||
// We also want to be able to select the array's type's original
|
// We also want to be able to select the array's type's original
|
||||||
// signature with no type arguments resolved
|
// signature with no type arguments resolved
|
||||||
flags.push((
|
flags.push((
|
||||||
"_Self".to_owned(),
|
sym::_Self,
|
||||||
Some(format!("[{}]", self.tcx.type_of(def.did).to_string())),
|
Some(format!("[{}]", self.tcx.type_of(def.did).to_string())),
|
||||||
));
|
));
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
if let Some(len) = len.assert_usize(tcx) {
|
if let Some(len) = len.assert_usize(tcx) {
|
||||||
flags.push((
|
flags.push((
|
||||||
"_Self".to_owned(),
|
sym::_Self,
|
||||||
Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)),
|
Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)),
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
flags.push((
|
flags.push((
|
||||||
"_Self".to_owned(),
|
sym::_Self,
|
||||||
Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())),
|
Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::util::nodemap::FxHashMap;
|
||||||
|
|
||||||
use syntax::ast::{MetaItem, NestedMetaItem};
|
use syntax::ast::{MetaItem, NestedMetaItem};
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
use syntax::symbol::sym;
|
use syntax::symbol::{Symbol, kw, sym};
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
use syntax_pos::symbol::LocalInternedString;
|
use syntax_pos::symbol::LocalInternedString;
|
||||||
|
|
||||||
|
@ -167,7 +167,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
|
||||||
pub fn evaluate(&self,
|
pub fn evaluate(&self,
|
||||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
trait_ref: ty::TraitRef<'tcx>,
|
trait_ref: ty::TraitRef<'tcx>,
|
||||||
options: &[(String, Option<String>)])
|
options: &[(Symbol, Option<String>)])
|
||||||
-> OnUnimplementedNote
|
-> OnUnimplementedNote
|
||||||
{
|
{
|
||||||
let mut message = None;
|
let mut message = None;
|
||||||
|
@ -180,7 +180,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
|
||||||
if !attr::eval_condition(condition, &tcx.sess.parse_sess, &mut |c| {
|
if !attr::eval_condition(condition, &tcx.sess.parse_sess, &mut |c| {
|
||||||
c.ident().map_or(false, |ident| {
|
c.ident().map_or(false, |ident| {
|
||||||
options.contains(&(
|
options.contains(&(
|
||||||
ident.to_string(),
|
ident.name,
|
||||||
c.value_str().map(|s| s.as_str().to_string())
|
c.value_str().map(|s| s.as_str().to_string())
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
|
@ -203,8 +203,8 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let options: FxHashMap<String, String> = options.into_iter()
|
let options: FxHashMap<Symbol, String> = options.into_iter()
|
||||||
.filter_map(|(k, v)| v.as_ref().map(|v| (k.to_owned(), v.to_owned())))
|
.filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned())))
|
||||||
.collect();
|
.collect();
|
||||||
OnUnimplementedNote {
|
OnUnimplementedNote {
|
||||||
label: label.map(|l| l.format(tcx, trait_ref, &options)),
|
label: label.map(|l| l.format(tcx, trait_ref, &options)),
|
||||||
|
@ -241,16 +241,16 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString {
|
||||||
Piece::String(_) => (), // Normal string, no need to check it
|
Piece::String(_) => (), // Normal string, no need to check it
|
||||||
Piece::NextArgument(a) => match a.position {
|
Piece::NextArgument(a) => match a.position {
|
||||||
// `{Self}` is allowed
|
// `{Self}` is allowed
|
||||||
Position::ArgumentNamed(s) if s == "Self" => (),
|
Position::ArgumentNamed(s) if s == kw::SelfUpper => (),
|
||||||
// `{ThisTraitsName}` is allowed
|
// `{ThisTraitsName}` is allowed
|
||||||
Position::ArgumentNamed(s) if s == name.as_str() => (),
|
Position::ArgumentNamed(s) if s == name => (),
|
||||||
// `{from_method}` is allowed
|
// `{from_method}` is allowed
|
||||||
Position::ArgumentNamed(s) if s == "from_method" => (),
|
Position::ArgumentNamed(s) if s == sym::from_method => (),
|
||||||
// `{from_desugaring}` is allowed
|
// `{from_desugaring}` is allowed
|
||||||
Position::ArgumentNamed(s) if s == "from_desugaring" => (),
|
Position::ArgumentNamed(s) if s == sym::from_desugaring => (),
|
||||||
// So is `{A}` if A is a type parameter
|
// So is `{A}` if A is a type parameter
|
||||||
Position::ArgumentNamed(s) => match generics.params.iter().find(|param| {
|
Position::ArgumentNamed(s) => match generics.params.iter().find(|param| {
|
||||||
param.name.as_str() == s
|
param.name.as_symbol() == s
|
||||||
}) {
|
}) {
|
||||||
Some(_) => (),
|
Some(_) => (),
|
||||||
None => {
|
None => {
|
||||||
|
@ -276,7 +276,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString {
|
||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
trait_ref: ty::TraitRef<'tcx>,
|
trait_ref: ty::TraitRef<'tcx>,
|
||||||
options: &FxHashMap<String, String>,
|
options: &FxHashMap<Symbol, String>,
|
||||||
) -> String {
|
) -> String {
|
||||||
let name = tcx.item_name(trait_ref.def_id);
|
let name = tcx.item_name(trait_ref.def_id);
|
||||||
let trait_str = tcx.def_path_str(trait_ref.def_id);
|
let trait_str = tcx.def_path_str(trait_ref.def_id);
|
||||||
|
@ -289,9 +289,9 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString {
|
||||||
},
|
},
|
||||||
GenericParamDefKind::Lifetime => return None
|
GenericParamDefKind::Lifetime => return None
|
||||||
};
|
};
|
||||||
let name = param.name.to_string();
|
let name = param.name.as_symbol();
|
||||||
Some((name, value))
|
Some((name, value))
|
||||||
}).collect::<FxHashMap<String, String>>();
|
}).collect::<FxHashMap<Symbol, String>>();
|
||||||
let empty_string = String::new();
|
let empty_string = String::new();
|
||||||
|
|
||||||
let parser = Parser::new(&self.0, None, vec![], false);
|
let parser = Parser::new(&self.0, None, vec![], false);
|
||||||
|
@ -299,15 +299,15 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString {
|
||||||
match p {
|
match p {
|
||||||
Piece::String(s) => s,
|
Piece::String(s) => s,
|
||||||
Piece::NextArgument(a) => match a.position {
|
Piece::NextArgument(a) => match a.position {
|
||||||
Position::ArgumentNamed(s) => match generic_map.get(s) {
|
Position::ArgumentNamed(s) => match generic_map.get(&s) {
|
||||||
Some(val) => val,
|
Some(val) => val,
|
||||||
None if s == name.as_str() => {
|
None if s == name => {
|
||||||
&trait_str
|
&trait_str
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
if let Some(val) = options.get(s) {
|
if let Some(val) = options.get(&s) {
|
||||||
val
|
val
|
||||||
} else if s == "from_desugaring" || s == "from_method" {
|
} else if s == sym::from_desugaring || s == sym::from_method {
|
||||||
// don't break messages using these two arguments incorrectly
|
// don't break messages using these two arguments incorrectly
|
||||||
&empty_string
|
&empty_string
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -28,7 +28,7 @@ enum ArgumentType {
|
||||||
|
|
||||||
enum Position {
|
enum Position {
|
||||||
Exact(usize),
|
Exact(usize),
|
||||||
Named(String),
|
Named(Symbol),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Context<'a, 'b: 'a> {
|
struct Context<'a, 'b: 'a> {
|
||||||
|
@ -57,7 +57,7 @@ struct Context<'a, 'b: 'a> {
|
||||||
/// Unique format specs seen for each argument.
|
/// Unique format specs seen for each argument.
|
||||||
arg_unique_types: Vec<Vec<ArgumentType>>,
|
arg_unique_types: Vec<Vec<ArgumentType>>,
|
||||||
/// Map from named arguments to their resolved indices.
|
/// Map from named arguments to their resolved indices.
|
||||||
names: FxHashMap<String, usize>,
|
names: FxHashMap<Symbol, usize>,
|
||||||
|
|
||||||
/// The latest consecutive literal strings, or empty if there weren't any.
|
/// The latest consecutive literal strings, or empty if there weren't any.
|
||||||
literal: String,
|
literal: String,
|
||||||
|
@ -127,9 +127,9 @@ fn parse_args<'a>(
|
||||||
ecx: &mut ExtCtxt<'a>,
|
ecx: &mut ExtCtxt<'a>,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
tts: &[tokenstream::TokenTree]
|
tts: &[tokenstream::TokenTree]
|
||||||
) -> Result<(P<ast::Expr>, Vec<P<ast::Expr>>, FxHashMap<String, usize>), DiagnosticBuilder<'a>> {
|
) -> Result<(P<ast::Expr>, Vec<P<ast::Expr>>, FxHashMap<Symbol, usize>), DiagnosticBuilder<'a>> {
|
||||||
let mut args = Vec::<P<ast::Expr>>::new();
|
let mut args = Vec::<P<ast::Expr>>::new();
|
||||||
let mut names = FxHashMap::<String, usize>::default();
|
let mut names = FxHashMap::<Symbol, usize>::default();
|
||||||
|
|
||||||
let mut p = ecx.new_parser_from_tts(tts);
|
let mut p = ecx.new_parser_from_tts(tts);
|
||||||
|
|
||||||
|
@ -158,11 +158,10 @@ fn parse_args<'a>(
|
||||||
"expected ident, positional arguments cannot follow named arguments",
|
"expected ident, positional arguments cannot follow named arguments",
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
let name: &str = &name.as_str();
|
|
||||||
|
|
||||||
p.expect(&token::Eq)?;
|
p.expect(&token::Eq)?;
|
||||||
let e = p.parse_expr()?;
|
let e = p.parse_expr()?;
|
||||||
if let Some(prev) = names.get(name) {
|
if let Some(prev) = names.get(&name) {
|
||||||
ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", name))
|
ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", name))
|
||||||
.span_note(args[*prev].span, "previously here")
|
.span_note(args[*prev].span, "previously here")
|
||||||
.emit();
|
.emit();
|
||||||
|
@ -174,7 +173,7 @@ fn parse_args<'a>(
|
||||||
// if the input is valid, we can simply append to the positional
|
// if the input is valid, we can simply append to the positional
|
||||||
// args. And remember the names.
|
// args. And remember the names.
|
||||||
let slot = args.len();
|
let slot = args.len();
|
||||||
names.insert(name.to_string(), slot);
|
names.insert(name, slot);
|
||||||
args.push(e);
|
args.push(e);
|
||||||
} else {
|
} else {
|
||||||
let e = p.parse_expr()?;
|
let e = p.parse_expr()?;
|
||||||
|
@ -188,7 +187,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||||
fn resolve_name_inplace(&self, p: &mut parse::Piece<'_>) {
|
fn resolve_name_inplace(&self, p: &mut parse::Piece<'_>) {
|
||||||
// NOTE: the `unwrap_or` branch is needed in case of invalid format
|
// NOTE: the `unwrap_or` branch is needed in case of invalid format
|
||||||
// arguments, e.g., `format_args!("{foo}")`.
|
// arguments, e.g., `format_args!("{foo}")`.
|
||||||
let lookup = |s| *self.names.get(s).unwrap_or(&0);
|
let lookup = |s: Symbol| *self.names.get(&s).unwrap_or(&0);
|
||||||
|
|
||||||
match *p {
|
match *p {
|
||||||
parse::String(_) => {}
|
parse::String(_) => {}
|
||||||
|
@ -222,7 +221,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||||
// it's written second, so it should come after width/precision.
|
// it's written second, so it should come after width/precision.
|
||||||
let pos = match arg.position {
|
let pos = match arg.position {
|
||||||
parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => Exact(i),
|
parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => Exact(i),
|
||||||
parse::ArgumentNamed(s) => Named(s.to_string()),
|
parse::ArgumentNamed(s) => Named(s),
|
||||||
};
|
};
|
||||||
|
|
||||||
let ty = Placeholder(arg.format.ty.to_string());
|
let ty = Placeholder(arg.format.ty.to_string());
|
||||||
|
@ -232,7 +231,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_count(&mut self, c: parse::Count<'_>) {
|
fn verify_count(&mut self, c: parse::Count) {
|
||||||
match c {
|
match c {
|
||||||
parse::CountImplied |
|
parse::CountImplied |
|
||||||
parse::CountIs(..) => {}
|
parse::CountIs(..) => {}
|
||||||
|
@ -240,7 +239,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||||
self.verify_arg_type(Exact(i), Count);
|
self.verify_arg_type(Exact(i), Count);
|
||||||
}
|
}
|
||||||
parse::CountIsName(s) => {
|
parse::CountIsName(s) => {
|
||||||
self.verify_arg_type(Named(s.to_string()), Count);
|
self.verify_arg_type(Named(s), Count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -390,7 +389,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||||
ecx.std_path(&[sym::fmt, sym::rt, sym::v1, Symbol::intern(s)])
|
ecx.std_path(&[sym::fmt, sym::rt, sym::v1, Symbol::intern(s)])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_count(&self, c: parse::Count<'_>) -> P<ast::Expr> {
|
fn build_count(&self, c: parse::Count) -> P<ast::Expr> {
|
||||||
let sp = self.macsp;
|
let sp = self.macsp;
|
||||||
let count = |c, arg| {
|
let count = |c, arg| {
|
||||||
let mut path = Context::rtpath(self.ecx, "Count");
|
let mut path = Context::rtpath(self.ecx, "Count");
|
||||||
|
@ -739,7 +738,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt<'_>,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
efmt: P<ast::Expr>,
|
efmt: P<ast::Expr>,
|
||||||
args: Vec<P<ast::Expr>>,
|
args: Vec<P<ast::Expr>>,
|
||||||
names: FxHashMap<String, usize>,
|
names: FxHashMap<Symbol, usize>,
|
||||||
append_newline: bool)
|
append_newline: bool)
|
||||||
-> P<ast::Expr> {
|
-> P<ast::Expr> {
|
||||||
// NOTE: this verbose way of initializing `Vec<Vec<ArgumentType>>` is because
|
// NOTE: this verbose way of initializing `Vec<Vec<ArgumentType>>` is because
|
||||||
|
|
|
@ -203,6 +203,7 @@ symbols! {
|
||||||
core_intrinsics,
|
core_intrinsics,
|
||||||
crate_id,
|
crate_id,
|
||||||
crate_in_paths,
|
crate_in_paths,
|
||||||
|
crate_local,
|
||||||
crate_name,
|
crate_name,
|
||||||
crate_type,
|
crate_type,
|
||||||
crate_visibility_modifier,
|
crate_visibility_modifier,
|
||||||
|
@ -221,6 +222,7 @@ symbols! {
|
||||||
deref,
|
deref,
|
||||||
deref_mut,
|
deref_mut,
|
||||||
derive,
|
derive,
|
||||||
|
direct,
|
||||||
doc,
|
doc,
|
||||||
doc_alias,
|
doc_alias,
|
||||||
doc_cfg,
|
doc_cfg,
|
||||||
|
@ -278,8 +280,10 @@ symbols! {
|
||||||
format_args_nl,
|
format_args_nl,
|
||||||
from,
|
from,
|
||||||
From,
|
From,
|
||||||
|
from_desugaring,
|
||||||
from_error,
|
from_error,
|
||||||
from_generator,
|
from_generator,
|
||||||
|
from_method,
|
||||||
from_ok,
|
from_ok,
|
||||||
from_usize,
|
from_usize,
|
||||||
fundamental,
|
fundamental,
|
||||||
|
@ -443,6 +447,7 @@ symbols! {
|
||||||
panic_impl,
|
panic_impl,
|
||||||
panic_implementation,
|
panic_implementation,
|
||||||
panic_runtime,
|
panic_runtime,
|
||||||
|
parent_trait,
|
||||||
partial_cmp,
|
partial_cmp,
|
||||||
PartialOrd,
|
PartialOrd,
|
||||||
passes,
|
passes,
|
||||||
|
@ -569,6 +574,7 @@ symbols! {
|
||||||
__rust_unstable_column,
|
__rust_unstable_column,
|
||||||
rvalue_static_promotion,
|
rvalue_static_promotion,
|
||||||
sanitizer_runtime,
|
sanitizer_runtime,
|
||||||
|
_Self,
|
||||||
self_in_typedefs,
|
self_in_typedefs,
|
||||||
self_struct_ctor,
|
self_struct_ctor,
|
||||||
Send,
|
Send,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue