11use rustc_ast as ast;
22use rustc_ast:: { ItemKind , VariantData } ;
3- use rustc_expand:: base:: { Annotatable , ExtCtxt } ;
4- use rustc_span:: { kw , sym , Ident , Span } ;
3+ use rustc_expand:: base:: { Annotatable , DummyResult , ExtCtxt } ;
4+ use rustc_span:: { Ident , Span , kw , sym } ;
55use thin_vec:: thin_vec;
66
77use crate :: deriving:: generic:: ty:: { Bounds , Path , PathKind , Ty } ;
88use crate :: deriving:: generic:: {
9- combine_substructure , BlockOrExpr , FieldlessVariantsStrategy , MethodDef , SubstructureFields ,
10- TraitDef ,
9+ BlockOrExpr , FieldlessVariantsStrategy , MethodDef , SubstructureFields , TraitDef ,
10+ combine_substructure ,
1111} ;
1212use crate :: deriving:: pathvec_std;
1313use crate :: errors;
@@ -22,6 +22,7 @@ pub(crate) fn expand_deriving_from(
2222 push : & mut dyn FnMut ( Annotatable ) ,
2323 is_const : bool ,
2424) {
25+ // #[derive(From)] is currently usable only on structs with exactly one field.
2526 let field = match & item {
2627 Annotatable :: Item ( item) => match & item. kind {
2728 ItemKind :: Struct ( _, _, data) => match data. fields ( ) {
@@ -33,18 +34,14 @@ pub(crate) fn expand_deriving_from(
3334 _ => None ,
3435 } ;
3536
36- // Make sure that the derive is only invoked on single- field [tuple] structs.
37- // From this point below, we know that there is exactly one field.
38- let Some ( field ) = field else {
39- cx . dcx ( ) . emit_err ( errors :: DeriveFromWrongTarget { span } ) ;
40- return ;
37+ let from_type = match & field {
38+ Some ( field ) => Ty :: AstTy ( field. ty . clone ( ) ) ,
39+ // We don't have a type to put into From<...> if we don't have a single field, so just put
40+ // unit there.
41+ None => Ty :: Unit ,
4142 } ;
42-
43- let path = Path :: new_ (
44- pathvec_std ! ( convert:: From ) ,
45- vec ! [ Box :: new( Ty :: AstTy ( field. ty. clone( ) ) ) ] ,
46- PathKind :: Std ,
47- ) ;
43+ let path =
44+ Path :: new_ ( pathvec_std ! ( convert:: From ) , vec ! [ Box :: new( from_type. clone( ) ) ] , PathKind :: Std ) ;
4845
4946 // Generate code like this:
5047 //
@@ -67,11 +64,16 @@ pub(crate) fn expand_deriving_from(
6764 name: sym:: from,
6865 generics: Bounds { bounds: vec![ ] } ,
6966 explicit_self: false ,
70- nonself_args: vec![ ( Ty :: AstTy ( field . ty ) , sym:: value) ] ,
67+ nonself_args: vec![ ( from_type , sym:: value) ] ,
7168 ret_ty: Ty :: Self_ ,
7269 attributes: thin_vec![ cx. attr_word( sym:: inline, span) ] ,
7370 fieldless_variants_strategy: FieldlessVariantsStrategy :: Default ,
7471 combine_substructure: combine_substructure( Box :: new( |cx, span, substructure| {
72+ let Some ( field) = & field else {
73+ let error = cx. dcx( ) . emit_err( errors:: DeriveFromWrongTarget { span } ) ;
74+ return BlockOrExpr :: new_expr( DummyResult :: raw_expr( span, Some ( error) ) ) ;
75+ } ;
76+
7577 let self_kw = Ident :: new( kw:: SelfUpper , span) ;
7678 let expr: Box <ast:: Expr > = match substructure. fields {
7779 SubstructureFields :: StaticStruct ( variant, _) => match variant {
0 commit comments