@@ -60,7 +60,8 @@ pub fn find_builtin_derive(ident: &name::Name) -> Option<BuiltinDeriveExpander>
6060
6161struct BasicAdtInfo {
6262 name : tt:: Ident ,
63- type_or_const_params : usize ,
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 > > ,
6465}
6566
6667fn parse_adt ( tt : & tt:: Subtree ) -> Result < BasicAdtInfo , ExpandError > {
@@ -92,65 +93,50 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
9293 let name_token_id =
9394 token_map. token_by_range ( name. syntax ( ) . text_range ( ) ) . unwrap_or_else ( TokenId :: unspecified) ;
9495 let name_token = tt:: Ident { id : name_token_id, text : name. text ( ) . into ( ) } ;
95- let type_or_const_params =
96- params. map_or ( 0 , |type_param_list| type_param_list. type_or_const_params ( ) . count ( ) ) ;
97- Ok ( BasicAdtInfo { name : name_token, type_or_const_params } )
98- }
99-
100- fn make_type_args ( n : usize , bound : Vec < tt:: TokenTree > ) -> Vec < tt:: TokenTree > {
101- let mut result = Vec :: < tt:: TokenTree > :: with_capacity ( n * 2 ) ;
102- result. push (
103- tt:: Leaf :: Punct ( tt:: Punct {
104- char : '<' ,
105- spacing : tt:: Spacing :: Alone ,
106- id : tt:: TokenId :: unspecified ( ) ,
107- } )
108- . into ( ) ,
109- ) ;
110- for i in 0 ..n {
111- if i > 0 {
112- result. push (
113- tt:: Leaf :: Punct ( tt:: Punct {
114- char : ',' ,
115- spacing : tt:: Spacing :: Alone ,
116- id : tt:: TokenId :: unspecified ( ) ,
117- } )
118- . into ( ) ,
119- ) ;
120- }
121- result. push (
122- tt:: Leaf :: Ident ( tt:: Ident {
123- id : tt:: TokenId :: unspecified ( ) ,
124- text : format ! ( "T{}" , i) . into ( ) ,
125- } )
126- . into ( ) ,
127- ) ;
128- result. extend ( bound. iter ( ) . cloned ( ) ) ;
129- }
130- result. push (
131- tt:: Leaf :: Punct ( tt:: Punct {
132- char : '>' ,
133- spacing : tt:: Spacing :: Alone ,
134- id : tt:: TokenId :: unspecified ( ) ,
96+ let param_types = params
97+ . into_iter ( )
98+ . flat_map ( |param_list| param_list. type_or_const_params ( ) )
99+ . map ( |param| {
100+ if let ast:: TypeOrConstParam :: Const ( param) = param {
101+ let ty = param
102+ . ty ( )
103+ . map ( |ty| mbe:: syntax_node_to_token_tree ( ty. syntax ( ) ) . 0 )
104+ . unwrap_or_default ( ) ;
105+ Some ( ty)
106+ } else {
107+ None
108+ }
135109 } )
136- . into ( ) ,
137- ) ;
138- result
110+ . collect ( ) ;
111+ Ok ( BasicAdtInfo { name : name_token, param_types } )
139112}
140113
141114fn expand_simple_derive ( tt : & tt:: Subtree , trait_path : tt:: Subtree ) -> ExpandResult < tt:: Subtree > {
142115 let info = match parse_adt ( tt) {
143116 Ok ( info) => info,
144117 Err ( e) => return ExpandResult :: only_err ( e) ,
145118 } ;
119+ let ( params, args) : ( Vec < _ > , Vec < _ > ) = info
120+ . param_types
121+ . into_iter ( )
122+ . enumerate ( )
123+ . map ( |( idx, param_ty) | {
124+ let ident = tt:: Leaf :: Ident ( tt:: Ident {
125+ id : tt:: TokenId :: unspecified ( ) ,
126+ text : format ! ( "T{idx}" ) . into ( ) ,
127+ } ) ;
128+ let ident_ = ident. clone ( ) ;
129+ if let Some ( ty) = param_ty {
130+ ( quote ! { const #ident : #ty , } , quote ! { #ident_ , } )
131+ } else {
132+ let bound = trait_path. clone ( ) ;
133+ ( quote ! { #ident : #bound , } , quote ! { #ident_ , } )
134+ }
135+ } )
136+ . unzip ( ) ;
146137 let name = info. name ;
147- let trait_path_clone = trait_path. token_trees . clone ( ) ;
148- let bound = ( quote ! { : ##trait_path_clone } ) . token_trees ;
149- let type_params = make_type_args ( info. type_or_const_params , bound) ;
150- let type_args = make_type_args ( info. type_or_const_params , Vec :: new ( ) ) ;
151- let trait_path = trait_path. token_trees ;
152138 let expanded = quote ! {
153- impl ##type_params ## trait_path for #name ##type_args { }
139+ impl < ##params > # trait_path for #name < ##args > { }
154140 } ;
155141 ExpandResult :: ok ( expanded)
156142}
0 commit comments