Skip to content

Commit

Permalink
Auto merge of #96468 - davidtwco:diagnostic-translation-subdiagnostic…
Browse files Browse the repository at this point in the history
…, r=oli-obk

macros: subdiagnostic derive

Add a new macro, `#[derive(SessionSubdiagnostic)]`, which can be applied to structs that represent subdiagnostics, such as labels, notes, helps or suggestions.

`#[derive(SessionSubdiagnostic)]` can be used with the existing `#[derive(SessionDiagnostic)]`. All diagnostics implemented using either derive are translatable, and this new derive should make it easier to port existing diagnostics to using these derives.

For example, consider the following subdiagnostic types...

```rust
#[derive(SessionSubdiagnostic)]
pub enum ExpectedIdentifierLabel<'tcx> {
    #[label(slug = "parser-expected-identifier")]
    WithoutFound {
        #[primary_span]
        span: Span,
    }
    #[label(slug = "parser-expected-identifier-found")]
    WithFound {
        #[primary_span]
        span: Span,
        found: String,
    }
}

#[derive(SessionSubdiagnostic)]
#[suggestion_verbose(slug = "parser-raw-identifier")]
pub struct RawIdentifierSuggestion<'tcx> {
    #[primary_span]
    span: Span,
    #[applicability]
    applicability: Applicability,
    ident: Ident,
}
```

...and the corresponding Fluent messages:

```fluent
parser-expected-identifier = expected identifier

parser-expected-identifier-found = expected identifier, found {$found}

parser-raw-identifier = escape `{$ident}` to use it as an identifier
```

These can be emitted using the new `subdiagnostic` function on `Diagnostic`...

```rust
diag.subdiagnostic(ExpectedIdentifierLabel::WithoutFound { span });
diag.subdiagnostic(RawIdentifierSuggestion { span, applicability, ident });
```

...or as part of a larger `#[derive(SessionDiagnostic)]`:

```rust
#[derive(SessionDiagnostic)]
#[error(slug = "parser-expected-identifier")]
pub struct ExpectedIdentifier {
    #[primary_span]
    span: Span,
    token_descr: String,
    #[subdiagnostic]
    label: ExpectedIdentifierLabel,
    #[subdiagnostic]
    raw_identifier_suggestion: Option<RawIdentifierSuggestion>,
}
```

```rust
sess.emit_err(ExpectedIdentifier { ... });
```

r? `@oli-obk`
cc `@pvdrz`
  • Loading branch information
bors committed Apr 29, 2022
2 parents 87937d3 + dca8861 commit 683c582
Show file tree
Hide file tree
Showing 32 changed files with 2,758 additions and 1,105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
err.span_suggestion_verbose(
span,
"consider changing this to be mutable",
" mut ".into(),
" mut ",
Applicability::MaybeIncorrect,
);
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/deriving/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ fn validate_default_attribute(
.span_suggestion_hidden(
attr.span,
"try using `#[default]`",
"#[default]".into(),
"#[default]",
Applicability::MaybeIncorrect,
)
.emit();
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_error_messages/locales/en-US/typeck.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,11 @@ typeck-value-of-associated-struct-already-specified =
typeck-address-of-temporary-taken = cannot take address of a temporary
.label = temporary value
typeck-add-return-type-add = try adding a return type
typeck-add-return-type-missing-here = a return type might be missing here
typeck-expected-default-return-type = expected `()` because of default return type
typeck-expected-return-type = expected `{$expected}` because of return type
28 changes: 21 additions & 7 deletions compiler/rustc_errors/src/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ impl<'source> Into<FluentValue<'source>> for DiagnosticArgValue<'source> {
}
}

/// Trait implemented by error types. This should not be implemented manually. Instead, use
/// `#[derive(SessionSubdiagnostic)]` -- see [rustc_macros::SessionSubdiagnostic].
pub trait AddSubdiagnostic {
/// Add a subdiagnostic to an existing diagnostic.
fn add_to_diagnostic(self, diag: &mut Diagnostic);
}

#[must_use]
#[derive(Clone, Debug, Encodable, Decodable)]
pub struct Diagnostic {
Expand Down Expand Up @@ -605,7 +612,7 @@ impl Diagnostic {
&mut self,
sp: Span,
msg: impl Into<DiagnosticMessage>,
suggestion: String,
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self {
self.span_suggestion_with_style(
Expand All @@ -623,13 +630,13 @@ impl Diagnostic {
&mut self,
sp: Span,
msg: impl Into<DiagnosticMessage>,
suggestion: String,
suggestion: impl ToString,
applicability: Applicability,
style: SuggestionStyle,
) -> &mut Self {
self.push_suggestion(CodeSuggestion {
substitutions: vec![Substitution {
parts: vec![SubstitutionPart { snippet: suggestion, span: sp }],
parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }],
}],
msg: msg.into(),
style,
Expand All @@ -643,7 +650,7 @@ impl Diagnostic {
&mut self,
sp: Span,
msg: impl Into<DiagnosticMessage>,
suggestion: String,
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self {
self.span_suggestion_with_style(
Expand Down Expand Up @@ -711,7 +718,7 @@ impl Diagnostic {
&mut self,
sp: Span,
msg: impl Into<DiagnosticMessage>,
suggestion: String,
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self {
self.span_suggestion_with_style(
Expand All @@ -734,7 +741,7 @@ impl Diagnostic {
&mut self,
sp: Span,
msg: impl Into<DiagnosticMessage>,
suggestion: String,
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self {
self.span_suggestion_with_style(
Expand All @@ -755,7 +762,7 @@ impl Diagnostic {
&mut self,
sp: Span,
msg: impl Into<DiagnosticMessage>,
suggestion: String,
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self {
self.span_suggestion_with_style(
Expand All @@ -768,6 +775,13 @@ impl Diagnostic {
self
}

/// Add a subdiagnostic from a type that implements `SessionSubdiagnostic` - see
/// [rustc_macros::SessionSubdiagnostic].
pub fn subdiagnostic(&mut self, subdiagnostic: impl AddSubdiagnostic) -> &mut Self {
subdiagnostic.add_to_diagnostic(self);
self
}

pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
self.span = sp.into();
if let Some(span) = self.span.primary_span() {
Expand Down
15 changes: 10 additions & 5 deletions compiler/rustc_errors/src/diagnostic_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
&mut self,
sp: Span,
msg: impl Into<DiagnosticMessage>,
suggestion: String,
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn span_suggestions(
Expand All @@ -497,28 +497,28 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
&mut self,
sp: Span,
msg: impl Into<DiagnosticMessage>,
suggestion: String,
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn span_suggestion_verbose(
&mut self,
sp: Span,
msg: impl Into<DiagnosticMessage>,
suggestion: String,
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn span_suggestion_hidden(
&mut self,
sp: Span,
msg: impl Into<DiagnosticMessage>,
suggestion: String,
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn tool_only_span_suggestion(
&mut self,
sp: Span,
msg: impl Into<DiagnosticMessage>,
suggestion: String,
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self);

Expand All @@ -530,6 +530,11 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
name: impl Into<Cow<'static, str>>,
arg: DiagnosticArgValue<'static>,
) -> &mut Self);

forward!(pub fn subdiagnostic(
&mut self,
subdiagnostic: impl crate::AddSubdiagnostic
) -> &mut Self);
}

impl<G: EmissionGuarantee> Debug for DiagnosticBuilder<'_, G> {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_errors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,8 +370,8 @@ impl fmt::Display for ExplicitBug {
impl error::Error for ExplicitBug {}

pub use diagnostic::{
Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId, DiagnosticStyledString,
IntoDiagnosticArg, SubDiagnostic,
AddSubdiagnostic, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId,
DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
};
pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee};
use std::backtrace::Backtrace;
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_expand/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a Meta
err.span_suggestion(
span,
"expected syntax is",
suggestion.into(),
suggestion,
Applicability::HasPlaceholders,
);
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2198,7 +2198,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
err.span_suggestion(
span.with_hi(before_close).shrink_to_hi(),
msg,
",".into(),
",",
Applicability::MachineApplicable,
);
} else {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/array_into_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
diag.span_suggestion(
call.ident.span,
"use `.iter()` instead of `.into_iter()` to avoid ambiguity",
"iter".into(),
"iter",
Applicability::MachineApplicable,
);
if self.for_expr_span == expr.span {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -738,7 +738,7 @@ pub trait LintContext: Sized {
db.span_suggestion_verbose(
span.shrink_to_hi(),
"insert whitespace here to avoid this being parsed as a prefix in Rust 2021",
" ".into(),
" ",
Applicability::MachineApplicable,
);
}
Expand Down
10 changes: 5 additions & 5 deletions compiler/rustc_lint/src/non_fmt_panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
l.span_suggestion_verbose(
arg_span.shrink_to_lo(),
"add a \"{}\" format string to Display the message",
"\"{}\", ".into(),
"\"{}\", ",
fmt_applicability,
);
} else if suggest_debug {
Expand All @@ -186,7 +186,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
"add a \"{{:?}}\" format string to use the Debug implementation of `{}`",
ty,
),
"\"{:?}\", ".into(),
"\"{:?}\", ",
fmt_applicability,
);
}
Expand Down Expand Up @@ -266,13 +266,13 @@ fn check_panic_str<'tcx>(
l.span_suggestion(
arg.span.shrink_to_hi(),
&format!("add the missing argument{}", pluralize!(n_arguments)),
", ...".into(),
", ...",
Applicability::HasPlaceholders,
);
l.span_suggestion(
arg.span.shrink_to_lo(),
"or add a \"{}\" format string to use the message literally",
"\"{}\", ".into(),
"\"{}\", ",
Applicability::MachineApplicable,
);
}
Expand All @@ -297,7 +297,7 @@ fn check_panic_str<'tcx>(
l.span_suggestion(
arg.span.shrink_to_lo(),
"add a \"{}\" format string to use the message literally",
"\"{}\", ".into(),
"\"{}\", ",
Applicability::MachineApplicable,
);
}
Expand Down
Loading

0 comments on commit 683c582

Please sign in to comment.