Point at formatting descriptor string when it is invalid
When a formatting string contains an invalid descriptor, point at it instead of the argument: ``` error: unknown format trait `foo` --> $DIR/ifmt-bad-arg.rs:86:17 | LL | println!("{:foo}", 1); | ^^^ | = note: the only appropriate formatting traits are: - ``, which uses the `Display` trait - `?`, which uses the `Debug` trait - `e`, which uses the `LowerExp` trait - `E`, which uses the `UpperExp` trait - `o`, which uses the `Octal` trait - `p`, which uses the `Pointer` trait - `b`, which uses the `Binary` trait - `x`, which uses the `LowerHex` trait - `X`, which uses the `UpperHex` trait ```
This commit is contained in:
parent
3a1b3b30c6
commit
08b235b5be
4 changed files with 47 additions and 37 deletions
|
@ -74,6 +74,8 @@ pub struct FormatSpec<'a> {
|
||||||
/// 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.
|
||||||
pub ty: &'a str,
|
pub ty: &'a str,
|
||||||
|
/// The span of the descriptor string (for diagnostics).
|
||||||
|
pub ty_span: Option<InnerSpan>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enum describing where an argument for a format can be located.
|
/// Enum describing where an argument for a format can be located.
|
||||||
|
@ -475,6 +477,7 @@ impl<'a> Parser<'a> {
|
||||||
width: CountImplied,
|
width: CountImplied,
|
||||||
width_span: None,
|
width_span: None,
|
||||||
ty: &self.input[..0],
|
ty: &self.input[..0],
|
||||||
|
ty_span: None,
|
||||||
};
|
};
|
||||||
if !self.consume(':') {
|
if !self.consume(':') {
|
||||||
return spec;
|
return spec;
|
||||||
|
@ -548,6 +551,7 @@ impl<'a> Parser<'a> {
|
||||||
spec.precision_span = sp;
|
spec.precision_span = sp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let ty_span_start = self.cur.peek().map(|(pos, _)| *pos);
|
||||||
// Optional radix followed by the actual format specifier
|
// Optional radix followed by the actual format specifier
|
||||||
if self.consume('x') {
|
if self.consume('x') {
|
||||||
if self.consume('?') {
|
if self.consume('?') {
|
||||||
|
@ -567,6 +571,11 @@ impl<'a> Parser<'a> {
|
||||||
spec.ty = "?";
|
spec.ty = "?";
|
||||||
} else {
|
} else {
|
||||||
spec.ty = self.word();
|
spec.ty = self.word();
|
||||||
|
let ty_span_end = self.cur.peek().map(|(pos, _)| *pos);
|
||||||
|
let this = self;
|
||||||
|
spec.ty_span = ty_span_start
|
||||||
|
.and_then(|s| ty_span_end.map(|e| (s, e)))
|
||||||
|
.map(|(start, end)| this.to_span_index(start).to(this.to_span_index(end)));
|
||||||
}
|
}
|
||||||
spec
|
spec
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ use std::collections::hash_map::Entry;
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
enum ArgumentType {
|
enum ArgumentType {
|
||||||
Placeholder(String),
|
Placeholder(&'static str),
|
||||||
Count,
|
Count,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,7 +244,36 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||||
parse::ArgumentNamed(s) => Named(s),
|
parse::ArgumentNamed(s) => Named(s),
|
||||||
};
|
};
|
||||||
|
|
||||||
let ty = Placeholder(arg.format.ty.to_string());
|
let ty = Placeholder(match &arg.format.ty[..] {
|
||||||
|
"" => "Display",
|
||||||
|
"?" => "Debug",
|
||||||
|
"e" => "LowerExp",
|
||||||
|
"E" => "UpperExp",
|
||||||
|
"o" => "Octal",
|
||||||
|
"p" => "Pointer",
|
||||||
|
"b" => "Binary",
|
||||||
|
"x" => "LowerHex",
|
||||||
|
"X" => "UpperHex",
|
||||||
|
_ => {
|
||||||
|
let fmtsp = self.fmtsp;
|
||||||
|
let mut err = self.ecx.struct_span_err(
|
||||||
|
arg.format.ty_span.map(|sp| fmtsp.from_inner(sp)).unwrap_or(fmtsp),
|
||||||
|
&format!("unknown format trait `{}`", arg.format.ty),
|
||||||
|
);
|
||||||
|
err.note("the only appropriate formatting traits are:\n\
|
||||||
|
- ``, which uses the `Display` trait\n\
|
||||||
|
- `?`, which uses the `Debug` trait\n\
|
||||||
|
- `e`, which uses the `LowerExp` trait\n\
|
||||||
|
- `E`, which uses the `UpperExp` trait\n\
|
||||||
|
- `o`, which uses the `Octal` trait\n\
|
||||||
|
- `p`, which uses the `Pointer` trait\n\
|
||||||
|
- `b`, which uses the `Binary` trait\n\
|
||||||
|
- `x`, which uses the `LowerHex` trait\n\
|
||||||
|
- `X`, which uses the `UpperHex` trait");
|
||||||
|
err.emit();
|
||||||
|
"<invalid>"
|
||||||
|
}
|
||||||
|
});
|
||||||
self.verify_arg_type(pos, ty);
|
self.verify_arg_type(pos, ty);
|
||||||
self.curpiece += 1;
|
self.curpiece += 1;
|
||||||
}
|
}
|
||||||
|
@ -588,6 +617,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||||
width: parse::CountImplied,
|
width: parse::CountImplied,
|
||||||
width_span: None,
|
width_span: None,
|
||||||
ty: arg.format.ty,
|
ty: arg.format.ty,
|
||||||
|
ty_span: arg.format.ty_span,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -759,37 +789,8 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||||
sp = ecx.with_def_site_ctxt(sp);
|
sp = ecx.with_def_site_ctxt(sp);
|
||||||
let arg = ecx.expr_ident(sp, arg);
|
let arg = ecx.expr_ident(sp, arg);
|
||||||
let trait_ = match *ty {
|
let trait_ = match *ty {
|
||||||
Placeholder(ref tyname) => {
|
Placeholder(trait_) if trait_ == "<invalid>" => return DummyResult::raw_expr(sp, true),
|
||||||
match &tyname[..] {
|
Placeholder(trait_) => trait_,
|
||||||
"" => "Display",
|
|
||||||
"?" => "Debug",
|
|
||||||
"e" => "LowerExp",
|
|
||||||
"E" => "UpperExp",
|
|
||||||
"o" => "Octal",
|
|
||||||
"p" => "Pointer",
|
|
||||||
"b" => "Binary",
|
|
||||||
"x" => "LowerHex",
|
|
||||||
"X" => "UpperHex",
|
|
||||||
_ => {
|
|
||||||
let mut err = ecx.struct_span_err(
|
|
||||||
sp,
|
|
||||||
&format!("unknown format trait `{}`", *tyname),
|
|
||||||
);
|
|
||||||
err.note("the only appropriate formatting traits are:\n\
|
|
||||||
- ``, which uses the `Display` trait\n\
|
|
||||||
- `?`, which uses the `Debug` trait\n\
|
|
||||||
- `e`, which uses the `LowerExp` trait\n\
|
|
||||||
- `E`, which uses the `UpperExp` trait\n\
|
|
||||||
- `o`, which uses the `Octal` trait\n\
|
|
||||||
- `p`, which uses the `Pointer` trait\n\
|
|
||||||
- `b`, which uses the `Binary` trait\n\
|
|
||||||
- `x`, which uses the `LowerHex` trait\n\
|
|
||||||
- `X`, which uses the `UpperHex` trait");
|
|
||||||
err.emit();
|
|
||||||
return DummyResult::raw_expr(sp, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Count => {
|
Count => {
|
||||||
let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, sym::from_usize]);
|
let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, sym::from_usize]);
|
||||||
return ecx.expr_call_global(macsp, path, vec![arg]);
|
return ecx.expr_call_global(macsp, path, vec![arg]);
|
||||||
|
|
|
@ -257,10 +257,10 @@ LL | println!("{} {:07$} {}", 1, 3.2, 4);
|
||||||
= note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
|
= note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
|
||||||
|
|
||||||
error: unknown format trait `foo`
|
error: unknown format trait `foo`
|
||||||
--> $DIR/ifmt-bad-arg.rs:86:24
|
--> $DIR/ifmt-bad-arg.rs:86:17
|
||||||
|
|
|
|
||||||
LL | println!("{:foo}", 1);
|
LL | println!("{:foo}", 1);
|
||||||
| ^
|
| ^^^
|
||||||
|
|
|
|
||||||
= note: the only appropriate formatting traits are:
|
= note: the only appropriate formatting traits are:
|
||||||
- ``, which uses the `Display` trait
|
- ``, which uses the `Display` trait
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: unknown format trait `notimplemented`
|
error: unknown format trait `notimplemented`
|
||||||
--> $DIR/ifmt-unknown-trait.rs:2:34
|
--> $DIR/ifmt-unknown-trait.rs:2:16
|
||||||
|
|
|
|
||||||
LL | format!("{:notimplemented}", "3");
|
LL | format!("{:notimplemented}", "3");
|
||||||
| ^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: the only appropriate formatting traits are:
|
= note: the only appropriate formatting traits are:
|
||||||
- ``, which uses the `Display` trait
|
- ``, which uses the `Display` trait
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue