errors: implement fallback diagnostic translation

This commit updates the signatures of all diagnostic functions to accept
types that can be converted into a `DiagnosticMessage`. This enables
existing diagnostic calls to continue to work as before and Fluent
identifiers to be provided. The `SessionDiagnostic` derive just
generates normal diagnostic calls, so these APIs had to be modified to
accept Fluent identifiers.

In addition, loading of the "fallback" Fluent bundle, which contains the
built-in English messages, has been implemented.

Each diagnostic now has "arguments" which correspond to variables in the
Fluent messages (necessary to render a Fluent message) but no API for
adding arguments has been added yet. Therefore, diagnostics (that do not
require interpolation) can be converted to use Fluent identifiers and
will be output as before.
This commit is contained in:
David Wood 2022-03-26 07:27:43 +00:00
parent c45f29595d
commit 7f91697b50
46 changed files with 919 additions and 293 deletions

View file

@ -250,7 +250,7 @@ fn check_binders(
if let Some(prev_info) = binders.get(&name) {
// 1. The meta-variable is already bound in the current LHS: This is an error.
let mut span = MultiSpan::from_span(span);
span.push_span_label(prev_info.span, "previous declaration".into());
span.push_span_label(prev_info.span, "previous declaration");
buffer_lint(sess, span, node_id, "duplicate matcher binding");
} else if get_binder_info(macros, binders, name).is_none() {
// 2. The meta-variable is free: This is a binder.
@ -622,7 +622,7 @@ fn ops_is_prefix(
for (i, binder) in binder_ops.iter().enumerate() {
if i >= occurrence_ops.len() {
let mut span = MultiSpan::from_span(span);
span.push_span_label(binder.span, "expected repetition".into());
span.push_span_label(binder.span, "expected repetition");
let message = &format!("variable '{}' is still repeating at this depth", name);
buffer_lint(sess, span, node_id, message);
return;
@ -630,8 +630,8 @@ fn ops_is_prefix(
let occurrence = &occurrence_ops[i];
if occurrence.op != binder.op {
let mut span = MultiSpan::from_span(span);
span.push_span_label(binder.span, "expected repetition".into());
span.push_span_label(occurrence.span, "conflicting repetition".into());
span.push_span_label(binder.span, "expected repetition");
span.push_span_label(occurrence.span, "conflicting repetition");
let message = "meta-variable repeats with different Kleene operator";
buffer_lint(sess, span, node_id, message);
return;

View file

@ -69,7 +69,7 @@ fn emit_frag_parse_err(
kind: AstFragmentKind,
) {
// FIXME(davidtwco): avoid depending on the error message text
if parser.token == token::Eof && e.message().as_str().ends_with(", found `<eof>`") {
if parser.token == token::Eof && e.message[0].0.expect_str().ends_with(", found `<eof>`") {
if !e.span.is_dummy() {
// early end of macro arm (#52866)
e.replace_span_with(parser.sess.source_map().next_point(parser.token.span));
@ -78,7 +78,7 @@ fn emit_frag_parse_err(
e.message[0] = (
rustc_errors::DiagnosticMessage::Str(format!(
"macro expansion ends with an incomplete expression: {}",
msg.0.as_str().replace(", found `<eof>`", ""),
msg.0.expect_str().replace(", found `<eof>`", ""),
)),
msg.1,
);

View file

@ -128,13 +128,15 @@ fn parse_ident<'sess>(
sess: &'sess ParseSess,
span: Span,
) -> PResult<'sess, Ident> {
let err_fn = |msg| sess.span_diagnostic.struct_span_err(span, msg);
if let Some(tt) = iter.next() && let TokenTree::Token(token) = tt {
if let Some((elem, false)) = token.ident() {
return Ok(elem);
}
let token_str = pprust::token_to_string(&token);
let mut err = err_fn(&format!("expected identifier, found `{}`", &token_str));
let mut err = sess.span_diagnostic.struct_span_err(
span,
&format!("expected identifier, found `{}`", &token_str)
);
err.span_suggestion(
token.span,
&format!("try removing `{}`", &token_str),
@ -143,7 +145,7 @@ fn parse_ident<'sess>(
);
return Err(err);
}
Err(err_fn("expected identifier"))
Err(sess.span_diagnostic.struct_span_err(span, "expected identifier"))
}
/// Tries to move the iterator forward returning `true` if there is a comma. If not, then the

View file

@ -127,6 +127,7 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &
create_default_session_if_not_set_then(|_| {
let output = Arc::new(Mutex::new(Vec::new()));
let fallback_bundle = rustc_errors::fallback_fluent_bundle();
let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
source_map.new_source_file(Path::new("test.rs").to_owned().into(), file_text.to_owned());
@ -142,6 +143,7 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &
let emitter = EmitterWriter::new(
Box::new(Shared { data: output.clone() }),
Some(source_map.clone()),
fallback_bundle,
false,
false,
false,