Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 8677fef

Browse files
committed
macros: move suggestion type handling to fn
Move the handling of `Span` or `(Span, Applicability)` types in `#[suggestion]` attributes to its own function. Signed-off-by: David Wood <david.wood@huawei.com>
1 parent 2bf64d6 commit 8677fef

File tree

1 file changed

+61
-68
lines changed

1 file changed

+61
-68
lines changed

compiler/rustc_macros/src/session_diagnostic.rs

Lines changed: 61 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -430,74 +430,8 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> {
430430
| suggestion_kind @ "suggestion_short"
431431
| suggestion_kind @ "suggestion_hidden"
432432
| suggestion_kind @ "suggestion_verbose" => {
433-
// For suggest, we need to ensure we are running on a (Span,
434-
// Applicability) pair.
435-
let (span, applicability) = (|| match &info.ty {
436-
ty @ syn::Type::Path(..)
437-
if type_matches_path(ty, &["rustc_span", "Span"]) =>
438-
{
439-
let binding = &info.binding.binding;
440-
Ok((
441-
quote!(*#binding),
442-
quote!(rustc_errors::Applicability::Unspecified),
443-
))
444-
}
445-
syn::Type::Tuple(tup) => {
446-
let mut span_idx = None;
447-
let mut applicability_idx = None;
448-
for (idx, elem) in tup.elems.iter().enumerate() {
449-
if type_matches_path(elem, &["rustc_span", "Span"]) {
450-
if span_idx.is_none() {
451-
span_idx = Some(syn::Index::from(idx));
452-
} else {
453-
throw_span_err!(
454-
info.span.unwrap(),
455-
"type of field annotated with `#[suggestion(...)]` contains more than one Span"
456-
);
457-
}
458-
} else if type_matches_path(
459-
elem,
460-
&["rustc_errors", "Applicability"],
461-
) {
462-
if applicability_idx.is_none() {
463-
applicability_idx = Some(syn::Index::from(idx));
464-
} else {
465-
throw_span_err!(
466-
info.span.unwrap(),
467-
"type of field annotated with `#[suggestion(...)]` contains more than one Applicability"
468-
);
469-
}
470-
}
471-
}
472-
if let Some(span_idx) = span_idx {
473-
let binding = &info.binding.binding;
474-
let span = quote!(#binding.#span_idx);
475-
let applicability = applicability_idx
476-
.map(
477-
|applicability_idx| quote!(#binding.#applicability_idx),
478-
)
479-
.unwrap_or_else(|| {
480-
quote!(rustc_errors::Applicability::Unspecified)
481-
});
482-
return Ok((span, applicability));
483-
}
484-
throw_span_err!(
485-
info.span.unwrap(),
486-
"wrong types for suggestion",
487-
|diag| {
488-
diag.help("#[suggestion(...)] on a tuple field must be applied to fields of type (Span, Applicability)")
489-
}
490-
);
491-
}
492-
_ => throw_span_err!(
493-
info.span.unwrap(),
494-
"wrong field type for suggestion",
495-
|diag| {
496-
diag.help("#[suggestion(...)] should be applied to fields of type Span or (Span, Applicability)")
497-
}
498-
),
499-
})()?;
500-
// Now read the key-value pairs.
433+
let (span, applicability) = self.span_and_applicability_of_ty(info)?;
434+
501435
let mut msg = None;
502436
let mut code = None;
503437

@@ -562,6 +496,65 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> {
562496
})
563497
}
564498

499+
fn span_and_applicability_of_ty(
500+
&self,
501+
info: FieldInfo<'_>,
502+
) -> Result<(proc_macro2::TokenStream, proc_macro2::TokenStream), SessionDiagnosticDeriveError>
503+
{
504+
match &info.ty {
505+
// If `ty` is `Span` w/out applicability, then use `Applicability::Unspecified`.
506+
ty @ syn::Type::Path(..) if type_matches_path(ty, &["rustc_span", "Span"]) => {
507+
let binding = &info.binding.binding;
508+
Ok((quote!(*#binding), quote!(rustc_errors::Applicability::Unspecified)))
509+
}
510+
// If `ty` is `(Span, Applicability)` then return tokens accessing those.
511+
syn::Type::Tuple(tup) => {
512+
let mut span_idx = None;
513+
let mut applicability_idx = None;
514+
515+
for (idx, elem) in tup.elems.iter().enumerate() {
516+
if type_matches_path(elem, &["rustc_span", "Span"]) {
517+
if span_idx.is_none() {
518+
span_idx = Some(syn::Index::from(idx));
519+
} else {
520+
throw_span_err!(
521+
info.span.unwrap(),
522+
"type of field annotated with `#[suggestion(...)]` contains more than one Span"
523+
);
524+
}
525+
} else if type_matches_path(elem, &["rustc_errors", "Applicability"]) {
526+
if applicability_idx.is_none() {
527+
applicability_idx = Some(syn::Index::from(idx));
528+
} else {
529+
throw_span_err!(
530+
info.span.unwrap(),
531+
"type of field annotated with `#[suggestion(...)]` contains more than one Applicability"
532+
);
533+
}
534+
}
535+
}
536+
537+
if let Some(span_idx) = span_idx {
538+
let binding = &info.binding.binding;
539+
let span = quote!(#binding.#span_idx);
540+
let applicability = applicability_idx
541+
.map(|applicability_idx| quote!(#binding.#applicability_idx))
542+
.unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified));
543+
544+
return Ok((span, applicability));
545+
}
546+
547+
throw_span_err!(info.span.unwrap(), "wrong types for suggestion", |diag| {
548+
diag.help("#[suggestion(...)] on a tuple field must be applied to fields of type `(Span, Applicability)`")
549+
});
550+
}
551+
// If `ty` isn't a `Span` or `(Span, Applicability)` then emit an error.
552+
_ => throw_span_err!(info.span.unwrap(), "wrong field type for suggestion", |diag| {
553+
diag.help("#[suggestion(...)] should be applied to fields of type `Span` or `(Span, Applicability)`")
554+
}),
555+
}
556+
}
557+
565558
/// In the strings in the attributes supplied to this macro, we want callers to be able to
566559
/// reference fields in the format string. For example:
567560
///

0 commit comments

Comments
 (0)