@@ -12,7 +12,7 @@ use syn::{spanned::Spanned, Attribute, Field, Meta, Type, TypeTuple};
1212use syn:: { MetaList , MetaNameValue , NestedMeta , Path } ;
1313use synstructure:: { BindingInfo , VariantInfo } ;
1414
15- use super :: error:: invalid_nested_attr;
15+ use super :: error:: { invalid_attr , invalid_nested_attr} ;
1616
1717thread_local ! {
1818 pub static CODE_IDENT_COUNT : RefCell <u32 > = RefCell :: new( 0 ) ;
@@ -472,32 +472,42 @@ pub(super) fn build_suggestion_code(
472472}
473473
474474/// Possible styles for suggestion subdiagnostics.
475- #[ derive( Clone , Copy ) ]
475+ #[ derive( Clone , Copy , PartialEq ) ]
476476pub ( super ) enum SuggestionKind {
477- /// `#[suggestion]`
478477 Normal ,
479- /// `#[suggestion_short]`
480478 Short ,
481- /// `#[suggestion_hidden]`
482479 Hidden ,
483- /// `#[suggestion_verbose]`
484480 Verbose ,
481+ ToolOnly ,
485482}
486483
487484impl FromStr for SuggestionKind {
488485 type Err = ( ) ;
489486
490487 fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
491488 match s {
492- "" => Ok ( SuggestionKind :: Normal ) ,
493- "_short" => Ok ( SuggestionKind :: Short ) ,
494- "_hidden" => Ok ( SuggestionKind :: Hidden ) ,
495- "_verbose" => Ok ( SuggestionKind :: Verbose ) ,
489+ "normal" => Ok ( SuggestionKind :: Normal ) ,
490+ "short" => Ok ( SuggestionKind :: Short ) ,
491+ "hidden" => Ok ( SuggestionKind :: Hidden ) ,
492+ "verbose" => Ok ( SuggestionKind :: Verbose ) ,
493+ "tool-only" => Ok ( SuggestionKind :: ToolOnly ) ,
496494 _ => Err ( ( ) ) ,
497495 }
498496 }
499497}
500498
499+ impl fmt:: Display for SuggestionKind {
500+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
501+ match self {
502+ SuggestionKind :: Normal => write ! ( f, "normal" ) ,
503+ SuggestionKind :: Short => write ! ( f, "short" ) ,
504+ SuggestionKind :: Hidden => write ! ( f, "hidden" ) ,
505+ SuggestionKind :: Verbose => write ! ( f, "verbose" ) ,
506+ SuggestionKind :: ToolOnly => write ! ( f, "tool-only" ) ,
507+ }
508+ }
509+ }
510+
501511impl SuggestionKind {
502512 pub fn to_suggestion_style ( & self ) -> TokenStream {
503513 match self {
@@ -513,6 +523,19 @@ impl SuggestionKind {
513523 SuggestionKind :: Verbose => {
514524 quote ! { rustc_errors:: SuggestionStyle :: ShowAlways }
515525 }
526+ SuggestionKind :: ToolOnly => {
527+ quote ! { rustc_errors:: SuggestionStyle :: CompletelyHidden }
528+ }
529+ }
530+ }
531+
532+ fn from_suffix ( s : & str ) -> Option < Self > {
533+ match s {
534+ "" => Some ( SuggestionKind :: Normal ) ,
535+ "_short" => Some ( SuggestionKind :: Short ) ,
536+ "_hidden" => Some ( SuggestionKind :: Hidden ) ,
537+ "_verbose" => Some ( SuggestionKind :: Verbose ) ,
538+ _ => None ,
516539 }
517540 }
518541}
@@ -565,25 +588,49 @@ impl SubdiagnosticKind {
565588 let name = name. as_str ( ) ;
566589
567590 let meta = attr. parse_meta ( ) ?;
591+
568592 let mut kind = match name {
569593 "label" => SubdiagnosticKind :: Label ,
570594 "note" => SubdiagnosticKind :: Note ,
571595 "help" => SubdiagnosticKind :: Help ,
572596 "warning" => SubdiagnosticKind :: Warn ,
573597 _ => {
598+ // Recover old `#[(multipart_)suggestion_*]` syntaxes
599+ // FIXME(#100717): remove
574600 if let Some ( suggestion_kind) =
575- name. strip_prefix ( "suggestion" ) . and_then ( |s| s . parse ( ) . ok ( ) )
601+ name. strip_prefix ( "suggestion" ) . and_then ( SuggestionKind :: from_suffix )
576602 {
603+ if suggestion_kind != SuggestionKind :: Normal {
604+ invalid_attr ( attr, & meta)
605+ . help ( format ! (
606+ r#"Use `#[suggestion(..., style = "{}")]` instead"# ,
607+ suggestion_kind
608+ ) )
609+ . emit ( ) ;
610+ }
611+
577612 SubdiagnosticKind :: Suggestion {
578- suggestion_kind,
613+ suggestion_kind : SuggestionKind :: Normal ,
579614 applicability : None ,
580615 code_field : new_code_ident ( ) ,
581616 code_init : TokenStream :: new ( ) ,
582617 }
583618 } else if let Some ( suggestion_kind) =
584- name. strip_prefix ( "multipart_suggestion" ) . and_then ( |s| s . parse ( ) . ok ( ) )
619+ name. strip_prefix ( "multipart_suggestion" ) . and_then ( SuggestionKind :: from_suffix )
585620 {
586- SubdiagnosticKind :: MultipartSuggestion { suggestion_kind, applicability : None }
621+ if suggestion_kind != SuggestionKind :: Normal {
622+ invalid_attr ( attr, & meta)
623+ . help ( format ! (
624+ r#"Use `#[multipart_suggestion(..., style = "{}")]` instead"# ,
625+ suggestion_kind
626+ ) )
627+ . emit ( ) ;
628+ }
629+
630+ SubdiagnosticKind :: MultipartSuggestion {
631+ suggestion_kind : SuggestionKind :: Normal ,
632+ applicability : None ,
633+ }
587634 } else {
588635 throw_invalid_attr ! ( attr, & meta) ;
589636 }
@@ -621,6 +668,7 @@ impl SubdiagnosticKind {
621668 } ;
622669
623670 let mut code = None ;
671+ let mut suggestion_kind = None ;
624672
625673 let mut nested_iter = nested. into_iter ( ) . peekable ( ) ;
626674
@@ -682,16 +730,37 @@ impl SubdiagnosticKind {
682730 } ) ;
683731 applicability. set_once ( value, span) ;
684732 }
733+ (
734+ "style" ,
735+ SubdiagnosticKind :: Suggestion { .. }
736+ | SubdiagnosticKind :: MultipartSuggestion { .. } ,
737+ ) => {
738+ let Some ( value) = string_value else {
739+ invalid_nested_attr ( attr, & nested_attr) . emit ( ) ;
740+ continue ;
741+ } ;
742+
743+ let value = value. value ( ) . parse ( ) . unwrap_or_else ( |( ) | {
744+ span_err ( value. span ( ) . unwrap ( ) , "invalid suggestion style" )
745+ . help ( "valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only`" )
746+ . emit ( ) ;
747+ SuggestionKind :: Normal
748+ } ) ;
749+
750+ suggestion_kind. set_once ( value, span) ;
751+ }
685752
686753 // Invalid nested attribute
687754 ( _, SubdiagnosticKind :: Suggestion { .. } ) => {
688755 invalid_nested_attr ( attr, & nested_attr)
689- . help ( "only `code` and `applicability` are valid nested attributes" )
756+ . help (
757+ "only `style`, `code` and `applicability` are valid nested attributes" ,
758+ )
690759 . emit ( ) ;
691760 }
692761 ( _, SubdiagnosticKind :: MultipartSuggestion { .. } ) => {
693762 invalid_nested_attr ( attr, & nested_attr)
694- . help ( "only `applicability` is a valid nested attributes" )
763+ . help ( "only `style` and `applicability` are valid nested attributes" )
695764 . emit ( )
696765 }
697766 _ => {
@@ -701,19 +770,34 @@ impl SubdiagnosticKind {
701770 }
702771
703772 match kind {
704- SubdiagnosticKind :: Suggestion { ref code_field, ref mut code_init, .. } => {
773+ SubdiagnosticKind :: Suggestion {
774+ ref code_field,
775+ ref mut code_init,
776+ suggestion_kind : ref mut kind_field,
777+ ..
778+ } => {
779+ if let Some ( kind) = suggestion_kind. value ( ) {
780+ * kind_field = kind;
781+ }
782+
705783 * code_init = if let Some ( init) = code. value ( ) {
706784 init
707785 } else {
708786 span_err ( span, "suggestion without `code = \" ...\" `" ) . emit ( ) ;
709787 quote ! { let #code_field = std:: iter:: empty( ) ; }
710788 } ;
711789 }
790+ SubdiagnosticKind :: MultipartSuggestion {
791+ suggestion_kind : ref mut kind_field, ..
792+ } => {
793+ if let Some ( kind) = suggestion_kind. value ( ) {
794+ * kind_field = kind;
795+ }
796+ }
712797 SubdiagnosticKind :: Label
713798 | SubdiagnosticKind :: Note
714799 | SubdiagnosticKind :: Help
715- | SubdiagnosticKind :: Warn
716- | SubdiagnosticKind :: MultipartSuggestion { .. } => { }
800+ | SubdiagnosticKind :: Warn => { }
717801 }
718802
719803 Ok ( Some ( ( kind, slug) ) )
0 commit comments