mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-21 22:34:05 +00:00
macros: support translatable suggestions
Extends support for generating `DiagnosticMessage::FluentIdentifier` messages from `SessionDiagnostic` derive to `#[suggestion]`. Signed-off-by: David Wood <david.wood@huawei.com>
This commit is contained in:
parent
b40ee88a28
commit
22685b9607
@ -594,6 +594,7 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> {
|
||||
info: FieldInfo<'_>,
|
||||
) -> Result<proc_macro2::TokenStream, SessionDiagnosticDeriveError> {
|
||||
let diag = &self.diag;
|
||||
let span = attr.span().unwrap();
|
||||
let field_binding = &info.binding.binding;
|
||||
|
||||
let name = attr.path.segments.last().unwrap().ident.to_string();
|
||||
@ -618,7 +619,7 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> {
|
||||
Ok(self.add_subdiagnostic(field_binding, name, name))
|
||||
}
|
||||
other => throw_span_err!(
|
||||
attr.span().unwrap(),
|
||||
span,
|
||||
&format!("`#[{}]` is not a valid `SessionDiagnostic` field attribute", other)
|
||||
),
|
||||
},
|
||||
@ -628,7 +629,7 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> {
|
||||
Ok(self.add_subdiagnostic(field_binding, name, &s.value()))
|
||||
}
|
||||
other => throw_span_err!(
|
||||
attr.span().unwrap(),
|
||||
span,
|
||||
&format!(
|
||||
"`#[{} = ...]` is not a valid `SessionDiagnostic` field attribute",
|
||||
other
|
||||
@ -636,77 +637,103 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> {
|
||||
),
|
||||
},
|
||||
syn::Meta::NameValue(_) => throw_span_err!(
|
||||
attr.span().unwrap(),
|
||||
span,
|
||||
&format!("`#[{} = ...]` is not a valid `SessionDiagnostic` field attribute", name),
|
||||
|diag| diag.help("value must be a string")
|
||||
),
|
||||
syn::Meta::List(list) => {
|
||||
match list.path.segments.iter().last().unwrap().ident.to_string().as_str() {
|
||||
suggestion_kind @ "suggestion"
|
||||
| suggestion_kind @ "suggestion_short"
|
||||
| suggestion_kind @ "suggestion_hidden"
|
||||
| suggestion_kind @ "suggestion_verbose" => {
|
||||
let (span, applicability) = self.span_and_applicability_of_ty(info)?;
|
||||
syn::Meta::List(syn::MetaList { path, nested, .. }) => {
|
||||
let name = path.segments.last().unwrap().ident.to_string();
|
||||
let name = name.as_ref();
|
||||
|
||||
let mut msg = None;
|
||||
let mut code = None;
|
||||
|
||||
for arg in list.nested.iter() {
|
||||
if let syn::NestedMeta::Meta(syn::Meta::NameValue(arg_name_value)) = arg
|
||||
{
|
||||
if let syn::MetaNameValue { lit: syn::Lit::Str(s), .. } =
|
||||
arg_name_value
|
||||
{
|
||||
let name = arg_name_value
|
||||
.path
|
||||
.segments
|
||||
.last()
|
||||
.unwrap()
|
||||
.ident
|
||||
.to_string();
|
||||
let name = name.as_str();
|
||||
let formatted_str = self.build_format(&s.value(), arg.span());
|
||||
match name {
|
||||
"message" => {
|
||||
msg = Some(formatted_str);
|
||||
}
|
||||
"code" => {
|
||||
code = Some(formatted_str);
|
||||
}
|
||||
other => throw_span_err!(
|
||||
arg.span().unwrap(),
|
||||
&format!(
|
||||
"`{}` is not a valid key for `#[suggestion(...)]`",
|
||||
other
|
||||
)
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let msg = if let Some(msg) = msg {
|
||||
quote!(#msg.as_str())
|
||||
} else {
|
||||
throw_span_err!(
|
||||
list.span().unwrap(),
|
||||
"missing suggestion message",
|
||||
|diag| {
|
||||
diag.help("provide a suggestion message using `#[suggestion(message = \"...\")]`")
|
||||
}
|
||||
);
|
||||
};
|
||||
let code = code.unwrap_or_else(|| quote! { String::new() });
|
||||
|
||||
let suggestion_method = format_ident!("span_{}", suggestion_kind);
|
||||
return Ok(quote! {
|
||||
#diag.#suggestion_method(#span, #msg, #code, #applicability);
|
||||
});
|
||||
}
|
||||
match name {
|
||||
"suggestion" | "suggestion_short" | "suggestion_hidden"
|
||||
| "suggestion_verbose" => (),
|
||||
other => throw_span_err!(
|
||||
list.span().unwrap(),
|
||||
&format!("invalid annotation list `#[{}(...)]`", other)
|
||||
span,
|
||||
&format!(
|
||||
"`#[{}(...)]` is not a valid `SessionDiagnostic` field attribute",
|
||||
other
|
||||
)
|
||||
),
|
||||
};
|
||||
|
||||
let (span_, applicability) = self.span_and_applicability_of_ty(info)?;
|
||||
|
||||
let mut msg = None;
|
||||
let mut code = None;
|
||||
|
||||
for attr in nested {
|
||||
let meta = match attr {
|
||||
syn::NestedMeta::Meta(meta) => meta,
|
||||
syn::NestedMeta::Lit(_) => throw_span_err!(
|
||||
span,
|
||||
&format!(
|
||||
"`#[{}(\"...\")]` is not a valid `SessionDiagnostic` field attribute",
|
||||
name
|
||||
)
|
||||
),
|
||||
};
|
||||
|
||||
let span = meta.span().unwrap();
|
||||
let nested_name = meta.path().segments.last().unwrap().ident.to_string();
|
||||
let nested_name = nested_name.as_str();
|
||||
|
||||
match meta {
|
||||
syn::Meta::NameValue(syn::MetaNameValue {
|
||||
lit: syn::Lit::Str(s), ..
|
||||
}) => match nested_name {
|
||||
"message" => {
|
||||
msg = Some(s.value());
|
||||
}
|
||||
"code" => {
|
||||
let formatted_str = self.build_format(&s.value(), s.span());
|
||||
code = Some(formatted_str);
|
||||
}
|
||||
other => throw_span_err!(
|
||||
span,
|
||||
&format!(
|
||||
"`#[{}({} = ...)]` is not a valid `SessionDiagnostic` field attribute",
|
||||
name, other
|
||||
)
|
||||
),
|
||||
},
|
||||
syn::Meta::NameValue(..) => throw_span_err!(
|
||||
span,
|
||||
&format!(
|
||||
"`#[{}({} = ...)]` is not a valid `SessionDiagnostic` struct attribute",
|
||||
name, nested_name
|
||||
),
|
||||
|diag| diag.help("value must be a string")
|
||||
),
|
||||
syn::Meta::Path(..) => throw_span_err!(
|
||||
span,
|
||||
&format!(
|
||||
"`#[{}({})]` is not a valid `SessionDiagnostic` struct attribute",
|
||||
name, nested_name
|
||||
)
|
||||
),
|
||||
syn::Meta::List(..) => throw_span_err!(
|
||||
span,
|
||||
&format!(
|
||||
"`#[{}({}(...))]` is not a valid `SessionDiagnostic` struct attribute",
|
||||
name, nested_name
|
||||
)
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
let method = format_ident!("span_{}", name);
|
||||
|
||||
let slug = self
|
||||
.slug
|
||||
.as_ref()
|
||||
.map(|(slug, _)| slug.as_str())
|
||||
.unwrap_or_else(|| "missing-slug");
|
||||
let msg = msg.as_deref().unwrap_or("suggestion");
|
||||
let msg = quote! { rustc_errors::DiagnosticMessage::fluent_attr(#slug, #msg) };
|
||||
let code = code.unwrap_or_else(|| quote! { String::new() });
|
||||
|
||||
Ok(quote! { #diag.#method(#span_, #msg, #code, #applicability); })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ struct InvalidNestedStructAttr3 {}
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(code = "E0123", slug = "foo")]
|
||||
struct WrongPlaceField {
|
||||
#[suggestion = "this is the wrong kind of attribute"]
|
||||
#[suggestion = "bar"]
|
||||
//~^ ERROR `#[suggestion = ...]` is not a valid `SessionDiagnostic` field attribute
|
||||
sp: Span,
|
||||
}
|
||||
@ -154,7 +154,7 @@ struct ErrorWithMessageAppliedToField {
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(code = "E0123", slug = "foo")]
|
||||
struct ErrorWithNonexistentField {
|
||||
#[suggestion(message = "This is a suggestion", code = "{name}")]
|
||||
#[suggestion(message = "bar", code = "{name}")]
|
||||
//~^ ERROR `name` doesn't refer to a field on this type
|
||||
suggestion: (Span, Applicability),
|
||||
}
|
||||
@ -163,7 +163,7 @@ struct ErrorWithNonexistentField {
|
||||
//~^ ERROR invalid format string: expected `'}'`
|
||||
#[error(code = "E0123", slug = "foo")]
|
||||
struct ErrorMissingClosingBrace {
|
||||
#[suggestion(message = "This is a suggestion", code = "{name")]
|
||||
#[suggestion(message = "bar", code = "{name")]
|
||||
suggestion: (Span, Applicability),
|
||||
name: String,
|
||||
val: usize,
|
||||
@ -173,7 +173,7 @@ struct ErrorMissingClosingBrace {
|
||||
//~^ ERROR invalid format string: unmatched `}`
|
||||
#[error(code = "E0123", slug = "foo")]
|
||||
struct ErrorMissingOpeningBrace {
|
||||
#[suggestion(message = "This is a suggestion", code = "name}")]
|
||||
#[suggestion(message = "bar", code = "name}")]
|
||||
suggestion: (Span, Applicability),
|
||||
name: String,
|
||||
val: usize,
|
||||
@ -197,55 +197,54 @@ struct LabelOnNonSpan {
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(code = "E0123", slug = "foo")]
|
||||
struct Suggest {
|
||||
#[suggestion(message = "This is a suggestion", code = "This is the suggested code")]
|
||||
#[suggestion_short(message = "This is a suggestion", code = "This is the suggested code")]
|
||||
#[suggestion_hidden(message = "This is a suggestion", code = "This is the suggested code")]
|
||||
#[suggestion_verbose(message = "This is a suggestion", code = "This is the suggested code")]
|
||||
#[suggestion(message = "bar", code = "This is the suggested code")]
|
||||
#[suggestion_short(message = "qux", code = "This is the suggested code")]
|
||||
#[suggestion_hidden(message = "foobar", code = "This is the suggested code")]
|
||||
#[suggestion_verbose(message = "fooqux", code = "This is the suggested code")]
|
||||
suggestion: (Span, Applicability),
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(code = "E0123", slug = "foo")]
|
||||
struct SuggestWithoutCode {
|
||||
#[suggestion(message = "This is a suggestion")]
|
||||
#[suggestion(message = "bar")]
|
||||
suggestion: (Span, Applicability),
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(code = "E0123", slug = "foo")]
|
||||
struct SuggestWithBadKey {
|
||||
#[suggestion(nonsense = "This is nonsense")]
|
||||
//~^ ERROR `nonsense` is not a valid key for `#[suggestion(...)]`
|
||||
#[suggestion(nonsense = "bar")]
|
||||
//~^ ERROR `#[suggestion(nonsense = ...)]` is not a valid `SessionDiagnostic` field attribute
|
||||
suggestion: (Span, Applicability),
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(code = "E0123", slug = "foo")]
|
||||
struct SuggestWithShorthandMsg {
|
||||
#[suggestion(msg = "This is a suggestion")]
|
||||
//~^ ERROR `msg` is not a valid key for `#[suggestion(...)]`
|
||||
#[suggestion(msg = "bar")]
|
||||
//~^ ERROR `#[suggestion(msg = ...)]` is not a valid `SessionDiagnostic` field attribute
|
||||
suggestion: (Span, Applicability),
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(code = "E0123", slug = "foo")]
|
||||
struct SuggestWithoutMsg {
|
||||
#[suggestion(code = "This is suggested code")]
|
||||
//~^ ERROR missing suggestion message
|
||||
#[suggestion(code = "bar")]
|
||||
suggestion: (Span, Applicability),
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(code = "E0123", slug = "foo")]
|
||||
struct SuggestWithTypesSwapped {
|
||||
#[suggestion(message = "This is a message", code = "This is suggested code")]
|
||||
#[suggestion(message = "bar", code = "This is suggested code")]
|
||||
suggestion: (Applicability, Span),
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(code = "E0123", slug = "foo")]
|
||||
struct SuggestWithWrongTypeApplicabilityOnly {
|
||||
#[suggestion(message = "This is a message", code = "This is suggested code")]
|
||||
#[suggestion(message = "bar", code = "This is suggested code")]
|
||||
//~^ ERROR wrong field type for suggestion
|
||||
suggestion: Applicability,
|
||||
}
|
||||
@ -253,14 +252,14 @@ struct SuggestWithWrongTypeApplicabilityOnly {
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(code = "E0123", slug = "foo")]
|
||||
struct SuggestWithSpanOnly {
|
||||
#[suggestion(message = "This is a message", code = "This is suggested code")]
|
||||
#[suggestion(message = "bar", code = "This is suggested code")]
|
||||
suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(code = "E0123", slug = "foo")]
|
||||
struct SuggestWithDuplicateSpanAndApplicability {
|
||||
#[suggestion(message = "This is a message", code = "This is suggested code")]
|
||||
#[suggestion(message = "bar", code = "This is suggested code")]
|
||||
//~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one `Span`
|
||||
suggestion: (Span, Span, Applicability),
|
||||
}
|
||||
@ -268,7 +267,7 @@ struct SuggestWithDuplicateSpanAndApplicability {
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(code = "E0123", slug = "foo")]
|
||||
struct SuggestWithDuplicateApplicabilityAndSpan {
|
||||
#[suggestion(message = "This is a message", code = "This is suggested code")]
|
||||
#[suggestion(message = "bar", code = "This is suggested code")]
|
||||
//~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one
|
||||
suggestion: (Applicability, Applicability, Span),
|
||||
}
|
||||
@ -277,7 +276,7 @@ struct SuggestWithDuplicateApplicabilityAndSpan {
|
||||
#[error(code = "E0123", slug = "foo")]
|
||||
struct WrongKindOfAnnotation {
|
||||
#[label("bar")]
|
||||
//~^ ERROR invalid annotation list `#[label(...)]`
|
||||
//~^ ERROR `#[label(...)]` is not a valid `SessionDiagnostic` field attribute
|
||||
z: Span,
|
||||
}
|
||||
|
||||
@ -286,7 +285,7 @@ struct WrongKindOfAnnotation {
|
||||
struct OptionsInErrors {
|
||||
#[label = "bar"]
|
||||
label: Option<Span>,
|
||||
#[suggestion(message = "suggestion message")]
|
||||
#[suggestion(message = "bar")]
|
||||
opt_sugg: Option<(Span, Applicability)>,
|
||||
}
|
||||
|
||||
@ -300,7 +299,7 @@ struct MoveOutOfBorrowError<'tcx> {
|
||||
span: Span,
|
||||
#[label = "qux"]
|
||||
other_span: Span,
|
||||
#[suggestion(message = "consider cloning here", code = "{name}.clone()")]
|
||||
#[suggestion(message = "bar", code = "{name}.clone()")]
|
||||
opt_sugg: Option<(Span, Applicability)>,
|
||||
}
|
||||
|
||||
|
@ -79,8 +79,8 @@ LL | #[error(nonsense = 4, code = "E0123", slug = "foo")]
|
||||
error: `#[suggestion = ...]` is not a valid `SessionDiagnostic` field attribute
|
||||
--> $DIR/session-derive-errors.rs:86:5
|
||||
|
|
||||
LL | #[suggestion = "this is the wrong kind of attribute"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #[suggestion = "bar"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `error` specified multiple times
|
||||
--> $DIR/session-derive-errors.rs:93:1
|
||||
@ -166,10 +166,10 @@ LL | #[label = "bar"]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `name` doesn't refer to a field on this type
|
||||
--> $DIR/session-derive-errors.rs:157:52
|
||||
--> $DIR/session-derive-errors.rs:157:42
|
||||
|
|
||||
LL | #[suggestion(message = "This is a suggestion", code = "{name}")]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
LL | #[suggestion(message = "bar", code = "{name}")]
|
||||
| ^^^^^^^^
|
||||
|
||||
error: invalid format string: expected `'}'` but string was terminated
|
||||
--> $DIR/session-derive-errors.rs:162:16
|
||||
@ -197,30 +197,22 @@ error: the `#[label = ...]` attribute can only be applied to fields of type `Spa
|
||||
LL | #[label = "bar"]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `nonsense` is not a valid key for `#[suggestion(...)]`
|
||||
error: `#[suggestion(nonsense = ...)]` is not a valid `SessionDiagnostic` field attribute
|
||||
--> $DIR/session-derive-errors.rs:217:18
|
||||
|
|
||||
LL | #[suggestion(nonsense = "This is nonsense")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #[suggestion(nonsense = "bar")]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `msg` is not a valid key for `#[suggestion(...)]`
|
||||
error: `#[suggestion(msg = ...)]` is not a valid `SessionDiagnostic` field attribute
|
||||
--> $DIR/session-derive-errors.rs:225:18
|
||||
|
|
||||
LL | #[suggestion(msg = "This is a suggestion")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing suggestion message
|
||||
--> $DIR/session-derive-errors.rs:233:7
|
||||
|
|
||||
LL | #[suggestion(code = "This is suggested code")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: provide a suggestion message using `#[suggestion(message = "...")]`
|
||||
LL | #[suggestion(msg = "bar")]
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: wrong field type for suggestion
|
||||
--> $DIR/session-derive-errors.rs:248:5
|
||||
--> $DIR/session-derive-errors.rs:247:5
|
||||
|
|
||||
LL | / #[suggestion(message = "This is a message", code = "This is suggested code")]
|
||||
LL | / #[suggestion(message = "bar", code = "This is suggested code")]
|
||||
LL | |
|
||||
LL | | suggestion: Applicability,
|
||||
| |_____________________________^
|
||||
@ -228,47 +220,47 @@ LL | | suggestion: Applicability,
|
||||
= help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)`
|
||||
|
||||
error: type of field annotated with `#[suggestion(...)]` contains more than one `Span`
|
||||
--> $DIR/session-derive-errors.rs:263:5
|
||||
--> $DIR/session-derive-errors.rs:262:5
|
||||
|
|
||||
LL | / #[suggestion(message = "This is a message", code = "This is suggested code")]
|
||||
LL | / #[suggestion(message = "bar", code = "This is suggested code")]
|
||||
LL | |
|
||||
LL | | suggestion: (Span, Span, Applicability),
|
||||
| |___________________________________________^
|
||||
|
||||
error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability
|
||||
--> $DIR/session-derive-errors.rs:271:5
|
||||
--> $DIR/session-derive-errors.rs:270:5
|
||||
|
|
||||
LL | / #[suggestion(message = "This is a message", code = "This is suggested code")]
|
||||
LL | / #[suggestion(message = "bar", code = "This is suggested code")]
|
||||
LL | |
|
||||
LL | | suggestion: (Applicability, Applicability, Span),
|
||||
| |____________________________________________________^
|
||||
|
||||
error: invalid annotation list `#[label(...)]`
|
||||
--> $DIR/session-derive-errors.rs:279:7
|
||||
error: `#[label(...)]` is not a valid `SessionDiagnostic` field attribute
|
||||
--> $DIR/session-derive-errors.rs:278:5
|
||||
|
|
||||
LL | #[label("bar")]
|
||||
| ^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: `#[help]` must come after `#[error(..)]` or `#[warn(..)]`
|
||||
--> $DIR/session-derive-errors.rs:400:1
|
||||
--> $DIR/session-derive-errors.rs:399:1
|
||||
|
|
||||
LL | #[help]
|
||||
| ^^^^^^^
|
||||
|
||||
error: `#[help = ...]` must come after `#[error(..)]` or `#[warn(..)]`
|
||||
--> $DIR/session-derive-errors.rs:408:1
|
||||
--> $DIR/session-derive-errors.rs:407:1
|
||||
|
|
||||
LL | #[help = "bar"]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: `#[note]` must come after `#[error(..)]` or `#[warn(..)]`
|
||||
--> $DIR/session-derive-errors.rs:416:1
|
||||
--> $DIR/session-derive-errors.rs:415:1
|
||||
|
|
||||
LL | #[note]
|
||||
| ^^^^^^^
|
||||
|
||||
error: `#[note = ...]` must come after `#[error(..)]` or `#[warn(..)]`
|
||||
--> $DIR/session-derive-errors.rs:424:1
|
||||
--> $DIR/session-derive-errors.rs:423:1
|
||||
|
|
||||
LL | #[note = "bar"]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
@ -286,7 +278,7 @@ LL | #[nonsense]
|
||||
| ^^^^^^^^
|
||||
|
||||
error[E0599]: no method named `into_diagnostic_arg` found for struct `Hello` in the current scope
|
||||
--> $DIR/session-derive-errors.rs:323:10
|
||||
--> $DIR/session-derive-errors.rs:322:10
|
||||
|
|
||||
LL | struct Hello {}
|
||||
| ------------ method `into_diagnostic_arg` not found for this
|
||||
@ -296,6 +288,6 @@ LL | #[derive(SessionDiagnostic)]
|
||||
|
|
||||
= note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 38 previous errors
|
||||
error: aborting due to 37 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
||||
|
Loading…
Reference in New Issue
Block a user