Skip to content

Commit 762855d

Browse files
committed
Rollup merge of rust-lang#53215 - ljedrz:refactor_format, r=estebank
Slightly refactor syntax_ext/format expand_preparsed_format_args: - move a potential error `return` earlier in the processing - pre-allocate some of the required space for `cx.pieces` and `cx.str_pieces` - create `cx`-independent objects before `cx` - build `pieces` and `errs` using `collect` instead of a `push` loop describe_num_args: - return `Cow<str>` instead of `String`
2 parents e2d0e3f + aab063a commit 762855d

File tree

1 file changed

+70
-61
lines changed

1 file changed

+70
-61
lines changed

src/libsyntax_ext/format.rs

+70-61
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ use self::Position::*;
1414
use fmt_macros as parse;
1515

1616
use syntax::ast;
17-
use syntax::ext::base;
18-
use syntax::ext::base::*;
17+
use syntax::ext::base::{self, *};
1918
use syntax::ext::build::AstBuilder;
2019
use syntax::feature_gate;
2120
use syntax::parse::token;
@@ -24,6 +23,7 @@ use syntax::symbol::Symbol;
2423
use syntax::tokenstream;
2524
use syntax_pos::{MultiSpan, Span, DUMMY_SP};
2625

26+
use std::borrow::Cow;
2727
use std::collections::hash_map::Entry;
2828
use std::collections::{HashMap, HashSet};
2929

