@@ -11,12 +11,15 @@ use syntax::{
11
11
12
12
#[ derive( Default ) ]
13
13
struct AstSubsts {
14
- // ast::TypeArgs stands in fact for both type and const params
15
- // as consts declared elsewhere look just like type params.
16
- types_and_consts : Vec < ast:: TypeArg > ,
14
+ types_and_consts : Vec < TypeOrConst > ,
17
15
lifetimes : Vec < ast:: LifetimeArg > ,
18
16
}
19
17
18
+ enum TypeOrConst {
19
+ Either ( ast:: TypeArg ) , // indistinguishable type or const param
20
+ Const ( ast:: ConstArg ) ,
21
+ }
22
+
20
23
type LifetimeName = String ;
21
24
22
25
/// `PathTransform` substitutes path in SyntaxNodes in bulk.
@@ -125,27 +128,38 @@ impl<'a> PathTransform<'a> {
125
128
// the resulting change can be applied correctly.
126
129
. zip ( self . substs . types_and_consts . iter ( ) . map ( Some ) . chain ( std:: iter:: repeat ( None ) ) )
127
130
. for_each ( |( k, v) | match ( k. split ( db) , v) {
128
- ( Either :: Right ( t ) , Some ( v ) ) => {
131
+ ( Either :: Right ( k ) , Some ( TypeOrConst :: Either ( v ) ) ) => {
129
132
if let Some ( ty) = v. ty ( ) {
130
- type_substs. insert ( t , ty. clone ( ) ) ;
133
+ type_substs. insert ( k , ty. clone ( ) ) ;
131
134
}
132
135
}
133
- ( Either :: Right ( t ) , None ) => {
134
- if let Some ( default) = t . default ( db) {
136
+ ( Either :: Right ( k ) , None ) => {
137
+ if let Some ( default) = k . default ( db) {
135
138
if let Some ( default) =
136
139
& default. display_source_code ( db, source_module. into ( ) , false ) . ok ( )
137
140
{
138
- type_substs. insert ( t , ast:: make:: ty ( default) . clone_for_update ( ) ) ;
139
- default_types. push ( t ) ;
141
+ type_substs. insert ( k , ast:: make:: ty ( default) . clone_for_update ( ) ) ;
142
+ default_types. push ( k ) ;
140
143
}
141
144
}
142
145
}
143
- ( Either :: Left ( c ) , Some ( v ) ) => {
146
+ ( Either :: Left ( k ) , Some ( TypeOrConst :: Either ( v ) ) ) => {
144
147
if let Some ( ty) = v. ty ( ) {
145
- const_substs. insert ( c, ty. syntax ( ) . clone ( ) ) ;
148
+ const_substs. insert ( k, ty. syntax ( ) . clone ( ) ) ;
149
+ }
150
+ }
151
+ ( Either :: Left ( k) , Some ( TypeOrConst :: Const ( v) ) ) => {
152
+ if let Some ( expr) = v. expr ( ) {
153
+ // FIXME: expressions in curly brackets can cause ambiguity after insertion
154
+ // (e.g. `N * 2` -> `{1 + 1} * 2`; it's unclear whether `{1 + 1}`
155
+ // is a standalone statement or a part of another expresson)
156
+ // and sometimes require slight modifications; see
157
+ // https://doc.rust-lang.org/reference/statements.html#expression-statements
158
+ const_substs. insert ( k, expr. syntax ( ) . clone ( ) ) ;
146
159
}
147
160
}
148
161
( Either :: Left ( _) , None ) => ( ) , // FIXME: get default const value
162
+ _ => ( ) , // ignore mismatching params
149
163
} ) ;
150
164
let lifetime_substs: FxHashMap < _ , _ > = self
151
165
. generic_def
@@ -201,6 +215,9 @@ impl<'a> Ctx<'a> {
201
215
fn transform_default_type_substs ( & self , default_types : Vec < hir:: TypeParam > ) {
202
216
for k in default_types {
203
217
let v = self . type_substs . get ( & k) . unwrap ( ) ;
218
+ // `transform_path` may update a node's parent and that would break the
219
+ // tree traversal. Thus all paths in the tree are collected into a vec
220
+ // so that such operation is safe.
204
221
let paths = postorder ( & v. syntax ( ) ) . filter_map ( ast:: Path :: cast) . collect :: < Vec < _ > > ( ) ;
205
222
for path in paths {
206
223
self . transform_path ( path) ;
@@ -326,8 +343,12 @@ fn get_type_args_from_arg_list(generic_arg_list: ast::GenericArgList) -> Option<
326
343
// Const params are marked as consts on definition only,
327
344
// being passed to the trait they are indistguishable from type params;
328
345
// anyway, we don't really need to distinguish them here.
329
- ast:: GenericArg :: TypeArg ( type_or_const_arg) => {
330
- result. types_and_consts . push ( type_or_const_arg)
346
+ ast:: GenericArg :: TypeArg ( type_arg) => {
347
+ result. types_and_consts . push ( TypeOrConst :: Either ( type_arg) )
348
+ }
349
+ // Some const values are recognized correctly.
350
+ ast:: GenericArg :: ConstArg ( const_arg) => {
351
+ result. types_and_consts . push ( TypeOrConst :: Const ( const_arg) ) ;
331
352
}
332
353
ast:: GenericArg :: LifetimeArg ( l_arg) => result. lifetimes . push ( l_arg) ,
333
354
_ => ( ) ,
0 commit comments