@@ -472,7 +472,7 @@ 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 {
477477 /// `#[suggestion]`
478478 Normal ,
@@ -489,10 +489,10 @@ impl FromStr for SuggestionKind {
489489
490490 fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
491491 match s {
492- "" => Ok ( SuggestionKind :: Normal ) ,
493- "_short " => Ok ( SuggestionKind :: Short ) ,
494- "_hidden " => Ok ( SuggestionKind :: Hidden ) ,
495- "_verbose " => Ok ( SuggestionKind :: Verbose ) ,
492+ "normal " => Ok ( SuggestionKind :: Normal ) ,
493+ "short " => Ok ( SuggestionKind :: Short ) ,
494+ "hidden " => Ok ( SuggestionKind :: Hidden ) ,
495+ "verbose " => Ok ( SuggestionKind :: Verbose ) ,
496496 _ => Err ( ( ) ) ,
497497 }
498498 }
@@ -515,6 +515,16 @@ impl SuggestionKind {
515515 }
516516 }
517517 }
518+
519+ fn from_suffix ( s : & str ) -> Option < Self > {
520+ match s {
521+ "" => Some ( SuggestionKind :: Normal ) ,
522+ "_short" => Some ( SuggestionKind :: Short ) ,
523+ "_hidden" => Some ( SuggestionKind :: Hidden ) ,
524+ "_verbose" => Some ( SuggestionKind :: Verbose ) ,
525+ _ => None ,
526+ }
527+ }
518528}
519529
520530/// Types of subdiagnostics that can be created using attributes
@@ -565,25 +575,40 @@ impl SubdiagnosticKind {
565575 let name = name. as_str ( ) ;
566576
567577 let meta = attr. parse_meta ( ) ?;
578+
579+ let mut opt_suggestion_kind = None ;
568580 let mut kind = match name {
569581 "label" => SubdiagnosticKind :: Label ,
570582 "note" => SubdiagnosticKind :: Note ,
571583 "help" => SubdiagnosticKind :: Help ,
572584 "warning" => SubdiagnosticKind :: Warn ,
573585 _ => {
574586 if let Some ( suggestion_kind) =
575- name. strip_prefix ( "suggestion" ) . and_then ( |s| s . parse ( ) . ok ( ) )
587+ name. strip_prefix ( "suggestion" ) . and_then ( SuggestionKind :: from_suffix )
576588 {
589+ if suggestion_kind != SuggestionKind :: Normal {
590+ // Plain `#[suggestion]` can have a `style = "..."` attribute later, so don't set it here
591+ opt_suggestion_kind. set_once ( suggestion_kind, attr. path . span ( ) . unwrap ( ) ) ;
592+ }
593+
577594 SubdiagnosticKind :: Suggestion {
578- suggestion_kind,
595+ suggestion_kind : SuggestionKind :: Normal ,
579596 applicability : None ,
580597 code_field : new_code_ident ( ) ,
581598 code_init : TokenStream :: new ( ) ,
582599 }
583600 } else if let Some ( suggestion_kind) =
584- name. strip_prefix ( "multipart_suggestion" ) . and_then ( |s| s . parse ( ) . ok ( ) )
601+ name. strip_prefix ( "multipart_suggestion" ) . and_then ( SuggestionKind :: from_suffix )
585602 {
586- SubdiagnosticKind :: MultipartSuggestion { suggestion_kind, applicability : None }
603+ if suggestion_kind != SuggestionKind :: Normal {
604+ // Plain `#[multipart_suggestion]` can have a `style = "..."` attribute later, so don't set it here
605+ opt_suggestion_kind. set_once ( suggestion_kind, attr. path . span ( ) . unwrap ( ) ) ;
606+ }
607+
608+ SubdiagnosticKind :: MultipartSuggestion {
609+ suggestion_kind : SuggestionKind :: Normal ,
610+ applicability : None ,
611+ }
587612 } else {
588613 throw_invalid_attr ! ( attr, & meta) ;
589614 }
@@ -682,16 +707,37 @@ impl SubdiagnosticKind {
682707 } ) ;
683708 applicability. set_once ( value, span) ;
684709 }
710+ (
711+ "style" ,
712+ SubdiagnosticKind :: Suggestion { .. }
713+ | SubdiagnosticKind :: MultipartSuggestion { .. } ,
714+ ) => {
715+ let Some ( value) = string_value else {
716+ invalid_nested_attr ( attr, & nested_attr) . emit ( ) ;
717+ continue ;
718+ } ;
719+
720+ let value = value. value ( ) . parse ( ) . unwrap_or_else ( |( ) | {
721+ span_err ( value. span ( ) . unwrap ( ) , "invalid suggestion style" )
722+ . help ( "valid styles are `normal`, `short`, `hidden` and `verbose`" )
723+ . emit ( ) ;
724+ SuggestionKind :: Normal
725+ } ) ;
726+
727+ opt_suggestion_kind. set_once ( value, span) ;
728+ }
685729
686730 // Invalid nested attribute
687731 ( _, SubdiagnosticKind :: Suggestion { .. } ) => {
688732 invalid_nested_attr ( attr, & nested_attr)
689- . help ( "only `code` and `applicability` are valid nested attributes" )
733+ . help (
734+ "only `style`, `code` and `applicability` are valid nested attributes" ,
735+ )
690736 . emit ( ) ;
691737 }
692738 ( _, SubdiagnosticKind :: MultipartSuggestion { .. } ) => {
693739 invalid_nested_attr ( attr, & nested_attr)
694- . help ( "only `applicability` is a valid nested attributes" )
740+ . help ( "only `style` and `applicability` are valid nested attributes" )
695741 . emit ( )
696742 }
697743 _ => {
@@ -701,19 +747,32 @@ impl SubdiagnosticKind {
701747 }
702748
703749 match kind {
704- SubdiagnosticKind :: Suggestion { ref code_field, ref mut code_init, .. } => {
750+ SubdiagnosticKind :: Suggestion {
751+ ref code_field,
752+ ref mut code_init,
753+ ref mut suggestion_kind,
754+ ..
755+ } => {
756+ if let Some ( kind) = opt_suggestion_kind. value ( ) {
757+ * suggestion_kind = kind;
758+ }
759+
705760 * code_init = if let Some ( init) = code. value ( ) {
706761 init
707762 } else {
708763 span_err ( span, "suggestion without `code = \" ...\" `" ) . emit ( ) ;
709764 quote ! { let #code_field = std:: iter:: empty( ) ; }
710765 } ;
711766 }
767+ SubdiagnosticKind :: MultipartSuggestion { ref mut suggestion_kind, .. } => {
768+ if let Some ( kind) = opt_suggestion_kind. value ( ) {
769+ * suggestion_kind = kind;
770+ }
771+ }
712772 SubdiagnosticKind :: Label
713773 | SubdiagnosticKind :: Note
714774 | SubdiagnosticKind :: Help
715- | SubdiagnosticKind :: Warn
716- | SubdiagnosticKind :: MultipartSuggestion { .. } => { }
775+ | SubdiagnosticKind :: Warn => { }
717776 }
718777
719778 Ok ( Some ( ( kind, slug) ) )
0 commit comments