@@ -143,8 +143,10 @@ fn parse_args(ecx: &mut ExtCtxt,
143143
ecx.span_err(sp, "requires at least a format string argument");
144144
return None;
145145
}
146+
146147
let fmtstr = panictry!(p.parse_expr());
147148
let mut named = false;
149+
148150
while p.token != token::Eof {
149151
if !p.eat(&token::Comma) {
150152
ecx.span_err(p.span, "expected token: `,`");
@@ -264,11 +266,11 @@ impl<'a, 'b> Context<'a, 'b> {
264266
}
265267
}
266268

267-
fn describe_num_args(&self) -> String {
269+
fn describe_num_args(&self) -> Cow<str> {
268270
match self.args.len() {
269-
0 => "no arguments were given".to_string(),
270-
1 => "there is 1 argument".to_string(),
271-
x => format!("there are {} arguments", x),
271+
0 => "no arguments were given".into(),
272+
1 => "there is 1 argument".into(),
273+
x => format!("there are {} arguments", x).into(),
272274
}
273275
}
274276

@@ -772,8 +774,10 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
772774
// `ArgumentType` does not derive `Clone`.
773775
let arg_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect();
774776
let arg_unique_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect();
777+
775778
let mut macsp = ecx.call_site();
776779
macsp = macsp.apply_mark(ecx.current_expansion.mark);
780+
777781
let msg = "format argument must be a string literal";
778782
let fmt_sp = efmt.span;
779783
let fmt = match expr_to_spanned_string(ecx, efmt, msg) {
@@ -796,11 +800,46 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
796800
return DummyResult::raw_expr(sp);
797801
}
798802
};
803+
799804
let is_literal = match ecx.codemap().span_to_snippet(fmt_sp) {
800805
Ok(ref s) if s.starts_with("\"") || s.starts_with("r#") => true,
801806
_ => false,
802807
};
803808

809+
let fmt_str = &*fmt.node.0.as_str();
810+
let str_style = match fmt.node.1 {
811+
ast::StrStyle::Cooked => None,
812+
ast::StrStyle::Raw(raw) => Some(raw as usize),
813+
};
814+
815+
let mut parser = parse::Parser::new(fmt_str, str_style);
816+
817+
let mut unverified_pieces = Vec::new();
818+
while let Some(piece) = parser.next() {
819+
if !parser.errors.is_empty() {
820+
break;
821+
} else {
822+
unverified_pieces.push(piece);
823+
}
824+
}
825+
826+
if !parser.errors.is_empty() {
827+
let err = parser.errors.remove(0);
828+
let sp = fmt.span.from_inner_byte_pos(err.start, err.end);
829+
let mut e = ecx.struct_span_err(sp, &format!("invalid format string: {}",
830+
err.description));
831+
e.span_label(sp, err.label + " in format string");
832+
if let Some(note) = err.note {
833+
e.note(&note);
834+
}
835+
e.emit();
836+
return DummyResult::raw_expr(sp);
837+
}
838+
839+
let arg_spans = parser.arg_places.iter()
840+
.map(|&(start, end)| fmt.span.from_inner_byte_pos(start, end))
841+
.collect();
842+
804843
let mut cx = Context {
805844
ecx,
806845
args,
@@ -815,42 +854,22 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
815854
count_positions_count: 0,
816855
count_args_index_offset: 0,
817856
literal: String::new(),
818-
pieces: Vec::new(),
819-
str_pieces: Vec::new(),
857+
pieces: Vec::with_capacity(unverified_pieces.len()),
858+
str_pieces: Vec::with_capacity(unverified_pieces.len()),
820859
all_pieces_simple: true,
821860
macsp,
822861
fmtsp: fmt.span,
823862
invalid_refs: Vec::new(),
824-
arg_spans: Vec::new(),
863+
arg_spans,
825864
is_literal,
826865
};
827866

828-
let fmt_str = &*fmt.node.0.as_str();
829-
let str_style = match fmt.node.1 {
830-
ast::StrStyle::Cooked => None,
831-
ast::StrStyle::Raw(raw) => Some(raw as usize),
832-
};
833-
let mut parser = parse::Parser::new(fmt_str, str_style);
834-
let mut unverified_pieces = vec![];
835-
let mut pieces = vec![];
836-
837-
while let Some(piece) = parser.next() {
838-
if !parser.errors.is_empty() {
839-
break;
840-
}
841-
unverified_pieces.push(piece);
842-
}
843-
844-
cx.arg_spans = parser.arg_places.iter()
845-
.map(|&(start, end)| fmt.span.from_inner_byte_pos(start, end))
846-
.collect();
847-
848867
// This needs to happen *after* the Parser has consumed all pieces to create all the spans
849-
for mut piece in unverified_pieces {
868+
let pieces = unverified_pieces.into_iter().map(|mut piece| {
850869
cx.verify_piece(&piece);
851870
cx.resolve_name_inplace(&mut piece);
852-
pieces.push(piece);
853-
}
871+
piece
872+
}).collect::<Vec<_>>();
854873

855874
let numbered_position_args = pieces.iter().any(|arg: &parse::Piece| {
856875
match *arg {
@@ -867,6 +886,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
867886
cx.build_index_map();
868887

869888
let mut arg_index_consumed = vec![0usize; cx.arg_index_map.len()];
889+
870890
for piece in pieces {
871891
if let Some(piece) = cx.build_piece(&piece, &mut arg_index_consumed) {
872892
let s = cx.build_literal_string();
@@ -875,18 +895,6 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
875895
}
876896
}
877897

878-
if !parser.errors.is_empty() {
879-
let err = parser.errors.remove(0);
880-
let sp = cx.fmtsp.from_inner_byte_pos(err.start, err.end);
881-
let mut e = cx.ecx.struct_span_err(sp, &format!("invalid format string: {}",
882-
err.description));
883-
e.span_label(sp, err.label + " in format string");
884-
if let Some(note) = err.note {
885-
e.note(&note);
886-
}
887-
e.emit();
888-
return DummyResult::raw_expr(sp);
889-
}
890898
if !cx.literal.is_empty() {
891899
let s = cx.build_literal_string();
892900
cx.str_pieces.push(s);
@@ -898,24 +906,25 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
898906

899907
// Make sure that all arguments were used and all arguments have types.
900908
let num_pos_args = cx.args.len() - cx.names.len();
901-
let mut errs = vec![];
902-
for (i, ty) in cx.arg_types.iter().enumerate() {
903-
if ty.len() == 0 {
904-
if cx.count_positions.contains_key(&i) {
905-
continue;
906-
}
907-
let msg = if i >= num_pos_args {
908-
// named argument
909-
"named argument never used"
910-
} else {
911-
// positional argument
912-
"argument never used"
913-
};
914-
errs.push((cx.args[i].span, msg));
915-
}
916-
}
909+
910+
let errs = cx.arg_types
911+
.iter()
912+
.enumerate()
913+
.filter(|(i, ty)| ty.is_empty() && !cx.count_positions.contains_key(&i))
914+
.map(|(i, _)| {
915+
let msg = if i >= num_pos_args {
916+
// named argument
917+
"named argument never used"
918+
} else {
919+
// positional argument
920+
"argument never used"
921+
};
922+
(cx.args[i].span, msg)
923+
})
924+
.collect::<Vec<_>>();
925+
917926
let errs_len = errs.len();
918-
if errs_len > 0 {
927+
if !errs.is_empty() {
919928
let args_used = cx.arg_types.len() - errs_len;
920929
let args_unused = errs_len;
921930

0 commit comments

Comments
 (0)