@@ -120,7 +120,6 @@ pub(crate) fn insert_use(
120120 }
121121
122122 if let ident_level @ 1 ..=usize:: MAX = scope. indent_level ( ) . 0 as usize {
123- // FIXME: this alone doesnt properly re-align all cases
124123 buf. push ( make:: tokens:: whitespace ( & " " . repeat ( 4 * ident_level) ) . into ( ) ) ;
125124 }
126125 buf. push ( use_item. syntax ( ) . clone ( ) . into ( ) ) ;
@@ -164,44 +163,6 @@ pub(crate) fn try_merge_imports(
164163 Some ( old. with_use_tree ( merged) )
165164}
166165
167- /// Orders paths in the following way:
168- /// the sole self token comes first, after that come uppercase identifiers, then lowercase identifiers
169- /// FIXME: rustfmt sort lowercase idents before uppercase
170- fn path_cmp ( a : & ast:: Path , b : & ast:: Path ) -> Ordering {
171- let a = segment_iter ( a) ;
172- let b = segment_iter ( b) ;
173- let mut a_clone = a. clone ( ) ;
174- let mut b_clone = b. clone ( ) ;
175- match (
176- a_clone. next ( ) . and_then ( |ps| ps. self_token ( ) ) . is_some ( ) && a_clone. next ( ) . is_none ( ) ,
177- b_clone. next ( ) . and_then ( |ps| ps. self_token ( ) ) . is_some ( ) && b_clone. next ( ) . is_none ( ) ,
178- ) {
179- ( true , true ) => Ordering :: Equal ,
180- ( true , false ) => Ordering :: Less ,
181- ( false , true ) => Ordering :: Greater ,
182- ( false , false ) => {
183- // cmp_by would be useful for us here but that is currently unstable
184- // cmp doesnt work due the lifetimes on text's return type
185- a. zip ( b)
186- . flat_map ( |( seg, seg2) | seg. name_ref ( ) . zip ( seg2. name_ref ( ) ) )
187- . find_map ( |( a, b) | match a. text ( ) . cmp ( b. text ( ) ) {
188- ord @ Ordering :: Greater | ord @ Ordering :: Less => Some ( ord) ,
189- Ordering :: Equal => None ,
190- } )
191- . unwrap_or ( Ordering :: Equal )
192- }
193- }
194- }
195-
196- fn path_cmp_opt ( a : Option < ast:: Path > , b : Option < ast:: Path > ) -> Ordering {
197- match ( a, b) {
198- ( None , None ) => Ordering :: Equal ,
199- ( None , Some ( _) ) => Ordering :: Less ,
200- ( Some ( _) , None ) => Ordering :: Greater ,
201- ( Some ( a) , Some ( b) ) => path_cmp ( & a, & b) ,
202- }
203- }
204-
205166pub ( crate ) fn try_merge_trees (
206167 old : & ast:: UseTree ,
207168 new : & ast:: UseTree ,
@@ -216,17 +177,18 @@ pub(crate) fn try_merge_trees(
216177 recursive_merge ( & lhs, & rhs, merge) . map ( |( merged, _) | merged)
217178}
218179
219- /// Returns the merged tree and the number of children it has, which is required to check if the tree is allowed to be used for MergeBehaviour::Last
180+ /// Recursively "zips" together lhs and rhs.
220181fn recursive_merge (
221182 lhs : & ast:: UseTree ,
222183 rhs : & ast:: UseTree ,
223184 merge : MergeBehaviour ,
224- ) -> Option < ( ast:: UseTree , usize ) > {
185+ ) -> Option < ( ast:: UseTree , bool ) > {
225186 let mut use_trees = lhs
226187 . use_tree_list ( )
227188 . into_iter ( )
228189 . flat_map ( |list| list. use_trees ( ) )
229- // check if any of the use trees are nested, if they are and the behaviour is last only we are not allowed to merge this
190+ // check if any of the use trees are nested, if they are and the behaviour is `last` we are not allowed to merge this
191+ // so early exit the iterator by using Option's Intoiterator impl
230192 . map ( |tree| match merge == MergeBehaviour :: Last && tree. use_tree_list ( ) . is_some ( ) {
231193 true => None ,
232194 false => Some ( tree) ,
@@ -237,15 +199,17 @@ fn recursive_merge(
237199 let rhs_path = rhs_t. path ( ) ;
238200 match use_trees. binary_search_by ( |p| path_cmp_opt ( p. path ( ) , rhs_path. clone ( ) ) ) {
239201 Ok ( idx) => {
240- let lhs_path = use_trees[ idx] . path ( ) ?;
202+ let lhs_t = & mut use_trees[ idx] ;
203+ let lhs_path = lhs_t. path ( ) ?;
241204 let rhs_path = rhs_path?;
242205 let ( lhs_prefix, rhs_prefix) = common_prefix ( & lhs_path, & rhs_path) ?;
243206 if lhs_prefix == lhs_path && rhs_prefix == rhs_path {
244- let tree_is_self =
245- |tree : ast:: UseTree | tree. path ( ) . map ( path_is_self) . unwrap_or ( false ) ;
207+ let tree_is_self = |tree : ast:: UseTree | {
208+ tree. path ( ) . as_ref ( ) . map ( path_is_self) . unwrap_or ( false )
209+ } ;
246210 // check if only one of the two trees has a tree list, and whether that then contains `self` or not.
247211 // If this is the case we can skip this iteration since the path without the list is already included in the other one via `self`
248- if use_trees [ idx ]
212+ if lhs_t
249213 . use_tree_list ( )
250214 . xor ( rhs_t. use_tree_list ( ) )
251215 . map ( |tree_list| tree_list. use_trees ( ) . any ( tree_is_self) )
@@ -257,8 +221,8 @@ fn recursive_merge(
257221 // glob imports arent part of the use-tree lists so we need to special handle them here as well
258222 // this special handling is only required for when we merge a module import into a glob import of said module
259223 // see the `merge_self_glob` or `merge_mod_into_glob` tests
260- if use_trees [ idx ] . star_token ( ) . is_some ( ) || rhs_t. star_token ( ) . is_some ( ) {
261- use_trees [ idx ] = make:: use_tree (
224+ if lhs_t . star_token ( ) . is_some ( ) || rhs_t. star_token ( ) . is_some ( ) {
225+ * lhs_t = make:: use_tree (
262226 make:: path_unqualified ( make:: path_segment_self ( ) ) ,
263227 None ,
264228 None ,
@@ -276,11 +240,14 @@ fn recursive_merge(
276240 continue ;
277241 }
278242 }
279- let lhs = use_trees [ idx ] . split_prefix ( & lhs_prefix) ;
243+ let lhs = lhs_t . split_prefix ( & lhs_prefix) ;
280244 let rhs = rhs_t. split_prefix ( & rhs_prefix) ;
245+ let this_has_children = use_trees. len ( ) > 0 ;
281246 match recursive_merge ( & lhs, & rhs, merge) {
282- Some ( ( _, count) )
283- if merge == MergeBehaviour :: Last && use_trees. len ( ) > 1 && count > 1 =>
247+ Some ( ( _, has_multiple_children) )
248+ if merge == MergeBehaviour :: Last
249+ && this_has_children
250+ && has_multiple_children =>
284251 {
285252 return None
286253 }
@@ -293,9 +260,8 @@ fn recursive_merge(
293260 }
294261 }
295262 }
296- let count = use_trees. len ( ) ;
297- let tl = make:: use_tree_list ( use_trees) ;
298- Some ( ( lhs. with_use_tree_list ( tl) , count) )
263+ let has_multiple_children = use_trees. len ( ) > 1 ;
264+ Some ( ( lhs. with_use_tree_list ( make:: use_tree_list ( use_trees) ) , has_multiple_children) )
299265}
300266
301267/// Traverses both paths until they differ, returning the common prefix of both.
@@ -306,7 +272,7 @@ fn common_prefix(lhs: &ast::Path, rhs: &ast::Path) -> Option<(ast::Path, ast::Pa
306272 loop {
307273 match ( lhs_curr. segment ( ) , rhs_curr. segment ( ) ) {
308274 ( Some ( lhs) , Some ( rhs) ) if lhs. syntax ( ) . text ( ) == rhs. syntax ( ) . text ( ) => ( ) ,
309- _ => break ,
275+ _ => break res ,
310276 }
311277 res = Some ( ( lhs_curr. clone ( ) , rhs_curr. clone ( ) ) ) ;
312278
@@ -315,17 +281,16 @@ fn common_prefix(lhs: &ast::Path, rhs: &ast::Path) -> Option<(ast::Path, ast::Pa
315281 lhs_curr = lhs;
316282 rhs_curr = rhs;
317283 }
318- _ => break ,
284+ _ => break res ,
319285 }
320286 }
321-
322- res
323287}
324288
325- fn path_is_self ( path : ast:: Path ) -> bool {
289+ fn path_is_self ( path : & ast:: Path ) -> bool {
326290 path. segment ( ) . and_then ( |seg| seg. self_token ( ) ) . is_some ( ) && path. qualifier ( ) . is_none ( )
327291}
328292
293+ #[ inline]
329294fn first_segment ( path : & ast:: Path ) -> Option < ast:: PathSegment > {
330295 first_path ( path) . segment ( )
331296}
@@ -339,6 +304,41 @@ fn segment_iter(path: &ast::Path) -> impl Iterator<Item = ast::PathSegment> + Cl
339304 successors ( first_segment ( path) , |p| p. parent_path ( ) . parent_path ( ) . and_then ( |p| p. segment ( ) ) )
340305}
341306
307+ /// Orders paths in the following way:
308+ /// the sole self token comes first, after that come uppercase identifiers, then lowercase identifiers
309+ // FIXME: rustfmt sort lowercase idents before uppercase, in general we want to have the same ordering rustfmt has
310+ // which is `self` and `super` first, then identifier imports with lowercase ones first, then glob imports and at last list imports.
311+ // Example foo::{self, foo, baz, Baz, Qux, *, {Bar}}
312+ fn path_cmp ( a : & ast:: Path , b : & ast:: Path ) -> Ordering {
313+ match ( path_is_self ( a) , path_is_self ( b) ) {
314+ ( true , true ) => Ordering :: Equal ,
315+ ( true , false ) => Ordering :: Less ,
316+ ( false , true ) => Ordering :: Greater ,
317+ ( false , false ) => {
318+ let a = segment_iter ( a) ;
319+ let b = segment_iter ( b) ;
320+ // cmp_by would be useful for us here but that is currently unstable
321+ // cmp doesnt work due the lifetimes on text's return type
322+ a. zip ( b)
323+ . flat_map ( |( seg, seg2) | seg. name_ref ( ) . zip ( seg2. name_ref ( ) ) )
324+ . find_map ( |( a, b) | match a. text ( ) . cmp ( b. text ( ) ) {
325+ ord @ Ordering :: Greater | ord @ Ordering :: Less => Some ( ord) ,
326+ Ordering :: Equal => None ,
327+ } )
328+ . unwrap_or ( Ordering :: Equal )
329+ }
330+ }
331+ }
332+
333+ fn path_cmp_opt ( a : Option < ast:: Path > , b : Option < ast:: Path > ) -> Ordering {
334+ match ( a, b) {
335+ ( None , None ) => Ordering :: Equal ,
336+ ( None , Some ( _) ) => Ordering :: Less ,
337+ ( Some ( _) , None ) => Ordering :: Greater ,
338+ ( Some ( a) , Some ( b) ) => path_cmp ( & a, & b) ,
339+ }
340+ }
341+
342342/// What type of merges are allowed.
343343#[ derive( Copy , Clone , PartialEq , Eq ) ]
344344pub enum MergeBehaviour {
@@ -924,6 +924,6 @@ use foo::bar::baz::Qux;",
924924 . unwrap ( ) ;
925925
926926 let result = try_merge_imports ( & use0, & use1, mb) ;
927- assert_eq ! ( result, None ) ;
927+ assert_eq ! ( result. map ( |u| u . to_string ( ) ) , None ) ;
928928 }
929929}
0 commit comments