@@ -284,8 +284,8 @@ struct ContainerInfo {
284
284
parent_loop : Option < SyntaxNode > ,
285
285
/// The function's return type, const's type etc.
286
286
ret_type : Option < hir:: Type > ,
287
- generic_param_list : Option < ast:: GenericParamList > ,
288
- where_clause : Option < ast:: WhereClause > ,
287
+ generic_param_lists : Vec < ast:: GenericParamList > ,
288
+ where_clauses : Vec < ast:: WhereClause > ,
289
289
}
290
290
291
291
/// Control flow that is exported from extracted function
@@ -715,15 +715,11 @@ impl FunctionBody {
715
715
}
716
716
} ;
717
717
718
- let mut generic_param_list = None ;
719
- let mut where_clause = None ;
720
-
721
718
let ( is_const, expr, ty) = loop {
722
719
let anc = ancestors. next ( ) ?;
723
720
break match_ast ! {
724
721
match anc {
725
722
ast:: ClosureExpr ( closure) => {
726
- generic_param_list = closure. generic_param_list( ) ;
727
723
( false , closure. body( ) , infer_expr_opt( closure. body( ) ) )
728
724
} ,
729
725
ast:: BlockExpr ( block_expr) => {
@@ -744,8 +740,6 @@ impl FunctionBody {
744
740
ret_ty = async_ret;
745
741
}
746
742
}
747
- generic_param_list = fn_. generic_param_list( ) ;
748
- where_clause = fn_. where_clause( ) ;
749
743
( fn_. const_token( ) . is_some( ) , fn_. body( ) . map( ast:: Expr :: BlockExpr ) , Some ( ret_ty) )
750
744
} ,
751
745
ast:: Static ( statik) => {
@@ -790,13 +784,18 @@ impl FunctionBody {
790
784
container_tail. zip ( self . tail_expr ( ) ) . map_or ( false , |( container_tail, body_tail) | {
791
785
container_tail. syntax ( ) . text_range ( ) . contains_range ( body_tail. syntax ( ) . text_range ( ) )
792
786
} ) ;
787
+
788
+ let parent = self . parent ( ) ?;
789
+ let generic_param_list = parent_generic_param_lists ( & parent) ;
790
+ let where_clause = parent_where_clauses ( & parent) ;
791
+
793
792
Some ( ContainerInfo {
794
793
is_in_tail,
795
794
is_const,
796
795
parent_loop,
797
796
ret_type : ty,
798
- generic_param_list,
799
- where_clause,
797
+ generic_param_lists : generic_param_list,
798
+ where_clauses : where_clause,
800
799
} )
801
800
}
802
801
@@ -954,6 +953,26 @@ impl FunctionBody {
954
953
}
955
954
}
956
955
956
+ fn parent_where_clauses ( parent : & SyntaxNode ) -> Vec < ast:: WhereClause > {
957
+ let mut where_clause: Vec < ast:: WhereClause > = parent
958
+ . ancestors ( )
959
+ . filter_map ( ast:: AnyHasGenericParams :: cast)
960
+ . filter_map ( |it| it. where_clause ( ) )
961
+ . collect ( ) ;
962
+ where_clause. reverse ( ) ;
963
+ where_clause
964
+ }
965
+
966
+ fn parent_generic_param_lists ( parent : & SyntaxNode ) -> Vec < ast:: GenericParamList > {
967
+ let mut generic_param_list: Vec < ast:: GenericParamList > = parent
968
+ . ancestors ( )
969
+ . filter_map ( ast:: AnyHasGenericParams :: cast)
970
+ . filter_map ( |it| it. generic_param_list ( ) )
971
+ . collect ( ) ;
972
+ generic_param_list. reverse ( ) ;
973
+ generic_param_list
974
+ }
975
+
957
976
/// checks if relevant var is used with `&mut` access inside body
958
977
fn has_exclusive_usages ( ctx : & AssistContext , usages : & LocalUsages , body : & FunctionBody ) -> bool {
959
978
usages
@@ -1393,14 +1412,14 @@ fn format_function(
1393
1412
1394
1413
format_to ! ( fn_def, "{}" , params) ;
1395
1414
1396
- if let Some ( where_clause) = where_clause {
1397
- format_to ! ( fn_def, " {}" , where_clause) ;
1398
- }
1399
-
1400
1415
if let Some ( ret_ty) = ret_ty {
1401
1416
format_to ! ( fn_def, " {}" , ret_ty) ;
1402
1417
}
1403
1418
1419
+ if let Some ( where_clause) = where_clause {
1420
+ format_to ! ( fn_def, " {}" , where_clause) ;
1421
+ }
1422
+
1404
1423
format_to ! ( fn_def, " {}" , body) ;
1405
1424
1406
1425
fn_def
@@ -1412,34 +1431,32 @@ fn make_generic_params_and_where_clause(
1412
1431
) -> ( Option < ast:: GenericParamList > , Option < ast:: WhereClause > ) {
1413
1432
let used_type_params = fun. type_params ( ctx) ;
1414
1433
1415
- let generic_param_list = fun
1416
- . mods
1417
- . generic_param_list
1418
- . as_ref ( )
1419
- . map ( |parent_params| make_generic_param_list ( ctx, parent_params, & used_type_params) )
1420
- . flatten ( ) ;
1421
-
1422
- let where_clause =
1423
- fun. mods . where_clause . as_ref ( ) . map ( |parent_where_clause| {
1424
- make_where_clause ( ctx, parent_where_clause, & used_type_params)
1425
- } ) ;
1434
+ let generic_param_list = make_generic_param_list ( ctx, fun, & used_type_params) ;
1435
+ let where_clause = make_where_clause ( ctx, fun, & used_type_params) ;
1426
1436
1427
1437
( generic_param_list, where_clause)
1428
1438
}
1429
1439
1430
1440
fn make_generic_param_list (
1431
1441
ctx : & AssistContext ,
1432
- parent_params : & ast :: GenericParamList ,
1442
+ fun : & Function ,
1433
1443
used_type_params : & [ TypeParam ] ,
1434
1444
) -> Option < ast:: GenericParamList > {
1435
- let required_generic_params: Vec < ast:: GenericParam > = parent_params
1436
- . generic_params ( )
1437
- . filter ( |param| param_is_required ( ctx, param, used_type_params) )
1438
- . collect ( ) ;
1439
- if required_generic_params. is_empty ( ) {
1440
- None
1445
+ let mut generic_params = fun
1446
+ . mods
1447
+ . generic_param_lists
1448
+ . iter ( )
1449
+ . flat_map ( |parent_params| {
1450
+ parent_params
1451
+ . generic_params ( )
1452
+ . filter ( |param| param_is_required ( ctx, param, used_type_params) )
1453
+ } )
1454
+ . peekable ( ) ;
1455
+
1456
+ if generic_params. peek ( ) . is_some ( ) {
1457
+ Some ( make:: generic_param_list ( generic_params) )
1441
1458
} else {
1442
- Some ( make :: generic_param_list ( required_generic_params ) )
1459
+ None
1443
1460
}
1444
1461
}
1445
1462
@@ -1451,21 +1468,33 @@ fn param_is_required(
1451
1468
match param {
1452
1469
ast:: GenericParam :: ConstParam ( _) | ast:: GenericParam :: LifetimeParam ( _) => false ,
1453
1470
ast:: GenericParam :: TypeParam ( type_param) => match & ctx. sema . to_def ( type_param) {
1454
- Some ( def) => used_type_params. iter ( ) . contains ( def) ,
1471
+ Some ( def) => used_type_params. contains ( def) ,
1455
1472
_ => false ,
1456
1473
} ,
1457
1474
}
1458
1475
}
1459
1476
1460
1477
fn make_where_clause (
1461
1478
ctx : & AssistContext ,
1462
- parent_where_clause : & ast :: WhereClause ,
1479
+ fun : & Function ,
1463
1480
used_type_params : & [ TypeParam ] ,
1464
- ) -> ast:: WhereClause {
1465
- let preds = parent_where_clause
1466
- . predicates ( )
1467
- . filter ( |pred| pred_is_required ( ctx, pred, used_type_params) ) ;
1468
- make:: where_clause ( preds)
1481
+ ) -> Option < ast:: WhereClause > {
1482
+ let mut predicates = fun
1483
+ . mods
1484
+ . where_clauses
1485
+ . iter ( )
1486
+ . flat_map ( |parent_where_clause| {
1487
+ parent_where_clause
1488
+ . predicates ( )
1489
+ . filter ( |pred| pred_is_required ( ctx, pred, used_type_params) )
1490
+ } )
1491
+ . peekable ( ) ;
1492
+
1493
+ if predicates. peek ( ) . is_some ( ) {
1494
+ Some ( make:: where_clause ( predicates) )
1495
+ } else {
1496
+ None
1497
+ }
1469
1498
}
1470
1499
1471
1500
fn pred_is_required (
@@ -5052,6 +5081,122 @@ fn func<T, U>(i: T, u: U) where T: Debug, U: Copy {
5052
5081
fn $0fun_name<T>(i: T) where T: Debug {
5053
5082
foo(i);
5054
5083
}
5084
+ "# ,
5085
+ ) ;
5086
+ }
5087
+
5088
+ #[ test]
5089
+ fn nested_generics ( ) {
5090
+ check_assist (
5091
+ extract_function,
5092
+ r#"
5093
+ struct Struct<T: Into<i32>>(T);
5094
+ impl <T: Into<i32> + Copy> Struct<T> {
5095
+ fn func<V: Into<i32>>(&self, v: V) -> i32 {
5096
+ let t = self.0;
5097
+ $0t.into() + v.into()$0
5098
+ }
5099
+ }
5100
+ "# ,
5101
+ r#"
5102
+ struct Struct<T: Into<i32>>(T);
5103
+ impl <T: Into<i32> + Copy> Struct<T> {
5104
+ fn func<V: Into<i32>>(&self, v: V) -> i32 {
5105
+ let t = self.0;
5106
+ fun_name(t, v)
5107
+ }
5108
+ }
5109
+
5110
+ fn $0fun_name<T: Into<i32> + Copy, V: Into<i32>>(t: T, v: V) -> i32 {
5111
+ t.into() + v.into()
5112
+ }
5113
+ "# ,
5114
+ ) ;
5115
+ }
5116
+
5117
+ #[ test]
5118
+ fn filters_unused_nested_generics ( ) {
5119
+ check_assist (
5120
+ extract_function,
5121
+ r#"
5122
+ struct Struct<T: Into<i32>, U: Debug>(T, U);
5123
+ impl <T: Into<i32> + Copy, U: Debug> Struct<T, U> {
5124
+ fn func<V: Into<i32>>(&self, v: V) -> i32 {
5125
+ let t = self.0;
5126
+ $0t.into() + v.into()$0
5127
+ }
5128
+ }
5129
+ "# ,
5130
+ r#"
5131
+ struct Struct<T: Into<i32>, U: Debug>(T, U);
5132
+ impl <T: Into<i32> + Copy, U: Debug> Struct<T, U> {
5133
+ fn func<V: Into<i32>>(&self, v: V) -> i32 {
5134
+ let t = self.0;
5135
+ fun_name(t, v)
5136
+ }
5137
+ }
5138
+
5139
+ fn $0fun_name<T: Into<i32> + Copy, V: Into<i32>>(t: T, v: V) -> i32 {
5140
+ t.into() + v.into()
5141
+ }
5142
+ "# ,
5143
+ ) ;
5144
+ }
5145
+
5146
+ #[ test]
5147
+ fn nested_where_clauses ( ) {
5148
+ check_assist (
5149
+ extract_function,
5150
+ r#"
5151
+ struct Struct<T>(T) where T: Into<i32>;
5152
+ impl <T> Struct<T> where T: Into<i32> + Copy {
5153
+ fn func<V>(&self, v: V) -> i32 where V: Into<i32> {
5154
+ let t = self.0;
5155
+ $0t.into() + v.into()$0
5156
+ }
5157
+ }
5158
+ "# ,
5159
+ r#"
5160
+ struct Struct<T>(T) where T: Into<i32>;
5161
+ impl <T> Struct<T> where T: Into<i32> + Copy {
5162
+ fn func<V>(&self, v: V) -> i32 where V: Into<i32> {
5163
+ let t = self.0;
5164
+ fun_name(t, v)
5165
+ }
5166
+ }
5167
+
5168
+ fn $0fun_name<T, V>(t: T, v: V) -> i32 where T: Into<i32> + Copy, V: Into<i32> {
5169
+ t.into() + v.into()
5170
+ }
5171
+ "# ,
5172
+ ) ;
5173
+ }
5174
+
5175
+ #[ test]
5176
+ fn filters_unused_nested_where_clauses ( ) {
5177
+ check_assist (
5178
+ extract_function,
5179
+ r#"
5180
+ struct Struct<T, U>(T, U) where T: Into<i32>, U: Debug;
5181
+ impl <T, U> Struct<T, U> where T: Into<i32> + Copy, U: Debug {
5182
+ fn func<V>(&self, v: V) -> i32 where V: Into<i32> {
5183
+ let t = self.0;
5184
+ $0t.into() + v.into()$0
5185
+ }
5186
+ }
5187
+ "# ,
5188
+ r#"
5189
+ struct Struct<T, U>(T, U) where T: Into<i32>, U: Debug;
5190
+ impl <T, U> Struct<T, U> where T: Into<i32> + Copy, U: Debug {
5191
+ fn func<V>(&self, v: V) -> i32 where V: Into<i32> {
5192
+ let t = self.0;
5193
+ fun_name(t, v)
5194
+ }
5195
+ }
5196
+
5197
+ fn $0fun_name<T, V>(t: T, v: V) -> i32 where T: Into<i32> + Copy, V: Into<i32> {
5198
+ t.into() + v.into()
5199
+ }
5055
5200
"# ,
5056
5201
) ;
5057
5202
}
0 commit comments