Allow specifying multiple alternative suggestions
This allows porting uses of span_suggestions() to diagnostic structs. Doesn't work for multipart_suggestions() because the rank would be reversed - the struct would specify multiple spans, each of which has multiple possible replacements, while multipart_suggestions() creates multiple possible replacements, each with multiple spans.
This commit is contained in:
parent
9be2f35a4c
commit
8bc43f99e9
8 changed files with 263 additions and 26 deletions
|
@ -690,6 +690,24 @@ impl Diagnostic {
|
||||||
msg: impl Into<SubdiagnosticMessage>,
|
msg: impl Into<SubdiagnosticMessage>,
|
||||||
suggestions: impl Iterator<Item = String>,
|
suggestions: impl Iterator<Item = String>,
|
||||||
applicability: Applicability,
|
applicability: Applicability,
|
||||||
|
) -> &mut Self {
|
||||||
|
self.span_suggestions_with_style(
|
||||||
|
sp,
|
||||||
|
msg,
|
||||||
|
suggestions,
|
||||||
|
applicability,
|
||||||
|
SuggestionStyle::ShowCode,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// [`Diagnostic::span_suggestions()`] but you can set the [`SuggestionStyle`].
|
||||||
|
pub fn span_suggestions_with_style(
|
||||||
|
&mut self,
|
||||||
|
sp: Span,
|
||||||
|
msg: impl Into<SubdiagnosticMessage>,
|
||||||
|
suggestions: impl Iterator<Item = String>,
|
||||||
|
applicability: Applicability,
|
||||||
|
style: SuggestionStyle,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
let mut suggestions: Vec<_> = suggestions.collect();
|
let mut suggestions: Vec<_> = suggestions.collect();
|
||||||
suggestions.sort();
|
suggestions.sort();
|
||||||
|
@ -706,14 +724,15 @@ impl Diagnostic {
|
||||||
self.push_suggestion(CodeSuggestion {
|
self.push_suggestion(CodeSuggestion {
|
||||||
substitutions,
|
substitutions,
|
||||||
msg: self.subdiagnostic_message_to_diagnostic_message(msg),
|
msg: self.subdiagnostic_message_to_diagnostic_message(msg),
|
||||||
style: SuggestionStyle::ShowCode,
|
style,
|
||||||
applicability,
|
applicability,
|
||||||
});
|
});
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints out a message with multiple suggested edits of the code.
|
/// Prints out a message with multiple suggested edits of the code, where each edit consists of
|
||||||
/// See also [`Diagnostic::span_suggestion()`].
|
/// multiple parts.
|
||||||
|
/// See also [`Diagnostic::multipart_suggestion()`].
|
||||||
pub fn multipart_suggestions(
|
pub fn multipart_suggestions(
|
||||||
&mut self,
|
&mut self,
|
||||||
msg: impl Into<SubdiagnosticMessage>,
|
msg: impl Into<SubdiagnosticMessage>,
|
||||||
|
@ -745,6 +764,7 @@ impl Diagnostic {
|
||||||
});
|
});
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints out a message with a suggested edit of the code. If the suggestion is presented
|
/// Prints out a message with a suggested edit of the code. If the suggestion is presented
|
||||||
/// inline, it will only show the message and not the suggestion.
|
/// inline, it will only show the message and not the suggestion.
|
||||||
///
|
///
|
||||||
|
|
|
@ -454,7 +454,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
||||||
|
|
||||||
self.formatting_init.extend(code_init);
|
self.formatting_init.extend(code_init);
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
#diag.span_suggestion_with_style(
|
#diag.span_suggestions_with_style(
|
||||||
#span_field,
|
#span_field,
|
||||||
rustc_errors::fluent::#slug,
|
rustc_errors::fluent::#slug,
|
||||||
#code_field,
|
#code_field,
|
||||||
|
|
|
@ -11,9 +11,11 @@ use crate::diagnostics::utils::{
|
||||||
};
|
};
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path};
|
use syn::{spanned::Spanned, Attribute, Meta, MetaList, NestedMeta, Path};
|
||||||
use synstructure::{BindingInfo, Structure, VariantInfo};
|
use synstructure::{BindingInfo, Structure, VariantInfo};
|
||||||
|
|
||||||
|
use super::utils::{build_suggestion_code, AllowMultipleAlternatives};
|
||||||
|
|
||||||
/// The central struct for constructing the `add_to_diagnostic` method from an annotated struct.
|
/// The central struct for constructing the `add_to_diagnostic` method from an annotated struct.
|
||||||
pub(crate) struct SubdiagnosticDeriveBuilder {
|
pub(crate) struct SubdiagnosticDeriveBuilder {
|
||||||
diag: syn::Ident,
|
diag: syn::Ident,
|
||||||
|
@ -414,15 +416,16 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
||||||
let nested_name = meta.path().segments.last().unwrap().ident.to_string();
|
let nested_name = meta.path().segments.last().unwrap().ident.to_string();
|
||||||
let nested_name = nested_name.as_str();
|
let nested_name = nested_name.as_str();
|
||||||
|
|
||||||
let Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) = meta else {
|
|
||||||
throw_invalid_nested_attr!(attr, &nested_attr);
|
|
||||||
};
|
|
||||||
|
|
||||||
match nested_name {
|
match nested_name {
|
||||||
"code" => {
|
"code" => {
|
||||||
let formatted_str = self.build_format(&value.value(), value.span());
|
|
||||||
let code_field = new_code_ident();
|
let code_field = new_code_ident();
|
||||||
code.set_once((code_field, formatted_str), span);
|
let formatting_init = build_suggestion_code(
|
||||||
|
&code_field,
|
||||||
|
meta,
|
||||||
|
self,
|
||||||
|
AllowMultipleAlternatives::No,
|
||||||
|
);
|
||||||
|
code.set_once((code_field, formatting_init), span);
|
||||||
}
|
}
|
||||||
_ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
|
_ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
|
||||||
diag.help("`code` is the only valid nested attribute")
|
diag.help("`code` is the only valid nested attribute")
|
||||||
|
@ -430,14 +433,14 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some((code_field, formatted_str)) = code.value() else {
|
let Some((code_field, formatting_init)) = code.value() else {
|
||||||
span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`")
|
span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`")
|
||||||
.emit();
|
.emit();
|
||||||
return Ok(quote! {});
|
return Ok(quote! {});
|
||||||
};
|
};
|
||||||
let binding = info.binding;
|
let binding = info.binding;
|
||||||
|
|
||||||
self.formatting_init.extend(quote! { let #code_field = #formatted_str; });
|
self.formatting_init.extend(formatting_init);
|
||||||
let code_field = if clone_suggestion_code {
|
let code_field = if clone_suggestion_code {
|
||||||
quote! { #code_field.clone() }
|
quote! { #code_field.clone() }
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::diagnostics::error::{
|
||||||
span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err, DiagnosticDeriveError,
|
span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err, DiagnosticDeriveError,
|
||||||
};
|
};
|
||||||
use proc_macro::Span;
|
use proc_macro::Span;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::{Ident, TokenStream};
|
||||||
use quote::{format_ident, quote, ToTokens};
|
use quote::{format_ident, quote, ToTokens};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::{BTreeSet, HashMap};
|
use std::collections::{BTreeSet, HashMap};
|
||||||
|
@ -395,6 +395,82 @@ pub(super) fn build_field_mapping<'v>(variant: &VariantInfo<'v>) -> HashMap<Stri
|
||||||
fields_map
|
fields_map
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub(super) enum AllowMultipleAlternatives {
|
||||||
|
No,
|
||||||
|
Yes,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs the `format!()` invocation(s) necessary for a `#[suggestion*(code = "foo")]` or
|
||||||
|
/// `#[suggestion*(code("foo", "bar"))]` attribute field
|
||||||
|
pub(super) fn build_suggestion_code(
|
||||||
|
code_field: &Ident,
|
||||||
|
meta: &Meta,
|
||||||
|
fields: &impl HasFieldMap,
|
||||||
|
allow_multiple: AllowMultipleAlternatives,
|
||||||
|
) -> TokenStream {
|
||||||
|
let values = match meta {
|
||||||
|
// `code = "foo"`
|
||||||
|
Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => vec![s],
|
||||||
|
// `code("foo", "bar")`
|
||||||
|
Meta::List(MetaList { nested, .. }) => {
|
||||||
|
if let AllowMultipleAlternatives::No = allow_multiple {
|
||||||
|
span_err(
|
||||||
|
meta.span().unwrap(),
|
||||||
|
"expected exactly one string literal for `code = ...`",
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
vec![]
|
||||||
|
} else if nested.is_empty() {
|
||||||
|
span_err(
|
||||||
|
meta.span().unwrap(),
|
||||||
|
"expected at least one string literal for `code(...)`",
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
vec![]
|
||||||
|
} else {
|
||||||
|
nested
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|item| {
|
||||||
|
if let NestedMeta::Lit(syn::Lit::Str(s)) = item {
|
||||||
|
Some(s)
|
||||||
|
} else {
|
||||||
|
span_err(
|
||||||
|
item.span().unwrap(),
|
||||||
|
"`code(...)` must contain only string literals",
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
span_err(
|
||||||
|
meta.span().unwrap(),
|
||||||
|
r#"`code = "..."`/`code(...)` must contain only string literals"#,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let AllowMultipleAlternatives::Yes = allow_multiple {
|
||||||
|
let formatted_strings: Vec<_> = values
|
||||||
|
.into_iter()
|
||||||
|
.map(|value| fields.build_format(&value.value(), value.span()))
|
||||||
|
.collect();
|
||||||
|
quote! { let #code_field = [#(#formatted_strings),*].into_iter(); }
|
||||||
|
} else if let [value] = values.as_slice() {
|
||||||
|
let formatted_str = fields.build_format(&value.value(), value.span());
|
||||||
|
quote! { let #code_field = #formatted_str; }
|
||||||
|
} else {
|
||||||
|
// error handled previously
|
||||||
|
quote! { let #code_field = String::new(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Possible styles for suggestion subdiagnostics.
|
/// Possible styles for suggestion subdiagnostics.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub(super) enum SuggestionKind {
|
pub(super) enum SuggestionKind {
|
||||||
|
@ -571,21 +647,23 @@ impl SubdiagnosticKind {
|
||||||
let nested_name = meta.path().segments.last().unwrap().ident.to_string();
|
let nested_name = meta.path().segments.last().unwrap().ident.to_string();
|
||||||
let nested_name = nested_name.as_str();
|
let nested_name = nested_name.as_str();
|
||||||
|
|
||||||
let value = match meta {
|
let string_value = match meta {
|
||||||
Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) => value,
|
Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) => Some(value),
|
||||||
|
|
||||||
Meta::Path(_) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
|
Meta::Path(_) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
|
||||||
diag.help("a diagnostic slug must be the first argument to the attribute")
|
diag.help("a diagnostic slug must be the first argument to the attribute")
|
||||||
}),
|
}),
|
||||||
_ => {
|
_ => None,
|
||||||
invalid_nested_attr(attr, &nested_attr).emit();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match (nested_name, &mut kind) {
|
match (nested_name, &mut kind) {
|
||||||
("code", SubdiagnosticKind::Suggestion { code_field, .. }) => {
|
("code", SubdiagnosticKind::Suggestion { code_field, .. }) => {
|
||||||
let formatted_str = fields.build_format(&value.value(), value.span());
|
let code_init = build_suggestion_code(
|
||||||
let code_init = quote! { let #code_field = #formatted_str; };
|
code_field,
|
||||||
|
meta,
|
||||||
|
fields,
|
||||||
|
AllowMultipleAlternatives::Yes,
|
||||||
|
);
|
||||||
code.set_once(code_init, span);
|
code.set_once(code_init, span);
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
|
@ -593,6 +671,11 @@ impl SubdiagnosticKind {
|
||||||
SubdiagnosticKind::Suggestion { ref mut applicability, .. }
|
SubdiagnosticKind::Suggestion { ref mut applicability, .. }
|
||||||
| SubdiagnosticKind::MultipartSuggestion { ref mut applicability, .. },
|
| SubdiagnosticKind::MultipartSuggestion { ref mut applicability, .. },
|
||||||
) => {
|
) => {
|
||||||
|
let Some(value) = string_value else {
|
||||||
|
invalid_nested_attr(attr, &nested_attr).emit();
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
let value = Applicability::from_str(&value.value()).unwrap_or_else(|()| {
|
let value = Applicability::from_str(&value.value()).unwrap_or_else(|()| {
|
||||||
span_err(span, "invalid applicability").emit();
|
span_err(span, "invalid applicability").emit();
|
||||||
Applicability::Unspecified
|
Applicability::Unspecified
|
||||||
|
@ -623,7 +706,7 @@ impl SubdiagnosticKind {
|
||||||
init
|
init
|
||||||
} else {
|
} else {
|
||||||
span_err(span, "suggestion without `code = \"...\"`").emit();
|
span_err(span, "suggestion without `code = \"...\"`").emit();
|
||||||
quote! { let #code_field: String = unreachable!(); }
|
quote! { let #code_field = std::iter::empty(); }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
SubdiagnosticKind::Label
|
SubdiagnosticKind::Label
|
||||||
|
@ -644,7 +727,7 @@ impl quote::IdentFragment for SubdiagnosticKind {
|
||||||
SubdiagnosticKind::Note => write!(f, "note"),
|
SubdiagnosticKind::Note => write!(f, "note"),
|
||||||
SubdiagnosticKind::Help => write!(f, "help"),
|
SubdiagnosticKind::Help => write!(f, "help"),
|
||||||
SubdiagnosticKind::Warn => write!(f, "warn"),
|
SubdiagnosticKind::Warn => write!(f, "warn"),
|
||||||
SubdiagnosticKind::Suggestion { .. } => write!(f, "suggestion_with_style"),
|
SubdiagnosticKind::Suggestion { .. } => write!(f, "suggestions_with_style"),
|
||||||
SubdiagnosticKind::MultipartSuggestion { .. } => {
|
SubdiagnosticKind::MultipartSuggestion { .. } => {
|
||||||
write!(f, "multipart_suggestion_with_style")
|
write!(f, "multipart_suggestion_with_style")
|
||||||
}
|
}
|
||||||
|
|
|
@ -758,3 +758,41 @@ struct WithDocComment {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(compiletest_example)]
|
||||||
|
struct SuggestionsGood {
|
||||||
|
#[suggestion(code("foo", "bar"))]
|
||||||
|
sub: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(compiletest_example)]
|
||||||
|
struct SuggestionsSingleItem {
|
||||||
|
#[suggestion(code("foo"))]
|
||||||
|
sub: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(compiletest_example)]
|
||||||
|
struct SuggestionsNoItem {
|
||||||
|
#[suggestion(code())]
|
||||||
|
//~^ ERROR expected at least one string literal for `code(...)`
|
||||||
|
sub: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(compiletest_example)]
|
||||||
|
struct SuggestionsInvalidItem {
|
||||||
|
#[suggestion(code(foo))]
|
||||||
|
//~^ ERROR `code(...)` must contain only string literals
|
||||||
|
sub: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(compiletest_example)]
|
||||||
|
struct SuggestionsInvalidLiteral {
|
||||||
|
#[suggestion(code = 3)]
|
||||||
|
//~^ ERROR `code = "..."`/`code(...)` must contain only string literals
|
||||||
|
sub: Span,
|
||||||
|
}
|
||||||
|
|
|
@ -573,6 +573,24 @@ LL | #[subdiagnostic(eager)]
|
||||||
|
|
|
|
||||||
= help: eager subdiagnostics are not supported on lints
|
= help: eager subdiagnostics are not supported on lints
|
||||||
|
|
||||||
|
error: expected at least one string literal for `code(...)`
|
||||||
|
--> $DIR/diagnostic-derive.rs:779:18
|
||||||
|
|
|
||||||
|
LL | #[suggestion(code())]
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error: `code(...)` must contain only string literals
|
||||||
|
--> $DIR/diagnostic-derive.rs:787:23
|
||||||
|
|
|
||||||
|
LL | #[suggestion(code(foo))]
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: `code = "..."`/`code(...)` must contain only string literals
|
||||||
|
--> $DIR/diagnostic-derive.rs:795:18
|
||||||
|
|
|
||||||
|
LL | #[suggestion(code = 3)]
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: cannot find attribute `nonsense` in this scope
|
error: cannot find attribute `nonsense` in this scope
|
||||||
--> $DIR/diagnostic-derive.rs:55:3
|
--> $DIR/diagnostic-derive.rs:55:3
|
||||||
|
|
|
|
||||||
|
@ -647,7 +665,7 @@ LL | arg: impl IntoDiagnosticArg,
|
||||||
| ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg`
|
| ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg`
|
||||||
= note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: aborting due to 80 previous errors
|
error: aborting due to 83 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0277, E0425.
|
Some errors have detailed explanations: E0277, E0425.
|
||||||
For more information about an error, try `rustc --explain E0277`.
|
For more information about an error, try `rustc --explain E0277`.
|
||||||
|
|
|
@ -661,3 +661,48 @@ enum BL {
|
||||||
span: Span,
|
span: Span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[multipart_suggestion(parser_add_paren)]
|
||||||
|
struct BM {
|
||||||
|
#[suggestion_part(code("foo"))]
|
||||||
|
//~^ ERROR expected exactly one string literal for `code = ...`
|
||||||
|
span: Span,
|
||||||
|
r#type: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[multipart_suggestion(parser_add_paren)]
|
||||||
|
struct BN {
|
||||||
|
#[suggestion_part(code("foo", "bar"))]
|
||||||
|
//~^ ERROR expected exactly one string literal for `code = ...`
|
||||||
|
span: Span,
|
||||||
|
r#type: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[multipart_suggestion(parser_add_paren)]
|
||||||
|
struct BO {
|
||||||
|
#[suggestion_part(code(3))]
|
||||||
|
//~^ ERROR expected exactly one string literal for `code = ...`
|
||||||
|
span: Span,
|
||||||
|
r#type: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[multipart_suggestion(parser_add_paren)]
|
||||||
|
struct BP {
|
||||||
|
#[suggestion_part(code())]
|
||||||
|
//~^ ERROR expected exactly one string literal for `code = ...`
|
||||||
|
span: Span,
|
||||||
|
r#type: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[multipart_suggestion(parser_add_paren)]
|
||||||
|
struct BQ {
|
||||||
|
#[suggestion_part(code = 3)]
|
||||||
|
//~^ ERROR `code = "..."`/`code(...)` must contain only string literals
|
||||||
|
span: Span,
|
||||||
|
r#type: String,
|
||||||
|
}
|
||||||
|
|
|
@ -415,6 +415,36 @@ error: `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_sugg
|
||||||
LL | #[applicability]
|
LL | #[applicability]
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: expected exactly one string literal for `code = ...`
|
||||||
|
--> $DIR/subdiagnostic-derive.rs:668:23
|
||||||
|
|
|
||||||
|
LL | #[suggestion_part(code("foo"))]
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: expected exactly one string literal for `code = ...`
|
||||||
|
--> $DIR/subdiagnostic-derive.rs:677:23
|
||||||
|
|
|
||||||
|
LL | #[suggestion_part(code("foo", "bar"))]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: expected exactly one string literal for `code = ...`
|
||||||
|
--> $DIR/subdiagnostic-derive.rs:686:23
|
||||||
|
|
|
||||||
|
LL | #[suggestion_part(code(3))]
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error: expected exactly one string literal for `code = ...`
|
||||||
|
--> $DIR/subdiagnostic-derive.rs:695:23
|
||||||
|
|
|
||||||
|
LL | #[suggestion_part(code())]
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error: `code = "..."`/`code(...)` must contain only string literals
|
||||||
|
--> $DIR/subdiagnostic-derive.rs:704:23
|
||||||
|
|
|
||||||
|
LL | #[suggestion_part(code = 3)]
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: cannot find attribute `foo` in this scope
|
error: cannot find attribute `foo` in this scope
|
||||||
--> $DIR/subdiagnostic-derive.rs:63:3
|
--> $DIR/subdiagnostic-derive.rs:63:3
|
||||||
|
|
|
|
||||||
|
@ -475,6 +505,6 @@ error[E0425]: cannot find value `slug` in module `rustc_errors::fluent`
|
||||||
LL | #[label(slug)]
|
LL | #[label(slug)]
|
||||||
| ^^^^ not found in `rustc_errors::fluent`
|
| ^^^^ not found in `rustc_errors::fluent`
|
||||||
|
|
||||||
error: aborting due to 67 previous errors
|
error: aborting due to 72 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0425`.
|
For more information about this error, try `rustc --explain E0425`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue