@@ -82,6 +82,7 @@ use syntax::ast_map;
8282use syntax:: ast_util;
8383use syntax:: ast_util:: name_to_dummy_lifetime;
8484use syntax:: owned_slice:: OwnedSlice ;
85+ use syntax:: codemap;
8586use syntax:: parse:: token;
8687use syntax:: print:: pprust;
8788use util:: ppaux:: UserString ;
@@ -143,10 +144,12 @@ trait ErrorReportingHelpers {
143144 origin : SubregionOrigin ) ;
144145
145146 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 ) ;
150153}
151154
152155impl < ' a > ErrorReporting for InferCtxt < ' a > {
@@ -260,6 +263,19 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
260263 scope_id : ast:: NodeId
261264 }
262265
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+
263279 fn free_regions_from_same_fn ( tcx : & ty:: ctxt ,
264280 sub : Region ,
265281 sup : Region )
@@ -280,17 +296,14 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
280296 match parent_node {
281297 Some ( node) => match node {
282298 ast_map:: NodeItem ( item) => match item. node {
283- // FIXME: handle method
284299 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) )
291301 } ,
292302 _ => None
293303 } ,
304+ ast_map:: NodeMethod ( ..) => {
305+ Some ( FreeRegionsFromSameFn :: new ( fr1, fr2, scope_id) )
306+ } ,
294307 _ => None
295308 } ,
296309 None => {
@@ -662,21 +675,28 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
662675 let node_inner = match parent_node {
663676 Some ( node) => match node {
664677 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 ) )
668680 } ,
669681 _ => None
670682 } ,
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+ } ,
671687 _ => None
672688 } ,
673689 None => None
674690 } ;
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) ;
680700 }
681701}
682702
@@ -694,53 +714,98 @@ struct RebuildPathInfo<'a> {
694714struct Rebuilder < ' a > {
695715 tcx : & ' a ty:: ctxt ,
696716 fn_decl : ast:: P < ast:: FnDecl > ,
717+ expl_self_opt : Option < ast:: ExplicitSelf_ > ,
697718 generics : & ' a ast:: Generics ,
698719 same_regions : & ' a [ SameRegions ] ,
699- life_giver : LifeGiver ,
720+ life_giver : & ' a LifeGiver ,
700721 cur_anon : Cell < uint > ,
701722 inserted_anons : RefCell < HashSet < uint > > ,
702723}
703724
725+ enum FreshOrKept {
726+ Fresh ,
727+ Kept
728+ }
729+
704730impl < ' a > Rebuilder < ' a > {
705731 fn new ( tcx : & ' a ty:: ctxt ,
706732 fn_decl : ast:: P < ast:: FnDecl > ,
733+ expl_self_opt : Option < ast:: ExplicitSelf_ > ,
707734 generics : & ' a ast:: Generics ,
708- same_regions : & ' a [ SameRegions ] )
735+ same_regions : & ' a [ SameRegions ] ,
736+ life_giver : & ' a LifeGiver )
709737 -> Rebuilder < ' a > {
710738 Rebuilder {
711739 tcx : tcx,
712740 fn_decl : fn_decl,
741+ expl_self_opt : expl_self_opt,
713742 generics : generics,
714743 same_regions : same_regions,
715- life_giver : LifeGiver :: with_taken ( generics . lifetimes . as_slice ( ) ) ,
744+ life_giver : life_giver ,
716745 cur_anon : Cell :: new ( 0 ) ,
717746 inserted_anons : RefCell :: new ( HashSet :: new ( ) ) ,
718747 }
719748 }
720749
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 ;
722753 let mut inputs = self . fn_decl . inputs . clone ( ) ;
723754 let mut output = self . fn_decl . output ;
724755 let mut ty_params = self . generics . ty_params . clone ( ) ;
756+ let mut kept_lifetimes = HashSet :: new ( ) ;
725757 for sr in self . same_regions . iter ( ) {
726758 self . cur_anon . set ( 0 ) ;
727759 self . offset_cur_anon ( ) ;
728760 let ( anon_nums, region_names) =
729761 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) ;
731769 inputs = self . rebuild_args_ty ( inputs. as_slice ( ) , lifetime,
732770 & anon_nums, & region_names) ;
733771 output = self . rebuild_arg_ty_or_output ( output, lifetime,
734772 & anon_nums, & region_names) ;
735773 ty_params = self . rebuild_ty_params ( ty_params, lifetime,
736774 & region_names) ;
737775 }
738- let generated_lifetimes = self . life_giver . get_generated_lifetimes ( ) ;
776+ let fresh_lifetimes = self . life_giver . get_generated_lifetimes ( ) ;
739777 let all_region_names = self . extract_all_region_names ( ) ;
740778 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 ) ;
744809 }
745810
746811 fn extract_anon_nums_and_names ( & self , same_regions : & SameRegions )
@@ -849,9 +914,38 @@ impl<'a> Rebuilder<'a> {
849914 } )
850915 }
851916
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+
852945 fn rebuild_generics ( & self ,
853946 generics : & ast:: Generics ,
854- add : Vec < ast:: Lifetime > ,
947+ add : & Vec < ast:: Lifetime > ,
948+ keep : & HashSet < ast:: Name > ,
855949 remove : & HashSet < ast:: Name > ,
856950 ty_params : OwnedSlice < ast:: TyParam > )
857951 -> ast:: Generics {
@@ -860,7 +954,7 @@ impl<'a> Rebuilder<'a> {
860954 lifetimes. push ( * lt) ;
861955 }
862956 for lt in generics. lifetimes . iter ( ) {
863- if !remove. contains ( & lt. name ) {
957+ if keep . contains ( & lt . name ) || !remove. contains ( & lt. name ) {
864958 lifetimes. push ( ( * lt) . clone ( ) ) ;
865959 }
866960 }
@@ -1099,29 +1193,17 @@ impl<'a> Rebuilder<'a> {
10991193
11001194impl < ' a > ErrorReportingHelpers for InferCtxt < ' a > {
11011195 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) ;
11221204 let msg = format ! ( "consider using an explicit lifetime \
11231205 parameter as shown: {}", suggested_fn) ;
1124- self . tcx . sess . span_note ( item . span , msg) ;
1206+ self . tcx . sess . span_note ( span, msg) ;
11251207 }
11261208
11271209 fn report_inference_failure ( & self ,
@@ -1318,6 +1400,47 @@ impl Resolvable for @ty::TraitRef {
13181400 }
13191401}
13201402
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+
13211444// LifeGiver is responsible for generating fresh lifetime names
13221445struct LifeGiver {
13231446 taken : HashSet < ~str > ,
@@ -1326,7 +1449,6 @@ struct LifeGiver {
13261449}
13271450
13281451impl LifeGiver {
1329- // FIXME: `taken` needs to include names from higher scope, too
13301452 fn with_taken ( taken : & [ ast:: Lifetime ] ) -> LifeGiver {
13311453 let mut taken_ = HashSet :: new ( ) ;
13321454 for lt in taken. iter ( ) {
0 commit comments