11//! Builtin derives.
22
33use base_db:: { CrateOrigin , LangCrateOrigin } ;
4+ use either:: Either ;
45use tracing:: debug;
56
67use crate :: tt:: { self , TokenId } ;
78use syntax:: {
8- ast:: { self , AstNode , HasGenericParams , HasModuleItem , HasName } ,
9+ ast:: { self , AstNode , HasGenericParams , HasModuleItem , HasName , HasTypeBounds } ,
910 match_ast,
1011} ;
1112
@@ -60,8 +61,11 @@ pub fn find_builtin_derive(ident: &name::Name) -> Option<BuiltinDeriveExpander>
6061
6162struct BasicAdtInfo {
6263 name : tt:: Ident ,
63- /// `Some(ty)` if it's a const param of type `ty`, `None` if it's a type param.
64- param_types : Vec < Option < tt:: Subtree > > ,
64+ /// first field is the name, and
65+ /// second field is `Some(ty)` if it's a const param of type `ty`, `None` if it's a type param.
66+ /// third fields is where bounds, if any
67+ param_types : Vec < ( tt:: Subtree , Option < tt:: Subtree > , Option < tt:: Subtree > ) > ,
68+ field_types : Vec < tt:: Subtree > ,
6569}
6670
6771fn parse_adt ( tt : & tt:: Subtree ) -> Result < BasicAdtInfo , ExpandError > {
@@ -75,17 +79,34 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
7579 ExpandError :: Other ( "no item found" . into ( ) )
7680 } ) ?;
7781 let node = item. syntax ( ) ;
78- let ( name, params) = match_ast ! {
82+ let ( name, params, fields ) = match_ast ! {
7983 match node {
80- ast:: Struct ( it) => ( it. name( ) , it. generic_param_list( ) ) ,
81- ast:: Enum ( it) => ( it. name( ) , it. generic_param_list( ) ) ,
82- ast:: Union ( it) => ( it. name( ) , it. generic_param_list( ) ) ,
84+ ast:: Struct ( it) => {
85+ ( it. name( ) , it. generic_param_list( ) , it. field_list( ) . into_iter( ) . collect:: <Vec <_>>( ) )
86+ } ,
87+ ast:: Enum ( it) => ( it. name( ) , it. generic_param_list( ) , it. variant_list( ) . into_iter( ) . flat_map( |x| x. variants( ) ) . filter_map( |x| x. field_list( ) ) . collect( ) ) ,
88+ ast:: Union ( it) => ( it. name( ) , it. generic_param_list( ) , it. record_field_list( ) . into_iter( ) . map( |x| ast:: FieldList :: RecordFieldList ( x) ) . collect( ) ) ,
8389 _ => {
8490 debug!( "unexpected node is {:?}" , node) ;
8591 return Err ( ExpandError :: Other ( "expected struct, enum or union" . into( ) ) )
8692 } ,
8793 }
8894 } ;
95+ let field_types = fields
96+ . into_iter ( )
97+ . flat_map ( |f| match f {
98+ ast:: FieldList :: RecordFieldList ( x) => Either :: Left (
99+ x. fields ( )
100+ . filter_map ( |x| x. ty ( ) )
101+ . map ( |x| mbe:: syntax_node_to_token_tree ( x. syntax ( ) ) . 0 ) ,
102+ ) ,
103+ ast:: FieldList :: TupleFieldList ( x) => Either :: Right (
104+ x. fields ( )
105+ . filter_map ( |x| x. ty ( ) )
106+ . map ( |x| mbe:: syntax_node_to_token_tree ( x. syntax ( ) ) . 0 ) ,
107+ ) ,
108+ } )
109+ . collect :: < Vec < _ > > ( ) ;
89110 let name = name. ok_or_else ( || {
90111 debug ! ( "parsed item has no name" ) ;
91112 ExpandError :: Other ( "missing name" . into ( ) )
@@ -97,35 +118,46 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
97118 . into_iter ( )
98119 . flat_map ( |param_list| param_list. type_or_const_params ( ) )
99120 . map ( |param| {
100- if let ast:: TypeOrConstParam :: Const ( param) = param {
121+ let name = param
122+ . name ( )
123+ . map ( |x| mbe:: syntax_node_to_token_tree ( x. syntax ( ) ) . 0 )
124+ . unwrap_or_else ( tt:: Subtree :: empty) ;
125+ let bounds = match & param {
126+ ast:: TypeOrConstParam :: Type ( x) => {
127+ x. type_bound_list ( ) . map ( |x| mbe:: syntax_node_to_token_tree ( x. syntax ( ) ) . 0 )
128+ }
129+ ast:: TypeOrConstParam :: Const ( _) => None ,
130+ } ;
131+ let ty = if let ast:: TypeOrConstParam :: Const ( param) = param {
101132 let ty = param
102133 . ty ( )
103134 . map ( |ty| mbe:: syntax_node_to_token_tree ( ty. syntax ( ) ) . 0 )
104135 . unwrap_or_else ( tt:: Subtree :: empty) ;
105136 Some ( ty)
106137 } else {
107138 None
108- }
139+ } ;
140+ ( name, ty, bounds)
109141 } )
110142 . collect ( ) ;
111- Ok ( BasicAdtInfo { name : name_token, param_types } )
143+ Ok ( BasicAdtInfo { name : name_token, param_types, field_types } )
112144}
113145
114146fn expand_simple_derive ( tt : & tt:: Subtree , trait_path : tt:: Subtree ) -> ExpandResult < tt:: Subtree > {
115147 let info = match parse_adt ( tt) {
116148 Ok ( info) => info,
117149 Err ( e) => return ExpandResult :: with_err ( tt:: Subtree :: empty ( ) , e) ,
118150 } ;
151+ let mut where_block = vec ! [ ] ;
119152 let ( params, args) : ( Vec < _ > , Vec < _ > ) = info
120153 . param_types
121154 . into_iter ( )
122- . enumerate ( )
123- . map ( |( idx, param_ty) | {
124- let ident = tt:: Leaf :: Ident ( tt:: Ident {
125- span : tt:: TokenId :: unspecified ( ) ,
126- text : format ! ( "T{idx}" ) . into ( ) ,
127- } ) ;
155+ . map ( |( ident, param_ty, bound) | {
128156 let ident_ = ident. clone ( ) ;
157+ if let Some ( b) = bound {
158+ let ident = ident. clone ( ) ;
159+ where_block. push ( quote ! { #ident : #b , } ) ;
160+ }
129161 if let Some ( ty) = param_ty {
130162 ( quote ! { const #ident : #ty , } , quote ! { #ident_ , } )
131163 } else {
@@ -134,9 +166,16 @@ fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResu
134166 }
135167 } )
136168 . unzip ( ) ;
169+
170+ where_block. extend ( info. field_types . iter ( ) . map ( |x| {
171+ let x = x. clone ( ) ;
172+ let bound = trait_path. clone ( ) ;
173+ quote ! { #x : #bound , }
174+ } ) ) ;
175+
137176 let name = info. name ;
138177 let expanded = quote ! {
139- impl < ##params > #trait_path for #name < ##args > { }
178+ impl < ##params > #trait_path for #name < ##args > where ##where_block { }
140179 } ;
141180 ExpandResult :: ok ( expanded)
142181}
0 commit comments