@@ -82,6 +82,7 @@ use syntax::ast_map;
82
82
use syntax:: ast_util;
83
83
use syntax:: ast_util:: name_to_dummy_lifetime;
84
84
use syntax:: owned_slice:: OwnedSlice ;
85
+ use syntax:: codemap;
85
86
use syntax:: parse:: token;
86
87
use syntax:: print:: pprust;
87
88
use util:: ppaux:: UserString ;
@@ -143,10 +144,12 @@ trait ErrorReportingHelpers {
143
144
origin : SubregionOrigin ) ;
144
145
145
146
fn give_expl_lifetime_param ( & self ,
146
- inputs : Vec < ast:: Arg > ,
147
- output : ast:: P < ast:: Ty > ,
148
- item : ast:: P < ast:: Item > ,
149
- generics : ast:: Generics ) ;
147
+ decl : & ast:: FnDecl ,
148
+ fn_style : ast:: FnStyle ,
149
+ ident : ast:: Ident ,
150
+ opt_explicit_self : Option < ast:: ExplicitSelf_ > ,
151
+ generics : & ast:: Generics ,
152
+ span : codemap:: Span ) ;
150
153
}
151
154
152
155
impl < ' a > ErrorReporting for InferCtxt < ' a > {
@@ -260,6 +263,19 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
260
263
scope_id : ast:: NodeId
261
264
}
262
265
266
+ impl FreeRegionsFromSameFn {
267
+ fn new ( sub_fr : ty:: FreeRegion ,
268
+ sup_fr : ty:: FreeRegion ,
269
+ scope_id : ast:: NodeId )
270
+ -> FreeRegionsFromSameFn {
271
+ FreeRegionsFromSameFn {
272
+ sub_fr : sub_fr,
273
+ sup_fr : sup_fr,
274
+ scope_id : scope_id
275
+ }
276
+ }
277
+ }
278
+
263
279
fn free_regions_from_same_fn ( tcx : & ty:: ctxt ,
264
280
sub : Region ,
265
281
sup : Region )
@@ -280,17 +296,14 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
280
296
match parent_node {
281
297
Some ( node) => match node {
282
298
ast_map:: NodeItem ( item) => match item. node {
283
- // FIXME: handle method
284
299
ast:: ItemFn ( ..) => {
285
- let fr_from_same_fn = FreeRegionsFromSameFn {
286
- sub_fr : fr1,
287
- sup_fr : fr2,
288
- scope_id : scope_id
289
- } ;
290
- Some ( fr_from_same_fn)
300
+ Some ( FreeRegionsFromSameFn :: new ( fr1, fr2, scope_id) )
291
301
} ,
292
302
_ => None
293
303
} ,
304
+ ast_map:: NodeMethod ( ..) => {
305
+ Some ( FreeRegionsFromSameFn :: new ( fr1, fr2, scope_id) )
306
+ } ,
294
307
_ => None
295
308
} ,
296
309
None => {
@@ -662,21 +675,28 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
662
675
let node_inner = match parent_node {
663
676
Some ( node) => match node {
664
677
ast_map:: NodeItem ( item) => match item. node {
665
- // FIXME: handling method
666
- ast:: ItemFn ( ref fn_decl, _, _, ref gen, _) => {
667
- Some ( ( item, fn_decl, gen) )
678
+ ast:: ItemFn ( ref fn_decl, ref pur, _, ref gen, _) => {
679
+ Some ( ( fn_decl, gen, * pur, item. ident , None , item. span ) )
668
680
} ,
669
681
_ => None
670
682
} ,
683
+ ast_map:: NodeMethod ( m) => {
684
+ Some ( ( & m. decl , & m. generics , m. fn_style ,
685
+ m. ident , Some ( m. explicit_self . node ) , m. span ) )
686
+ } ,
671
687
_ => None
672
688
} ,
673
689
None => None
674
690
} ;
675
- let ( item, fn_decl, generics) = node_inner. expect ( "expect item fn" ) ;
676
- let rebuilder = Rebuilder :: new ( self . tcx , * fn_decl,
677
- generics, same_regions) ;
678
- let ( inputs, output, generics) = rebuilder. rebuild ( ) ;
679
- self . give_expl_lifetime_param ( inputs, output, item, generics) ;
691
+ let ( fn_decl, generics, fn_style, ident, expl_self, span)
692
+ = node_inner. expect ( "expect item fn" ) ;
693
+ let taken = lifetimes_in_scope ( self . tcx , scope_id) ;
694
+ let life_giver = LifeGiver :: with_taken ( taken. as_slice ( ) ) ;
695
+ let rebuilder = Rebuilder :: new ( self . tcx , * fn_decl, expl_self,
696
+ generics, same_regions, & life_giver) ;
697
+ let ( fn_decl, expl_self, generics) = rebuilder. rebuild ( ) ;
698
+ self . give_expl_lifetime_param ( & fn_decl, fn_style, ident,
699
+ expl_self, & generics, span) ;
680
700
}
681
701
}
682
702
@@ -694,53 +714,98 @@ struct RebuildPathInfo<'a> {
694
714
struct Rebuilder < ' a > {
695
715
tcx : & ' a ty:: ctxt ,
696
716
fn_decl : ast:: P < ast:: FnDecl > ,
717
+ expl_self_opt : Option < ast:: ExplicitSelf_ > ,
697
718
generics : & ' a ast:: Generics ,
698
719
same_regions : & ' a [ SameRegions ] ,
699
- life_giver : LifeGiver ,
720
+ life_giver : & ' a LifeGiver ,
700
721
cur_anon : Cell < uint > ,
701
722
inserted_anons : RefCell < HashSet < uint > > ,
702
723
}
703
724
725
+ enum FreshOrKept {
726
+ Fresh ,
727
+ Kept
728
+ }
729
+
704
730
impl < ' a > Rebuilder < ' a > {
705
731
fn new ( tcx : & ' a ty:: ctxt ,
706
732
fn_decl : ast:: P < ast:: FnDecl > ,
733
+ expl_self_opt : Option < ast:: ExplicitSelf_ > ,
707
734
generics : & ' a ast:: Generics ,
708
- same_regions : & ' a [ SameRegions ] )
735
+ same_regions : & ' a [ SameRegions ] ,
736
+ life_giver : & ' a LifeGiver )
709
737
-> Rebuilder < ' a > {
710
738
Rebuilder {
711
739
tcx : tcx,
712
740
fn_decl : fn_decl,
741
+ expl_self_opt : expl_self_opt,
713
742
generics : generics,
714
743
same_regions : same_regions,
715
- life_giver : LifeGiver :: with_taken ( generics . lifetimes . as_slice ( ) ) ,
744
+ life_giver : life_giver ,
716
745
cur_anon : Cell :: new ( 0 ) ,
717
746
inserted_anons : RefCell :: new ( HashSet :: new ( ) ) ,
718
747
}
719
748
}
720
749
721
- fn rebuild ( & self ) -> ( Vec < ast:: Arg > , ast:: P < ast:: Ty > , ast:: Generics ) {
750
+ fn rebuild ( & self )
751
+ -> ( ast:: FnDecl , Option < ast:: ExplicitSelf_ > , ast:: Generics ) {
752
+ let mut expl_self_opt = self . expl_self_opt ;
722
753
let mut inputs = self . fn_decl . inputs . clone ( ) ;
723
754
let mut output = self . fn_decl . output ;
724
755
let mut ty_params = self . generics . ty_params . clone ( ) ;
756
+ let mut kept_lifetimes = HashSet :: new ( ) ;
725
757
for sr in self . same_regions . iter ( ) {
726
758
self . cur_anon . set ( 0 ) ;
727
759
self . offset_cur_anon ( ) ;
728
760
let ( anon_nums, region_names) =
729
761
self . extract_anon_nums_and_names ( sr) ;
730
- let lifetime = self . life_giver . give_lifetime ( ) ;
762
+ let ( lifetime, fresh_or_kept) = self . pick_lifetime ( & region_names) ;
763
+ match fresh_or_kept {
764
+ Kept => { kept_lifetimes. insert ( lifetime. name ) ; }
765
+ _ => ( )
766
+ }
767
+ expl_self_opt = self . rebuild_expl_self ( expl_self_opt, lifetime,
768
+ & anon_nums, & region_names) ;
731
769
inputs = self . rebuild_args_ty ( inputs. as_slice ( ) , lifetime,
732
770
& anon_nums, & region_names) ;
733
771
output = self . rebuild_arg_ty_or_output ( output, lifetime,
734
772
& anon_nums, & region_names) ;
735
773
ty_params = self . rebuild_ty_params ( ty_params, lifetime,
736
774
& region_names) ;
737
775
}
738
- let generated_lifetimes = self . life_giver . get_generated_lifetimes ( ) ;
776
+ let fresh_lifetimes = self . life_giver . get_generated_lifetimes ( ) ;
739
777
let all_region_names = self . extract_all_region_names ( ) ;
740
778
let generics = self . rebuild_generics ( self . generics ,
741
- generated_lifetimes,
742
- & all_region_names, ty_params) ;
743
- ( inputs, output, generics)
779
+ & fresh_lifetimes,
780
+ & kept_lifetimes,
781
+ & all_region_names,
782
+ ty_params) ;
783
+ let new_fn_decl = ast:: FnDecl {
784
+ inputs : inputs,
785
+ output : output,
786
+ cf : self . fn_decl . cf ,
787
+ variadic : self . fn_decl . variadic
788
+ } ;
789
+ ( new_fn_decl, expl_self_opt, generics)
790
+ }
791
+
792
+ fn pick_lifetime ( & self ,
793
+ region_names : & HashSet < ast:: Name > )
794
+ -> ( ast:: Lifetime , FreshOrKept ) {
795
+ if region_names. len ( ) > 0 {
796
+ // It's not necessary to convert the set of region names to a
797
+ // vector of string and then sort them. However, it makes the
798
+ // choice of lifetime name deterministic and thus easier to test.
799
+ let mut names = Vec :: new ( ) ;
800
+ for rn in region_names. iter ( ) {
801
+ let lt_name = token:: get_name ( * rn) . get ( ) . to_owned ( ) ;
802
+ names. push ( lt_name) ;
803
+ }
804
+ names. sort ( ) ;
805
+ let name = token:: str_to_ident ( names. get ( 0 ) . as_slice ( ) ) . name ;
806
+ return ( name_to_dummy_lifetime ( name) , Kept ) ;
807
+ }
808
+ return ( self . life_giver . give_lifetime ( ) , Fresh ) ;
744
809
}
745
810
746
811
fn extract_anon_nums_and_names ( & self , same_regions : & SameRegions )
@@ -849,9 +914,38 @@ impl<'a> Rebuilder<'a> {
849
914
} )
850
915
}
851
916
917
+ fn rebuild_expl_self ( & self ,
918
+ expl_self_opt : Option < ast:: ExplicitSelf_ > ,
919
+ lifetime : ast:: Lifetime ,
920
+ anon_nums : & HashSet < uint > ,
921
+ region_names : & HashSet < ast:: Name > )
922
+ -> Option < ast:: ExplicitSelf_ > {
923
+ match expl_self_opt {
924
+ Some ( expl_self) => match expl_self {
925
+ ast:: SelfRegion ( lt_opt, muta) => match lt_opt {
926
+ Some ( lt) => if region_names. contains ( & lt. name ) {
927
+ return Some ( ast:: SelfRegion ( Some ( lifetime) , muta) ) ;
928
+ } ,
929
+ None => {
930
+ let anon = self . cur_anon . get ( ) ;
931
+ self . inc_and_offset_cur_anon ( 1 ) ;
932
+ if anon_nums. contains ( & anon) {
933
+ self . track_anon ( anon) ;
934
+ return Some ( ast:: SelfRegion ( Some ( lifetime) , muta) ) ;
935
+ }
936
+ }
937
+ } ,
938
+ _ => ( )
939
+ } ,
940
+ None => ( )
941
+ }
942
+ expl_self_opt
943
+ }
944
+
852
945
fn rebuild_generics ( & self ,
853
946
generics : & ast:: Generics ,
854
- add : Vec < ast:: Lifetime > ,
947
+ add : & Vec < ast:: Lifetime > ,
948
+ keep : & HashSet < ast:: Name > ,
855
949
remove : & HashSet < ast:: Name > ,
856
950
ty_params : OwnedSlice < ast:: TyParam > )
857
951
-> ast:: Generics {
@@ -860,7 +954,7 @@ impl<'a> Rebuilder<'a> {
860
954
lifetimes. push ( * lt) ;
861
955
}
862
956
for lt in generics. lifetimes . iter ( ) {
863
- if !remove. contains ( & lt. name ) {
957
+ if keep . contains ( & lt . name ) || !remove. contains ( & lt. name ) {
864
958
lifetimes. push ( ( * lt) . clone ( ) ) ;
865
959
}
866
960
}
@@ -1099,29 +1193,17 @@ impl<'a> Rebuilder<'a> {
1099
1193
1100
1194
impl < ' a > ErrorReportingHelpers for InferCtxt < ' a > {
1101
1195
fn give_expl_lifetime_param ( & self ,
1102
- inputs : Vec < ast:: Arg > ,
1103
- output : ast:: P < ast:: Ty > ,
1104
- item : ast:: P < ast:: Item > ,
1105
- generics : ast:: Generics ) {
1106
- let ( fn_decl, fn_style, ident) = match item. node {
1107
- // FIXME: handling method
1108
- ast:: ItemFn ( ref fn_decl, ref fn_style, _, _, _) => {
1109
- ( fn_decl, fn_style, item. ident )
1110
- } ,
1111
- _ => fail ! ( "Expect function or method" )
1112
-
1113
- } ;
1114
- let fd = ast:: FnDecl {
1115
- inputs : inputs,
1116
- output : output,
1117
- cf : fn_decl. cf ,
1118
- variadic : fn_decl. variadic
1119
- } ;
1120
- let suggested_fn =
1121
- pprust:: fun_to_str ( & fd, * fn_style, ident, None , & generics) ;
1196
+ decl : & ast:: FnDecl ,
1197
+ fn_style : ast:: FnStyle ,
1198
+ ident : ast:: Ident ,
1199
+ opt_explicit_self : Option < ast:: ExplicitSelf_ > ,
1200
+ generics : & ast:: Generics ,
1201
+ span : codemap:: Span ) {
1202
+ let suggested_fn = pprust:: fun_to_str ( decl, fn_style, ident,
1203
+ opt_explicit_self, generics) ;
1122
1204
let msg = format ! ( "consider using an explicit lifetime \
1123
1205
parameter as shown: {}", suggested_fn) ;
1124
- self . tcx . sess . span_note ( item . span , msg) ;
1206
+ self . tcx . sess . span_note ( span, msg) ;
1125
1207
}
1126
1208
1127
1209
fn report_inference_failure ( & self ,
@@ -1318,6 +1400,47 @@ impl Resolvable for @ty::TraitRef {
1318
1400
}
1319
1401
}
1320
1402
1403
+ fn lifetimes_in_scope ( tcx : & ty:: ctxt ,
1404
+ scope_id : ast:: NodeId )
1405
+ -> Vec < ast:: Lifetime > {
1406
+ let mut taken = Vec :: new ( ) ;
1407
+ let parent = tcx. map . get_parent ( scope_id) ;
1408
+ let method_id_opt = match tcx. map . find ( parent) {
1409
+ Some ( node) => match node {
1410
+ ast_map:: NodeItem ( item) => match item. node {
1411
+ ast:: ItemFn ( _, _, _, ref gen, _) => {
1412
+ taken. push_all ( gen. lifetimes . as_slice ( ) ) ;
1413
+ None
1414
+ } ,
1415
+ _ => None
1416
+ } ,
1417
+ ast_map:: NodeMethod ( m) => {
1418
+ taken. push_all ( m. generics . lifetimes . as_slice ( ) ) ;
1419
+ Some ( m. id )
1420
+ } ,
1421
+ _ => None
1422
+ } ,
1423
+ None => None
1424
+ } ;
1425
+ if method_id_opt. is_some ( ) {
1426
+ let method_id = method_id_opt. unwrap ( ) ;
1427
+ let parent = tcx. map . get_parent ( method_id) ;
1428
+ match tcx. map . find ( parent) {
1429
+ Some ( node) => match node {
1430
+ ast_map:: NodeItem ( item) => match item. node {
1431
+ ast:: ItemImpl ( ref gen, _, _, _) => {
1432
+ taken. push_all ( gen. lifetimes . as_slice ( ) ) ;
1433
+ }
1434
+ _ => ( )
1435
+ } ,
1436
+ _ => ( )
1437
+ } ,
1438
+ None => ( )
1439
+ }
1440
+ }
1441
+ return taken;
1442
+ }
1443
+
1321
1444
// LifeGiver is responsible for generating fresh lifetime names
1322
1445
struct LifeGiver {
1323
1446
taken : HashSet < ~str > ,
@@ -1326,7 +1449,6 @@ struct LifeGiver {
1326
1449
}
1327
1450
1328
1451
impl LifeGiver {
1329
- // FIXME: `taken` needs to include names from higher scope, too
1330
1452
fn with_taken ( taken : & [ ast:: Lifetime ] ) -> LifeGiver {
1331
1453
let mut taken_ = HashSet :: new ( ) ;
1332
1454
for lt in taken. iter ( ) {
0 commit comments