1
Fork 0

Add more "help: ..."'s to the parser.

Adds a method for printing a fatal error and also a help message to the
parser and uses this in a variety of places to improve error messages.

Closes #12213.
This commit is contained in:
Huon Wilson 2014-11-10 21:58:03 +11:00
parent e621e3216b
commit 26282ac337
3 changed files with 41 additions and 24 deletions

View file

@ -66,6 +66,7 @@ use ast_util::{as_prec, ident_to_path, operator_prec};
use ast_util; use ast_util;
use codemap::{Span, BytePos, Spanned, spanned, mk_sp}; use codemap::{Span, BytePos, Spanned, spanned, mk_sp};
use codemap; use codemap;
use diagnostic;
use ext::tt::macro_parser; use ext::tt::macro_parser;
use parse; use parse;
use parse::attr::ParserAttr; use parse::attr::ParserAttr;
@ -940,6 +941,11 @@ impl<'a> Parser<'a> {
pub fn span_fatal(&mut self, sp: Span, m: &str) -> ! { pub fn span_fatal(&mut self, sp: Span, m: &str) -> ! {
self.sess.span_diagnostic.span_fatal(sp, m) self.sess.span_diagnostic.span_fatal(sp, m)
} }
pub fn span_fatal_help(&mut self, sp: Span, m: &str, help: &str) -> ! {
self.span_err(sp, m);
self.span_help(sp, help);
panic!(diagnostic::FatalError);
}
pub fn span_note(&mut self, sp: Span, m: &str) { pub fn span_note(&mut self, sp: Span, m: &str) {
self.sess.span_diagnostic.span_note(sp, m) self.sess.span_diagnostic.span_note(sp, m)
} }
@ -3702,7 +3708,14 @@ impl<'a> Parser<'a> {
maybe_whole!(no_clone self, NtBlock); maybe_whole!(no_clone self, NtBlock);
let lo = self.span.lo; let lo = self.span.lo;
self.expect(&token::OpenDelim(token::Brace));
if !self.eat(&token::OpenDelim(token::Brace)) {
let sp = self.span;
let tok = self.this_token_to_string();
self.span_fatal_help(sp,
format!("expected `{{`, found `{}`", tok).as_slice(),
"place this code inside a block");
}
return self.parse_block_tail_(lo, DefaultBlock, Vec::new()); return self.parse_block_tail_(lo, DefaultBlock, Vec::new());
} }
@ -4693,9 +4706,10 @@ impl<'a> Parser<'a> {
_ => { _ => {
let span = self.span; let span = self.span;
let token_str = self.this_token_to_string(); let token_str = self.this_token_to_string();
self.span_fatal(span, self.span_fatal_help(span,
format!("expected `,`, or `}}`, found `{}`", format!("expected `,`, or `}}`, found `{}`",
token_str).as_slice()) token_str).as_slice(),
"struct fields should be separated by commas")
} }
} }
a_var a_var
@ -4897,19 +4911,24 @@ impl<'a> Parser<'a> {
(true, false) => (default_path, false), (true, false) => (default_path, false),
(false, true) => (secondary_path, true), (false, true) => (secondary_path, true),
(false, false) => { (false, false) => {
self.span_fatal(id_sp, self.span_fatal_help(id_sp,
format!("file not found for module \ format!("file not found for module `{}`",
`{}`", mod_name).as_slice(),
mod_name).as_slice()); format!("name the file either {} or {} inside \
the directory {}",
default_path_str,
secondary_path_str,
dir_path.display()).as_slice());
} }
(true, true) => { (true, true) => {
self.span_fatal( self.span_fatal_help(
id_sp, id_sp,
format!("file for module `{}` found at both {} \ format!("file for module `{}` found at both {} \
and {}", and {}",
mod_name, mod_name,
default_path_str, default_path_str,
secondary_path_str).as_slice()); secondary_path_str).as_slice(),
"delete or rename one of them to remove the ambiguity");
} }
} }
} }
@ -5062,9 +5081,10 @@ impl<'a> Parser<'a> {
// skip the ident if there is one // skip the ident if there is one
if self.token.is_ident() { self.bump(); } if self.token.is_ident() { self.bump(); }
self.span_err(span, self.span_err(span, "expected `;`, found `as`");
format!("expected `;`, found `as`; perhaps you meant \ self.span_help(span,
to enclose the crate name `{}` in a string?", format!("perhaps you meant to enclose the crate name `{}` in \
a string?",
the_ident.as_str()).as_slice()); the_ident.as_str()).as_slice());
None None
} else { } else {
@ -5574,16 +5594,12 @@ impl<'a> Parser<'a> {
} }
// FAILURE TO PARSE ITEM // FAILURE TO PARSE ITEM
if visibility != Inherited { match visibility {
let mut s = String::from_str("unmatched visibility `"); Inherited => {}
if visibility == Public { Public => {
s.push_str("pub")
} else {
s.push_str("priv")
}
s.push('`');
let last_span = self.last_span; let last_span = self.last_span;
self.span_fatal(last_span, s.as_slice()); self.span_fatal(last_span, "unmatched visibility `pub`");
}
} }
return IoviNone(attrs); return IoviNone(attrs);
} }
@ -5905,4 +5921,3 @@ impl<'a> Parser<'a> {
} }
} }
} }

View file

@ -11,4 +11,5 @@
// Tests that the proper help is displayed in the error message // Tests that the proper help is displayed in the error message
extern crate foo as bar; extern crate foo as bar;
//~^ ERROR expected `;`, found `as`; perhaps you meant to enclose the crate name `foo` in a string? //~^ ERROR expected `;`, found `as`
//~^^ HELP perhaps you meant to enclose the crate name `foo` in a string?

View file

@ -9,6 +9,7 @@
// except according to those terms. // except according to those terms.
mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file`
//~^ HELP name the file either not_a_real_file.rs or not_a_real_file/mod.rs inside the directory
fn main() { fn main() {
assert_eq!(mod_file_aux::bar(), 10); assert_eq!(mod_file_aux::bar(), 10);