@@ -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