1
1
use rustc_ast as ast;
2
2
use 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 } ;
5
5
use thin_vec:: thin_vec;
6
6
7
7
use crate :: deriving:: generic:: ty:: { Bounds , Path , PathKind , Ty } ;
8
8
use crate :: deriving:: generic:: {
9
- combine_substructure , BlockOrExpr , FieldlessVariantsStrategy , MethodDef , SubstructureFields ,
10
- TraitDef ,
9
+ BlockOrExpr , FieldlessVariantsStrategy , MethodDef , SubstructureFields , TraitDef ,
10
+ combine_substructure ,
11
11
} ;
12
12
use crate :: deriving:: pathvec_std;
13
13
use crate :: errors;
@@ -22,6 +22,7 @@ pub(crate) fn expand_deriving_from(
22
22
push : & mut dyn FnMut ( Annotatable ) ,
23
23
is_const : bool ,
24
24
) {
25
+ // #[derive(From)] is currently usable only on structs with exactly one field.
25
26
let field = match & item {
26
27
Annotatable :: Item ( item) => match & item. kind {
27
28
ItemKind :: Struct ( _, _, data) => match data. fields ( ) {
@@ -33,18 +34,14 @@ pub(crate) fn expand_deriving_from(
33
34
_ => None ,
34
35
} ;
35
36
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 ,
41
42
} ;
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 ) ;
48
45
49
46
// Generate code like this:
50
47
//
@@ -67,11 +64,16 @@ pub(crate) fn expand_deriving_from(
67
64
name: sym:: from,
68
65
generics: Bounds { bounds: vec![ ] } ,
69
66
explicit_self: false ,
70
- nonself_args: vec![ ( Ty :: AstTy ( field . ty ) , sym:: value) ] ,
67
+ nonself_args: vec![ ( from_type , sym:: value) ] ,
71
68
ret_ty: Ty :: Self_ ,
72
69
attributes: thin_vec![ cx. attr_word( sym:: inline, span) ] ,
73
70
fieldless_variants_strategy: FieldlessVariantsStrategy :: Default ,
74
71
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
+
75
77
let self_kw = Ident :: new( kw:: SelfUpper , span) ;
76
78
let expr: Box <ast:: Expr > = match substructure. fields {
77
79
SubstructureFields :: StaticStruct ( variant, _) => match variant {
0 commit comments