Skip to content

Commit 75ac733

Browse files
committed
---
yaml --- r: 150802 b: refs/heads/try2 c: 79d1e5d h: refs/heads/master v: v3
1 parent ff90bfa commit 75ac733

File tree

4 files changed

+200
-58
lines changed

4 files changed

+200
-58
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ refs/heads/snap-stage3: 78a7676898d9f80ab540c6df5d4c9ce35bb50463
55
refs/heads/try: 519addf6277dbafccbb4159db4b710c37eaa2ec5
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
8-
refs/heads/try2: 189584e792bfc10142793ca1117e803c2201991a
8+
refs/heads/try2: 79d1e5df2190e4cfdd1814af95837b21ef046745
99
refs/heads/dist-snap: ba4081a5a8573875fed17545846f6f6902c8ba8d
1010
refs/tags/release-0.2: c870d2dffb391e14efb05aa27898f1f6333a9596
1111
refs/tags/release-0.3: b5f0d0f648d9a6153664837026ba1be43d3e2503

branches/try2/src/librustc/middle/typeck/infer/error_reporting.rs

Lines changed: 174 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ use syntax::ast_map;
8282
use syntax::ast_util;
8383
use syntax::ast_util::name_to_dummy_lifetime;
8484
use syntax::owned_slice::OwnedSlice;
85+
use syntax::codemap;
8586
use syntax::parse::token;
8687
use syntax::print::pprust;
8788
use 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

152155
impl<'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> {
694714
struct 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+
704730
impl<'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

11001194
impl<'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
13221445
struct LifeGiver {
13231446
taken: HashSet<~str>,
@@ -1326,7 +1449,6 @@ struct LifeGiver {
13261449
}
13271450

13281451
impl 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() {

branches/try2/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ impl<'r> Itble<'r, uint, Range<uint>> for (uint, uint) {
2222
}
2323

2424
fn check<'r, I: Iterator<uint>, T: Itble<'r, uint, I>>(cont: &T) -> bool {
25-
//~^ NOTE: consider using an explicit lifetime parameter as shown: fn check<'a, I: Iterator<uint>, T: Itble<'a, uint, I>>(cont: &'a T) -> bool
25+
//~^ NOTE: consider using an explicit lifetime parameter as shown: fn check<'r, I: Iterator<uint>, T: Itble<'r, uint, I>>(cont: &'r T) -> bool
2626
let cont_iter = cont.iter(); //~ ERROR: cannot infer
2727
let result = cont_iter.fold(Some(0u16), |state, val| {
2828
state.map_or(None, |mask| {

0 commit comments

Comments
 (0)