about summary refs log tree commit diff
path: root/src/libsyntax_ext
diff options
context:
space:
mode:
authorTommy Ip <hkmp7tommy@gmail.com>2017-11-06 08:49:47 +0000
committerTommy Ip <hkmp7tommy@gmail.com>2017-11-06 16:28:30 +0000
commit82d5ea4b12d8543c6c8f871881fbbefbf5e63dc2 (patch)
treee2aab4bc2c39eb7916a5d08517807cf9cd0766a6 /src/libsyntax_ext
parent74be072068737ae3ef30be66e34c1569cf652652 (diff)
downloadrust-82d5ea4b12d8543c6c8f871881fbbefbf5e63dc2.tar.gz
rust-82d5ea4b12d8543c6c8f871881fbbefbf5e63dc2.zip
Make format! positional argument errors clear
Diffstat (limited to 'src/libsyntax_ext')
-rw-r--r--src/libsyntax_ext/format.rs49
1 files changed, 41 insertions, 8 deletions
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
index 63c533df198..ceefbfc271c 100644
--- a/src/libsyntax_ext/format.rs
+++ b/src/libsyntax_ext/format.rs
@@ -110,6 +110,8 @@ struct Context<'a, 'b: 'a> {
     /// still existed in this phase of processing.
     /// Used only for `all_pieces_simple` tracking in `trans_piece`.
     curarg: usize,
+    /// Keep track of invalid references to positional arguments
+    invalid_refs: Vec<usize>,
 }
 
 /// Parses the arguments from the given list of tokens, returning None
@@ -251,23 +253,49 @@ impl<'a, 'b> Context<'a, 'b> {
 
     fn describe_num_args(&self) -> String {
         match self.args.len() {
-            0 => "no arguments given".to_string(),
-            1 => "there is 1 argument".to_string(),
-            x => format!("there are {} arguments", x),
+            0 => "no arguments were given".to_string(),
+            1 => "there is only 1 argument".to_string(),
+            x => format!("there are only {} arguments", x),
         }
     }
 
+    /// Handle invalid references to positional arguments. Output different
+    /// errors for the case where all arguments are positional and for when
+    /// there are named arguments in the format string.
+    fn report_invalid_references(&self) {
+        let mut refs: Vec<String> = self.invalid_refs
+                                        .iter()
+                                        .map(|r| r.to_string())
+                                        .collect();
+
+        let msg = if self.names.is_empty() {
+            format!("{} positional argument{} in format string, but {}",
+                    self.pieces.len(),
+                    if self.pieces.len() > 1 { "s" } else { "" },
+                    self.describe_num_args())
+        } else {
+            let arg_list = match refs.len() {
+                1 => format!("argument {}", refs.pop().unwrap()),
+                _ => format!("arguments {head} and {tail}",
+                             tail=refs.pop().unwrap(),
+                             head=refs.join(", "))
+            };
+
+            format!("invalid reference to positional {} ({})",
+                    arg_list,
+                    self.describe_num_args())
+        };
+
+        self.ecx.span_err(self.fmtsp, &msg[..]);
+    }
+
     /// Actually verifies and tracks a given format placeholder
     /// (a.k.a. argument).
     fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) {
         match arg {
             Exact(arg) => {
                 if self.args.len() <= arg {
-                    let msg = format!("invalid reference to argument `{}` ({})",
-                                      arg,
-                                      self.describe_num_args());
-
-                    self.ecx.span_err(self.fmtsp, &msg[..]);
+                    self.invalid_refs.push(arg);
                     return;
                 }
                 match ty {
@@ -691,6 +719,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
         all_pieces_simple: true,
         macsp,
         fmtsp: fmt.span,
+        invalid_refs: Vec::new(),
     };
 
     let fmt_str = &*fmt.node.0.as_str();
@@ -736,6 +765,10 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
         cx.str_pieces.push(s);
     }
 
+    if cx.invalid_refs.len() >= 1 {
+        cx.report_invalid_references();
+    }
+
     // Make sure that all arguments were used and all arguments have types.
     let num_pos_args = cx.args.len() - cx.names.len();
     let mut errs = vec![];