11use rustc_ast as ast;
22use rustc_ast:: { ItemKind , VariantData } ;
3+ use rustc_errors:: MultiSpan ;
34use rustc_expand:: base:: { Annotatable , DummyResult , ExtCtxt } ;
45use rustc_span:: { Ident , Span , kw, sym} ;
56use thin_vec:: thin_vec;
@@ -18,17 +19,18 @@ pub(crate) fn expand_deriving_from(
1819 cx : & ExtCtxt < ' _ > ,
1920 span : Span ,
2021 mitem : & ast:: MetaItem ,
21- item : & Annotatable ,
22+ annotatable : & Annotatable ,
2223 push : & mut dyn FnMut ( Annotatable ) ,
2324 is_const : bool ,
2425) {
26+ let Annotatable :: Item ( item) = & annotatable else {
27+ cx. dcx ( ) . bug ( "derive(From) used on something else than an item" ) ;
28+ } ;
29+
2530 // #[derive(From)] is currently usable only on structs with exactly one field.
26- let field = match & item {
27- Annotatable :: Item ( item) => match & item. kind {
28- ItemKind :: Struct ( _, _, data) => match data. fields ( ) {
29- [ field] => Some ( field. clone ( ) ) ,
30- _ => None ,
31- } ,
31+ let field = match & item. kind {
32+ ItemKind :: Struct ( _, _, data) => match data. fields ( ) {
33+ [ field] => Some ( field. clone ( ) ) ,
3234 _ => None ,
3335 } ,
3436 _ => None ,
@@ -70,7 +72,24 @@ pub(crate) fn expand_deriving_from(
7072 fieldless_variants_strategy: FieldlessVariantsStrategy :: Default ,
7173 combine_substructure: combine_substructure( Box :: new( |cx, span, substructure| {
7274 let Some ( field) = & field else {
73- let error = cx. dcx( ) . emit_err( errors:: DeriveFromWrongTarget { span } ) ;
75+ let item_span = item. kind. ident( ) . map( |ident| ident. span) . unwrap_or( item. span) ;
76+ let err_span = MultiSpan :: from_spans( vec![ span, item_span] ) ;
77+ let error = match & item. kind {
78+ ItemKind :: Struct ( _, _, data) => {
79+ cx. dcx( ) . emit_err( errors:: DeriveFromWrongFieldCount {
80+ span: err_span,
81+ multiple_fields: data. fields( ) . len( ) > 1 ,
82+ } )
83+ }
84+ ItemKind :: Enum ( _, _, _) | ItemKind :: Union ( _, _, _) => {
85+ cx. dcx( ) . emit_err( errors:: DeriveFromWrongTarget {
86+ span: err_span,
87+ kind: & format!( "{} {}" , item. kind. article( ) , item. kind. descr( ) ) ,
88+ } )
89+ }
90+ _ => cx. dcx( ) . bug( "Invalid derive(From) ADT input" ) ,
91+ } ;
92+
7493 return BlockOrExpr :: new_expr( DummyResult :: raw_expr( span, Some ( error) ) ) ;
7594 } ;
7695
@@ -109,5 +128,5 @@ pub(crate) fn expand_deriving_from(
109128 is_staged_api_crate : cx. ecfg . features . staged_api ( ) ,
110129 } ;
111130
112- from_trait_def. expand ( cx, mitem, item , push) ;
131+ from_trait_def. expand ( cx, mitem, annotatable , push) ;
113132}
0 commit comments