1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 Error Reporting Code for the inference engine
15 Because of the way inference, and in particular region inference,
16 works, it often happens that errors are not detected until far after
17 the relevant line of code has been type-checked. Therefore, there is
18 an elaborate system to track why a particular constraint in the
19 inference graph arose so that we can explain to the user what gave
20 rise to a particular error.
22 The basis of the system are the "origin" types. An "origin" is the
23 reason that a constraint or inference variable arose. There are
24 different "origin" enums for different kinds of constraints/variables
25 (e.g., `TypeOrigin`, `RegionVariableOrigin`). An origin always has
26 a span, but also more information so that we can generate a meaningful
29 Having a catalogue of all the different reasons an error can arise is
30 also useful for other reasons, like cross-referencing FAQs etc, though
31 we are not really taking advantage of this yet.
35 Region inference is particularly tricky because it always succeeds "in
36 the moment" and simply registers a constraint. Then, at the end, we
37 can compute the full graph and report errors, so we need to be able to
38 store and later report what gave rise to the conflicting constraints.
42 Determing whether `T1 <: T2` often involves a number of subtypes and
43 subconstraints along the way. A "TypeTrace" is an extended version
44 of an origin that traces the types and other values that were being
45 compared. It is not necessarily comprehensive (in fact, at the time of
46 this writing it only tracks the root values being compared) but I'd
47 like to extend it to include significant "waypoints". For example, if
48 you are comparing `(T1, T2) <: (T3, T4)`, and the problem is that `T2
49 <: T4` fails, I'd like the trace to include enough information to say
50 "in the 2nd element of the tuple". Similarly, failures when comparing
51 arguments or return types in fn types should be able to cite the
52 specific position, etc.
56 Of course, there is still a LOT of code in typeck that has yet to be
57 ported to this system, and which relies on string concatenation at the
58 time of error detection.
61 use self::FreshOrKept::*;
63 use std::collections::HashSet;
66 use middle::ty::{mod, Ty};
67 use middle::ty::{Region, ReFree};
68 use middle::typeck::infer;
69 use middle::typeck::infer::InferCtxt;
70 use middle::typeck::infer::TypeTrace;
71 use middle::typeck::infer::SubregionOrigin;
72 use middle::typeck::infer::RegionVariableOrigin;
73 use middle::typeck::infer::ValuePairs;
74 use middle::typeck::infer::region_inference::RegionResolutionError;
75 use middle::typeck::infer::region_inference::ConcreteFailure;
76 use middle::typeck::infer::region_inference::SubSupConflict;
77 use middle::typeck::infer::region_inference::SupSupConflict;
78 use middle::typeck::infer::region_inference::ParamBoundFailure;
79 use middle::typeck::infer::region_inference::ProcessedErrors;
80 use middle::typeck::infer::region_inference::SameRegions;
81 use std::cell::{Cell, RefCell};
82 use std::char::from_u32;
84 use std::string::String;
87 use syntax::ast_util::{name_to_dummy_lifetime, PostExpansionMethod};
88 use syntax::owned_slice::OwnedSlice;
90 use syntax::parse::token;
91 use syntax::print::pprust;
93 use util::ppaux::bound_region_to_string;
94 use util::ppaux::note_and_explain_region;
96 // Note: only import UserString, not Repr, since user-facing error
97 // messages shouldn't include debug serializations.
98 use util::ppaux::UserString;
100 pub trait ErrorReporting<'tcx> {
101 fn report_region_errors(&self,
102 errors: &Vec<RegionResolutionError<'tcx>>);
104 fn process_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>)
105 -> Vec<RegionResolutionError<'tcx>>;
107 fn report_type_error(&self, trace: TypeTrace<'tcx>, terr: &ty::type_err<'tcx>);
109 fn report_and_explain_type_error(&self,
110 trace: TypeTrace<'tcx>,
111 terr: &ty::type_err<'tcx>);
113 fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<String>;
115 fn expected_found_str<T: UserString<'tcx> + Resolvable<'tcx>>(
117 exp_found: &ty::expected_found<T>)
120 fn report_concrete_failure(&self,
121 origin: SubregionOrigin<'tcx>,
125 fn report_param_bound_failure(&self,
126 origin: SubregionOrigin<'tcx>,
127 param_ty: ty::ParamTy,
131 fn report_sub_sup_conflict(&self,
132 var_origin: RegionVariableOrigin,
133 sub_origin: SubregionOrigin<'tcx>,
135 sup_origin: SubregionOrigin<'tcx>,
138 fn report_sup_sup_conflict(&self,
139 var_origin: RegionVariableOrigin,
140 origin1: SubregionOrigin<'tcx>,
142 origin2: SubregionOrigin<'tcx>,
145 fn report_processed_errors(&self,
146 var_origin: &[RegionVariableOrigin],
147 trace_origin: &[(TypeTrace<'tcx>, ty::type_err<'tcx>)],
148 same_regions: &[SameRegions]);
150 fn give_suggestion(&self, same_regions: &[SameRegions]);
153 trait ErrorReportingHelpers<'tcx> {
154 fn report_inference_failure(&self,
155 var_origin: RegionVariableOrigin);
157 fn note_region_origin(&self,
158 origin: &SubregionOrigin<'tcx>);
160 fn give_expl_lifetime_param(&self,
162 fn_style: ast::FnStyle,
164 opt_explicit_self: Option<&ast::ExplicitSelf_>,
165 generics: &ast::Generics,
166 span: codemap::Span);
169 impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
170 fn report_region_errors(&self,
171 errors: &Vec<RegionResolutionError<'tcx>>) {
172 let p_errors = self.process_errors(errors);
173 let errors = if p_errors.is_empty() { errors } else { &p_errors };
174 for error in errors.iter() {
175 match error.clone() {
176 ConcreteFailure(origin, sub, sup) => {
177 self.report_concrete_failure(origin, sub, sup);
180 ParamBoundFailure(origin, param_ty, sub, sups) => {
181 self.report_param_bound_failure(origin, param_ty, sub, sups);
184 SubSupConflict(var_origin,
186 sup_origin, sup_r) => {
187 self.report_sub_sup_conflict(var_origin,
192 SupSupConflict(var_origin,
195 self.report_sup_sup_conflict(var_origin,
200 ProcessedErrors(ref var_origins,
202 ref same_regions) => {
203 if !same_regions.is_empty() {
204 self.report_processed_errors(var_origins.as_slice(),
205 trace_origins.as_slice(),
206 same_regions.as_slice());
213 // This method goes through all the errors and try to group certain types
214 // of error together, for the purpose of suggesting explicit lifetime
215 // parameters to the user. This is done so that we can have a more
216 // complete view of what lifetimes should be the same.
217 // If the return value is an empty vector, it means that processing
218 // failed (so the return value of this method should not be used)
219 fn process_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>)
220 -> Vec<RegionResolutionError<'tcx>> {
221 debug!("process_errors()");
222 let mut var_origins = Vec::new();
223 let mut trace_origins = Vec::new();
224 let mut same_regions = Vec::new();
225 let mut processed_errors = Vec::new();
226 for error in errors.iter() {
227 match error.clone() {
228 ConcreteFailure(origin, sub, sup) => {
229 debug!("processing ConcreteFailure")
230 let trace = match origin {
231 infer::Subtype(trace) => Some(trace),
234 match free_regions_from_same_fn(self.tcx, sub, sup) {
235 Some(ref same_frs) if trace.is_some() => {
236 let trace = trace.unwrap();
237 let terr = ty::terr_regions_does_not_outlive(sup,
239 trace_origins.push((trace, terr));
240 append_to_same_regions(&mut same_regions, same_frs);
242 _ => processed_errors.push((*error).clone()),
245 SubSupConflict(var_origin, _, sub_r, _, sup_r) => {
246 debug!("processing SubSupConflict")
247 match free_regions_from_same_fn(self.tcx, sub_r, sup_r) {
248 Some(ref same_frs) => {
249 var_origins.push(var_origin);
250 append_to_same_regions(&mut same_regions, same_frs);
252 None => processed_errors.push((*error).clone()),
255 SupSupConflict(..) => processed_errors.push((*error).clone()),
256 _ => () // This shouldn't happen
259 if !same_regions.is_empty() {
260 let common_scope_id = same_regions[0].scope_id;
261 for sr in same_regions.iter() {
262 // Since ProcessedErrors is used to reconstruct the function
263 // declaration, we want to make sure that they are, in fact,
264 // from the same scope
265 if sr.scope_id != common_scope_id {
266 debug!("returning empty result from process_errors because
267 {} != {}", sr.scope_id, common_scope_id);
271 let pe = ProcessedErrors(var_origins, trace_origins, same_regions);
272 debug!("errors processed: {}", pe);
273 processed_errors.push(pe);
275 return processed_errors;
278 struct FreeRegionsFromSameFn {
279 sub_fr: ty::FreeRegion,
280 sup_fr: ty::FreeRegion,
281 scope_id: ast::NodeId
284 impl FreeRegionsFromSameFn {
285 fn new(sub_fr: ty::FreeRegion,
286 sup_fr: ty::FreeRegion,
287 scope_id: ast::NodeId)
288 -> FreeRegionsFromSameFn {
289 FreeRegionsFromSameFn {
297 fn free_regions_from_same_fn(tcx: &ty::ctxt,
300 -> Option<FreeRegionsFromSameFn> {
301 debug!("free_regions_from_same_fn(sub={}, sup={})", sub, sup);
302 let (scope_id, fr1, fr2) = match (sub, sup) {
303 (ReFree(fr1), ReFree(fr2)) => {
304 if fr1.scope != fr2.scope {
307 assert!(fr1.scope == fr2.scope);
308 (fr1.scope.node_id(), fr1, fr2)
312 let parent = tcx.map.get_parent(scope_id);
313 let parent_node = tcx.map.find(parent);
315 Some(node) => match node {
316 ast_map::NodeItem(item) => match item.node {
318 Some(FreeRegionsFromSameFn::new(fr1, fr2, scope_id))
322 ast_map::NodeImplItem(..) |
323 ast_map::NodeTraitItem(..) => {
324 Some(FreeRegionsFromSameFn::new(fr1, fr2, scope_id))
329 debug!("no parent node of scope_id {}", scope_id)
335 fn append_to_same_regions(same_regions: &mut Vec<SameRegions>,
336 same_frs: &FreeRegionsFromSameFn) {
337 let scope_id = same_frs.scope_id;
338 let (sub_fr, sup_fr) = (same_frs.sub_fr, same_frs.sup_fr);
339 for sr in same_regions.iter_mut() {
340 if sr.contains(&sup_fr.bound_region)
341 && scope_id == sr.scope_id {
342 sr.push(sub_fr.bound_region);
346 same_regions.push(SameRegions {
348 regions: vec!(sub_fr.bound_region, sup_fr.bound_region)
353 fn report_type_error(&self, trace: TypeTrace<'tcx>, terr: &ty::type_err<'tcx>) {
354 let expected_found_str = match self.values_str(&trace.values) {
357 return; /* derived error */
361 let message_root_str = match trace.origin {
362 infer::Misc(_) => "mismatched types",
363 infer::MethodCompatCheck(_) => "method not compatible with trait",
364 infer::ExprAssignable(_) => "mismatched types",
365 infer::RelateTraitRefs(_) => "mismatched traits",
366 infer::RelateSelfType(_) => "mismatched types",
367 infer::RelateOutputImplTypes(_) => "mismatched types",
368 infer::MatchExpressionArm(_, _) => "match arms have incompatible types",
369 infer::IfExpression(_) => "if and else have incompatible types",
370 infer::IfExpressionWithNoElse(_) => "if may be missing an else clause",
373 self.tcx.sess.span_err(
375 format!("{}: {} ({})",
378 ty::type_err_to_str(self.tcx, terr)).as_slice());
381 infer::MatchExpressionArm(_, arm_span) =>
382 self.tcx.sess.span_note(arm_span, "match arm with an incompatible type"),
387 fn report_and_explain_type_error(&self,
388 trace: TypeTrace<'tcx>,
389 terr: &ty::type_err<'tcx>) {
390 self.report_type_error(trace, terr);
391 ty::note_and_explain_type_err(self.tcx, terr);
394 fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<String> {
396 * Returns a string of the form "expected `{}`, found `{}`",
397 * or None if this is a derived error.
400 infer::Types(ref exp_found) => self.expected_found_str(exp_found),
401 infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found)
405 fn expected_found_str<T: UserString<'tcx> + Resolvable<'tcx>>(
407 exp_found: &ty::expected_found<T>)
410 let expected = exp_found.expected.resolve(self);
411 if expected.contains_error() {
415 let found = exp_found.found.resolve(self);
416 if found.contains_error() {
420 Some(format!("expected `{}`, found `{}`",
421 expected.user_string(self.tcx),
422 found.user_string(self.tcx)))
425 fn report_param_bound_failure(&self,
426 origin: SubregionOrigin<'tcx>,
427 param_ty: ty::ParamTy,
429 _sups: Vec<Region>) {
431 // FIXME: it would be better to report the first error message
432 // with the span of the parameter itself, rather than the span
433 // where the error was detected. But that span is not readily
437 ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
438 // Does the required lifetime have a nice name we can print?
439 self.tcx.sess.span_err(
442 "the parameter type `{}` may not live long enough",
443 param_ty.user_string(self.tcx)).as_slice());
444 self.tcx.sess.span_help(
447 "consider adding an explicit lifetime bound `{}: {}`...",
448 param_ty.user_string(self.tcx),
449 sub.user_string(self.tcx)).as_slice());
453 // Does the required lifetime have a nice name we can print?
454 self.tcx.sess.span_err(
457 "the parameter type `{}` may not live long enough",
458 param_ty.user_string(self.tcx)).as_slice());
459 self.tcx.sess.span_help(
462 "consider adding an explicit lifetime bound `{}: 'static`...",
463 param_ty.user_string(self.tcx)).as_slice());
467 // If not, be less specific.
468 self.tcx.sess.span_err(
471 "the parameter type `{}` may not live long enough",
472 param_ty.user_string(self.tcx)).as_slice());
473 self.tcx.sess.span_help(
476 "consider adding an explicit lifetime bound to `{}`",
477 param_ty.user_string(self.tcx)).as_slice());
478 note_and_explain_region(
480 format!("the parameter type `{}` must be valid for ",
481 param_ty.user_string(self.tcx)).as_slice(),
487 self.note_region_origin(&origin);
490 fn report_concrete_failure(&self,
491 origin: SubregionOrigin<'tcx>,
495 infer::Subtype(trace) => {
496 let terr = ty::terr_regions_does_not_outlive(sup, sub);
497 self.report_and_explain_type_error(trace, &terr);
499 infer::Reborrow(span) => {
500 self.tcx.sess.span_err(
502 "lifetime of reference outlines \
503 lifetime of borrowed content...");
504 note_and_explain_region(
506 "...the reference is valid for ",
509 note_and_explain_region(
511 "...but the borrowed content is only valid for ",
515 infer::ReborrowUpvar(span, ref upvar_id) => {
516 self.tcx.sess.span_err(
518 format!("lifetime of borrowed pointer outlives \
519 lifetime of captured variable `{}`...",
520 ty::local_var_name_str(self.tcx,
523 .to_string()).as_slice());
524 note_and_explain_region(
526 "...the borrowed pointer is valid for ",
529 note_and_explain_region(
531 format!("...but `{}` is only valid for ",
532 ty::local_var_name_str(self.tcx,
535 .to_string()).as_slice(),
539 infer::InfStackClosure(span) => {
540 self.tcx.sess.span_err(
542 "closure outlives stack frame");
543 note_and_explain_region(
545 "...the closure must be valid for ",
548 note_and_explain_region(
550 "...but the closure's stack frame is only valid for ",
554 infer::InvokeClosure(span) => {
555 self.tcx.sess.span_err(
557 "cannot invoke closure outside of its lifetime");
558 note_and_explain_region(
560 "the closure is only valid for ",
564 infer::DerefPointer(span) => {
565 self.tcx.sess.span_err(
567 "dereference of reference outside its lifetime");
568 note_and_explain_region(
570 "the reference is only valid for ",
574 infer::FreeVariable(span, id) => {
575 self.tcx.sess.span_err(
577 format!("captured variable `{}` does not \
578 outlive the enclosing closure",
579 ty::local_var_name_str(self.tcx,
581 .to_string()).as_slice());
582 note_and_explain_region(
584 "captured variable is valid for ",
587 note_and_explain_region(
589 "closure is valid for ",
593 infer::ProcCapture(span, id) => {
594 self.tcx.sess.span_err(
596 format!("captured variable `{}` must be 'static \
597 to be captured in a proc",
598 ty::local_var_name_str(self.tcx, id).get())
600 note_and_explain_region(
602 "captured variable is only valid for ",
606 infer::IndexSlice(span) => {
607 self.tcx.sess.span_err(span,
608 "index of slice outside its lifetime");
609 note_and_explain_region(
611 "the slice is only valid for ",
615 infer::RelateObjectBound(span) => {
616 self.tcx.sess.span_err(
618 "lifetime of the source pointer does not outlive \
619 lifetime bound of the object type");
620 note_and_explain_region(
622 "object type is valid for ",
625 note_and_explain_region(
627 "source pointer is only valid for ",
631 infer::RelateProcBound(span, var_node_id, ty) => {
632 self.tcx.sess.span_err(
635 "the type `{}` of captured variable `{}` \
636 outlives the `proc()` it \
638 self.ty_to_string(ty),
639 ty::local_var_name_str(self.tcx,
640 var_node_id)).as_slice());
641 note_and_explain_region(
643 "`proc()` is valid for ",
646 note_and_explain_region(
648 format!("the type `{}` is only valid for ",
649 self.ty_to_string(ty)).as_slice(),
653 infer::RelateParamBound(span, ty) => {
654 self.tcx.sess.span_err(
656 format!("the type `{}` does not fulfill the \
658 self.ty_to_string(ty)).as_slice());
659 note_and_explain_region(self.tcx,
660 "type must outlive ",
664 infer::RelateRegionParamBound(span) => {
665 self.tcx.sess.span_err(
667 "declared lifetime bound not satisfied");
668 note_and_explain_region(
670 "lifetime parameter instantiated with ",
673 note_and_explain_region(
675 "but lifetime parameter must outlive ",
679 infer::RelateDefaultParamBound(span, ty) => {
680 self.tcx.sess.span_err(
682 format!("the type `{}` (provided as the value of \
683 a type parameter) is not valid at this point",
684 self.ty_to_string(ty)).as_slice());
685 note_and_explain_region(self.tcx,
686 "type must outlive ",
690 infer::CallRcvr(span) => {
691 self.tcx.sess.span_err(
693 "lifetime of method receiver does not outlive \
695 note_and_explain_region(
697 "the receiver is only valid for ",
701 infer::CallArg(span) => {
702 self.tcx.sess.span_err(
704 "lifetime of function argument does not outlive \
706 note_and_explain_region(
708 "the function argument is only valid for ",
712 infer::CallReturn(span) => {
713 self.tcx.sess.span_err(
715 "lifetime of return value does not outlive \
717 note_and_explain_region(
719 "the return value is only valid for ",
723 infer::AddrOf(span) => {
724 self.tcx.sess.span_err(
726 "reference is not valid \
727 at the time of borrow");
728 note_and_explain_region(
730 "the borrow is only valid for ",
734 infer::AutoBorrow(span) => {
735 self.tcx.sess.span_err(
737 "automatically reference is not valid \
738 at the time of borrow");
739 note_and_explain_region(
741 "the automatic borrow is only valid for ",
745 infer::ExprTypeIsNotInScope(t, span) => {
746 self.tcx.sess.span_err(
748 format!("type of expression contains references \
749 that are not valid during the expression: `{}`",
750 self.ty_to_string(t)).as_slice());
751 note_and_explain_region(
753 "type is only valid for ",
757 infer::BindingTypeIsNotValidAtDecl(span) => {
758 self.tcx.sess.span_err(
760 "lifetime of variable does not enclose its declaration");
761 note_and_explain_region(
763 "the variable is only valid for ",
767 infer::ReferenceOutlivesReferent(ty, span) => {
768 self.tcx.sess.span_err(
770 format!("in type `{}`, reference has a longer lifetime \
771 than the data it references",
772 self.ty_to_string(ty)).as_slice());
773 note_and_explain_region(
775 "the pointer is valid for ",
778 note_and_explain_region(
780 "but the referenced data is only valid for ",
787 fn report_sub_sup_conflict(&self,
788 var_origin: RegionVariableOrigin,
789 sub_origin: SubregionOrigin<'tcx>,
791 sup_origin: SubregionOrigin<'tcx>,
792 sup_region: Region) {
793 self.report_inference_failure(var_origin);
795 note_and_explain_region(
797 "first, the lifetime cannot outlive ",
801 self.note_region_origin(&sup_origin);
803 note_and_explain_region(
805 "but, the lifetime must be valid for ",
809 self.note_region_origin(&sub_origin);
812 fn report_sup_sup_conflict(&self,
813 var_origin: RegionVariableOrigin,
814 origin1: SubregionOrigin<'tcx>,
816 origin2: SubregionOrigin<'tcx>,
818 self.report_inference_failure(var_origin);
820 note_and_explain_region(
822 "first, the lifetime must be contained by ",
826 self.note_region_origin(&origin1);
828 note_and_explain_region(
830 "but, the lifetime must also be contained by ",
834 self.note_region_origin(&origin2);
837 fn report_processed_errors(&self,
838 var_origins: &[RegionVariableOrigin],
839 trace_origins: &[(TypeTrace<'tcx>, ty::type_err<'tcx>)],
840 same_regions: &[SameRegions]) {
841 for vo in var_origins.iter() {
842 self.report_inference_failure(vo.clone());
844 self.give_suggestion(same_regions);
845 for &(ref trace, terr) in trace_origins.iter() {
846 self.report_type_error(trace.clone(), &terr);
850 fn give_suggestion(&self, same_regions: &[SameRegions]) {
851 let scope_id = same_regions[0].scope_id;
852 let parent = self.tcx.map.get_parent(scope_id);
853 let parent_node = self.tcx.map.find(parent);
854 let node_inner = match parent_node {
855 Some(ref node) => match *node {
856 ast_map::NodeItem(ref item) => {
858 ast::ItemFn(ref fn_decl, pur, _, ref gen, _) => {
859 Some((&**fn_decl, gen, pur, item.ident, None, item.span))
864 ast_map::NodeImplItem(ref item) => {
866 ast::MethodImplItem(ref m) => {
867 Some((m.pe_fn_decl(),
871 Some(&m.pe_explicit_self().node),
874 ast::TypeImplItem(_) => None,
877 ast_map::NodeTraitItem(ref item) => {
879 ast::ProvidedMethod(ref m) => {
880 Some((m.pe_fn_decl(),
884 Some(&m.pe_explicit_self().node),
894 let (fn_decl, generics, fn_style, ident, expl_self, span)
895 = node_inner.expect("expect item fn");
896 let taken = lifetimes_in_scope(self.tcx, scope_id);
897 let life_giver = LifeGiver::with_taken(taken.as_slice());
898 let rebuilder = Rebuilder::new(self.tcx, fn_decl, expl_self,
899 generics, same_regions, &life_giver);
900 let (fn_decl, expl_self, generics) = rebuilder.rebuild();
901 self.give_expl_lifetime_param(&fn_decl, fn_style, ident,
902 expl_self.as_ref(), &generics, span);
906 struct RebuildPathInfo<'a> {
908 // indexes to insert lifetime on path.lifetimes
910 // number of lifetimes we expect to see on the type referred by `path`
911 // (e.g., expected=1 for struct Foo<'a>)
913 anon_nums: &'a HashSet<uint>,
914 region_names: &'a HashSet<ast::Name>
917 struct Rebuilder<'a, 'tcx: 'a> {
918 tcx: &'a ty::ctxt<'tcx>,
919 fn_decl: &'a ast::FnDecl,
920 expl_self_opt: Option<&'a ast::ExplicitSelf_>,
921 generics: &'a ast::Generics,
922 same_regions: &'a [SameRegions],
923 life_giver: &'a LifeGiver,
924 cur_anon: Cell<uint>,
925 inserted_anons: RefCell<HashSet<uint>>,
933 impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
934 fn new(tcx: &'a ty::ctxt<'tcx>,
935 fn_decl: &'a ast::FnDecl,
936 expl_self_opt: Option<&'a ast::ExplicitSelf_>,
937 generics: &'a ast::Generics,
938 same_regions: &'a [SameRegions],
939 life_giver: &'a LifeGiver)
940 -> Rebuilder<'a, 'tcx> {
944 expl_self_opt: expl_self_opt,
946 same_regions: same_regions,
947 life_giver: life_giver,
948 cur_anon: Cell::new(0),
949 inserted_anons: RefCell::new(HashSet::new()),
954 -> (ast::FnDecl, Option<ast::ExplicitSelf_>, ast::Generics) {
955 let mut expl_self_opt = self.expl_self_opt.map(|x| x.clone());
956 let mut inputs = self.fn_decl.inputs.clone();
957 let mut output = self.fn_decl.output.clone();
958 let mut ty_params = self.generics.ty_params.clone();
959 let where_clause = self.generics.where_clause.clone();
960 let mut kept_lifetimes = HashSet::new();
961 for sr in self.same_regions.iter() {
962 self.cur_anon.set(0);
963 self.offset_cur_anon();
964 let (anon_nums, region_names) =
965 self.extract_anon_nums_and_names(sr);
966 let (lifetime, fresh_or_kept) = self.pick_lifetime(®ion_names);
967 match fresh_or_kept {
968 Kept => { kept_lifetimes.insert(lifetime.name); }
971 expl_self_opt = self.rebuild_expl_self(expl_self_opt, lifetime,
972 &anon_nums, ®ion_names);
973 inputs = self.rebuild_args_ty(inputs.as_slice(), lifetime,
974 &anon_nums, ®ion_names);
975 output = self.rebuild_output(&output, lifetime, &anon_nums, ®ion_names);
976 ty_params = self.rebuild_ty_params(ty_params, lifetime,
979 let fresh_lifetimes = self.life_giver.get_generated_lifetimes();
980 let all_region_names = self.extract_all_region_names();
981 let generics = self.rebuild_generics(self.generics,
987 let new_fn_decl = ast::FnDecl {
990 variadic: self.fn_decl.variadic
992 (new_fn_decl, expl_self_opt, generics)
995 fn pick_lifetime(&self,
996 region_names: &HashSet<ast::Name>)
997 -> (ast::Lifetime, FreshOrKept) {
998 if region_names.len() > 0 {
999 // It's not necessary to convert the set of region names to a
1000 // vector of string and then sort them. However, it makes the
1001 // choice of lifetime name deterministic and thus easier to test.
1002 let mut names = Vec::new();
1003 for rn in region_names.iter() {
1004 let lt_name = token::get_name(*rn).get().to_string();
1005 names.push(lt_name);
1008 let name = token::str_to_ident(names[0].as_slice()).name;
1009 return (name_to_dummy_lifetime(name), Kept);
1011 return (self.life_giver.give_lifetime(), Fresh);
1014 fn extract_anon_nums_and_names(&self, same_regions: &SameRegions)
1015 -> (HashSet<uint>, HashSet<ast::Name>) {
1016 let mut anon_nums = HashSet::new();
1017 let mut region_names = HashSet::new();
1018 for br in same_regions.regions.iter() {
1021 anon_nums.insert(i);
1023 ty::BrNamed(_, name) => {
1024 region_names.insert(name);
1029 (anon_nums, region_names)
1032 fn extract_all_region_names(&self) -> HashSet<ast::Name> {
1033 let mut all_region_names = HashSet::new();
1034 for sr in self.same_regions.iter() {
1035 for br in sr.regions.iter() {
1037 ty::BrNamed(_, name) => {
1038 all_region_names.insert(name);
1047 fn inc_cur_anon(&self, n: uint) {
1048 let anon = self.cur_anon.get();
1049 self.cur_anon.set(anon+n);
1052 fn offset_cur_anon(&self) {
1053 let mut anon = self.cur_anon.get();
1054 while self.inserted_anons.borrow().contains(&anon) {
1057 self.cur_anon.set(anon);
1060 fn inc_and_offset_cur_anon(&self, n: uint) {
1061 self.inc_cur_anon(n);
1062 self.offset_cur_anon();
1065 fn track_anon(&self, anon: uint) {
1066 self.inserted_anons.borrow_mut().insert(anon);
1069 fn rebuild_ty_params(&self,
1070 ty_params: OwnedSlice<ast::TyParam>,
1071 lifetime: ast::Lifetime,
1072 region_names: &HashSet<ast::Name>)
1073 -> OwnedSlice<ast::TyParam> {
1074 ty_params.map(|ty_param| {
1075 let bounds = self.rebuild_ty_param_bounds(ty_param.bounds.clone(),
1079 ident: ty_param.ident,
1082 unbound: ty_param.unbound.clone(),
1083 default: ty_param.default.clone(),
1084 span: ty_param.span,
1089 fn rebuild_ty_param_bounds(&self,
1090 ty_param_bounds: OwnedSlice<ast::TyParamBound>,
1091 lifetime: ast::Lifetime,
1092 region_names: &HashSet<ast::Name>)
1093 -> OwnedSlice<ast::TyParamBound> {
1094 ty_param_bounds.map(|tpb| {
1096 &ast::RegionTyParamBound(lt) => {
1097 // FIXME -- it's unclear whether I'm supposed to
1098 // substitute lifetime here. I suspect we need to
1099 // be passing down a map.
1100 ast::RegionTyParamBound(lt)
1102 &ast::TraitTyParamBound(ref poly_tr) => {
1103 let tr = &poly_tr.trait_ref;
1104 let last_seg = tr.path.segments.last().unwrap();
1105 let mut insert = Vec::new();
1106 let lifetimes = last_seg.parameters.lifetimes();
1107 for (i, lt) in lifetimes.iter().enumerate() {
1108 if region_names.contains(<.name) {
1112 let rebuild_info = RebuildPathInfo {
1115 expected: lifetimes.len(),
1116 anon_nums: &HashSet::new(),
1117 region_names: region_names
1119 let new_path = self.rebuild_path(rebuild_info, lifetime);
1120 ast::TraitTyParamBound(ast::PolyTraitRef {
1121 bound_lifetimes: poly_tr.bound_lifetimes.clone(),
1122 trait_ref: ast::TraitRef {
1132 fn rebuild_expl_self(&self,
1133 expl_self_opt: Option<ast::ExplicitSelf_>,
1134 lifetime: ast::Lifetime,
1135 anon_nums: &HashSet<uint>,
1136 region_names: &HashSet<ast::Name>)
1137 -> Option<ast::ExplicitSelf_> {
1138 match expl_self_opt {
1139 Some(ref expl_self) => match *expl_self {
1140 ast::SelfRegion(lt_opt, muta, id) => match lt_opt {
1141 Some(lt) => if region_names.contains(<.name) {
1142 return Some(ast::SelfRegion(Some(lifetime), muta, id));
1145 let anon = self.cur_anon.get();
1146 self.inc_and_offset_cur_anon(1);
1147 if anon_nums.contains(&anon) {
1148 self.track_anon(anon);
1149 return Some(ast::SelfRegion(Some(lifetime), muta, id));
1160 fn rebuild_generics(&self,
1161 generics: &ast::Generics,
1162 add: &Vec<ast::Lifetime>,
1163 keep: &HashSet<ast::Name>,
1164 remove: &HashSet<ast::Name>,
1165 ty_params: OwnedSlice<ast::TyParam>,
1166 where_clause: ast::WhereClause)
1168 let mut lifetimes = Vec::new();
1169 for lt in add.iter() {
1170 lifetimes.push(ast::LifetimeDef { lifetime: *lt,
1171 bounds: Vec::new() });
1173 for lt in generics.lifetimes.iter() {
1174 if keep.contains(<.lifetime.name) ||
1175 !remove.contains(<.lifetime.name) {
1176 lifetimes.push((*lt).clone());
1180 lifetimes: lifetimes,
1181 ty_params: ty_params,
1182 where_clause: where_clause,
1186 fn rebuild_args_ty(&self,
1187 inputs: &[ast::Arg],
1188 lifetime: ast::Lifetime,
1189 anon_nums: &HashSet<uint>,
1190 region_names: &HashSet<ast::Name>)
1192 let mut new_inputs = Vec::new();
1193 for arg in inputs.iter() {
1194 let new_ty = self.rebuild_arg_ty_or_output(&*arg.ty, lifetime,
1195 anon_nums, region_names);
1196 let possibly_new_arg = ast::Arg {
1198 pat: arg.pat.clone(),
1201 new_inputs.push(possibly_new_arg);
1206 fn rebuild_output(&self, ty: &ast::FunctionRetTy,
1207 lifetime: ast::Lifetime,
1208 anon_nums: &HashSet<uint>,
1209 region_names: &HashSet<ast::Name>) -> ast::FunctionRetTy {
1211 ast::Return(ref ret_ty) => ast::Return(
1212 self.rebuild_arg_ty_or_output(&**ret_ty, lifetime, anon_nums, region_names)
1214 ast::NoReturn(span) => ast::NoReturn(span)
1218 fn rebuild_arg_ty_or_output(&self,
1220 lifetime: ast::Lifetime,
1221 anon_nums: &HashSet<uint>,
1222 region_names: &HashSet<ast::Name>)
1224 let mut new_ty = P(ty.clone());
1225 let mut ty_queue = vec!(ty);
1226 while !ty_queue.is_empty() {
1227 let cur_ty = ty_queue.remove(0).unwrap();
1229 ast::TyRptr(lt_opt, ref mut_ty) => {
1230 let rebuild = match lt_opt {
1231 Some(lt) => region_names.contains(<.name),
1233 let anon = self.cur_anon.get();
1234 let rebuild = anon_nums.contains(&anon);
1236 self.track_anon(anon);
1238 self.inc_and_offset_cur_anon(1);
1245 node: ast::TyRptr(Some(lifetime), mut_ty.clone()),
1248 new_ty = self.rebuild_ty(new_ty, P(to));
1250 ty_queue.push(&*mut_ty.ty);
1252 ast::TyPath(ref path, ref bounds, id) => {
1253 let a_def = match self.tcx.def_map.borrow().get(&id) {
1259 pprust::path_to_string(path)).as_slice())
1264 def::DefTy(did, _) | def::DefStruct(did) => {
1265 let generics = ty::lookup_item_type(self.tcx, did).generics;
1268 generics.regions.len(subst::TypeSpace);
1270 path.segments.last().unwrap().parameters.lifetimes();
1271 let mut insert = Vec::new();
1272 if lifetimes.len() == 0 {
1273 let anon = self.cur_anon.get();
1274 for (i, a) in range(anon,
1275 anon+expected).enumerate() {
1276 if anon_nums.contains(&a) {
1281 self.inc_and_offset_cur_anon(expected);
1283 for (i, lt) in lifetimes.iter().enumerate() {
1284 if region_names.contains(<.name) {
1289 let rebuild_info = RebuildPathInfo {
1293 anon_nums: anon_nums,
1294 region_names: region_names
1296 let new_path = self.rebuild_path(rebuild_info, lifetime);
1299 node: ast::TyPath(new_path, bounds.clone(), id),
1302 new_ty = self.rebuild_ty(new_ty, P(to));
1309 ast::TyPtr(ref mut_ty) => {
1310 ty_queue.push(&*mut_ty.ty);
1312 ast::TyVec(ref ty) |
1313 ast::TyFixedLengthVec(ref ty, _) => {
1314 ty_queue.push(&**ty);
1316 ast::TyTup(ref tys) => ty_queue.extend(tys.iter().map(|ty| &**ty)),
1323 fn rebuild_ty(&self,
1328 fn build_to(from: P<ast::Ty>,
1329 to: &mut Option<P<ast::Ty>>)
1331 if Some(from.id) == to.as_ref().map(|ty| ty.id) {
1332 return to.take().expect("`to` type found more than once during rebuild");
1334 from.map(|ast::Ty {id, node, span}| {
1335 let new_node = match node {
1336 ast::TyRptr(lifetime, mut_ty) => {
1337 ast::TyRptr(lifetime, ast::MutTy {
1338 mutbl: mut_ty.mutbl,
1339 ty: build_to(mut_ty.ty, to),
1342 ast::TyPtr(mut_ty) => {
1343 ast::TyPtr(ast::MutTy {
1344 mutbl: mut_ty.mutbl,
1345 ty: build_to(mut_ty.ty, to),
1348 ast::TyVec(ty) => ast::TyVec(build_to(ty, to)),
1349 ast::TyFixedLengthVec(ty, e) => {
1350 ast::TyFixedLengthVec(build_to(ty, to), e)
1352 ast::TyTup(tys) => {
1353 ast::TyTup(tys.into_iter().map(|ty| build_to(ty, to)).collect())
1355 ast::TyParen(typ) => ast::TyParen(build_to(typ, to)),
1358 ast::Ty { id: id, node: new_node, span: span }
1362 build_to(from, &mut Some(to))
1365 fn rebuild_path(&self,
1366 rebuild_info: RebuildPathInfo,
1367 lifetime: ast::Lifetime)
1370 let RebuildPathInfo {
1378 let last_seg = path.segments.last().unwrap();
1379 let new_parameters = match last_seg.parameters {
1380 ast::ParenthesizedParameters(..) => {
1381 last_seg.parameters.clone()
1384 ast::AngleBracketedParameters(ref data) => {
1385 let mut new_lts = Vec::new();
1386 if data.lifetimes.len() == 0 {
1387 // traverse once to see if there's a need to insert lifetime
1388 let need_insert = range(0, expected).any(|i| {
1389 indexes.contains(&i)
1392 for i in range(0, expected) {
1393 if indexes.contains(&i) {
1394 new_lts.push(lifetime);
1396 new_lts.push(self.life_giver.give_lifetime());
1401 for (i, lt) in data.lifetimes.iter().enumerate() {
1402 if indexes.contains(&i) {
1403 new_lts.push(lifetime);
1409 let new_types = data.types.map(|t| {
1410 self.rebuild_arg_ty_or_output(&**t, lifetime, anon_nums, region_names)
1412 ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
1418 let new_seg = ast::PathSegment {
1419 identifier: last_seg.identifier,
1420 parameters: new_parameters
1422 let mut new_segs = Vec::new();
1423 new_segs.push_all(path.segments.init());
1424 new_segs.push(new_seg);
1427 global: path.global,
1433 impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
1434 fn give_expl_lifetime_param(&self,
1436 fn_style: ast::FnStyle,
1438 opt_explicit_self: Option<&ast::ExplicitSelf_>,
1439 generics: &ast::Generics,
1440 span: codemap::Span) {
1441 let suggested_fn = pprust::fun_to_string(decl, fn_style, ident,
1442 opt_explicit_self, generics);
1443 let msg = format!("consider using an explicit lifetime \
1444 parameter as shown: {}", suggested_fn);
1445 self.tcx.sess.span_help(span, msg.as_slice());
1448 fn report_inference_failure(&self,
1449 var_origin: RegionVariableOrigin) {
1450 let var_description = match var_origin {
1451 infer::MiscVariable(_) => "".to_string(),
1452 infer::PatternRegion(_) => " for pattern".to_string(),
1453 infer::AddrOfRegion(_) => " for borrow expression".to_string(),
1454 infer::AddrOfSlice(_) => " for slice expression".to_string(),
1455 infer::Autoref(_) => " for autoref".to_string(),
1456 infer::Coercion(_) => " for automatic coercion".to_string(),
1457 infer::LateBoundRegion(_, br, infer::FnCall) => {
1458 format!(" for {}in function call",
1459 bound_region_to_string(self.tcx, "lifetime parameter ", true, br))
1461 infer::LateBoundRegion(_, br, infer::HigherRankedType) => {
1462 format!(" for {}in generic type",
1463 bound_region_to_string(self.tcx, "lifetime parameter ", true, br))
1465 infer::EarlyBoundRegion(_, name) => {
1466 format!(" for lifetime parameter `{}`",
1467 token::get_name(name).get())
1469 infer::BoundRegionInCoherence(name) => {
1470 format!(" for lifetime parameter `{}` in coherence check",
1471 token::get_name(name).get())
1473 infer::UpvarRegion(ref upvar_id, _) => {
1474 format!(" for capture of `{}` by closure",
1475 ty::local_var_name_str(self.tcx, upvar_id.var_id).get().to_string())
1479 self.tcx.sess.span_err(
1481 format!("cannot infer an appropriate lifetime{} \
1482 due to conflicting requirements",
1483 var_description).as_slice());
1486 fn note_region_origin(&self, origin: &SubregionOrigin<'tcx>) {
1488 infer::Subtype(ref trace) => {
1489 let desc = match trace.origin {
1491 format!("types are compatible")
1493 infer::MethodCompatCheck(_) => {
1494 format!("method type is compatible with trait")
1496 infer::ExprAssignable(_) => {
1497 format!("expression is assignable")
1499 infer::RelateTraitRefs(_) => {
1500 format!("traits are compatible")
1502 infer::RelateSelfType(_) => {
1503 format!("self type matches impl self type")
1505 infer::RelateOutputImplTypes(_) => {
1506 format!("trait type parameters matches those \
1507 specified on the impl")
1509 infer::MatchExpressionArm(_, _) => {
1510 format!("match arms have compatible types")
1512 infer::IfExpression(_) => {
1513 format!("if and else have compatible types")
1515 infer::IfExpressionWithNoElse(_) => {
1516 format!("if may be missing an else clause")
1520 match self.values_str(&trace.values) {
1521 Some(values_str) => {
1522 self.tcx.sess.span_note(
1523 trace.origin.span(),
1524 format!("...so that {} ({})",
1525 desc, values_str).as_slice());
1528 // Really should avoid printing this error at
1529 // all, since it is derived, but that would
1530 // require more refactoring than I feel like
1531 // doing right now. - nmatsakis
1532 self.tcx.sess.span_note(
1533 trace.origin.span(),
1534 format!("...so that {}", desc).as_slice());
1538 infer::Reborrow(span) => {
1539 self.tcx.sess.span_note(
1541 "...so that reference does not outlive \
1544 infer::ReborrowUpvar(span, ref upvar_id) => {
1545 self.tcx.sess.span_note(
1548 "...so that closure can access `{}`",
1549 ty::local_var_name_str(self.tcx, upvar_id.var_id)
1551 .to_string()).as_slice())
1553 infer::InfStackClosure(span) => {
1554 self.tcx.sess.span_note(
1556 "...so that closure does not outlive its stack frame");
1558 infer::InvokeClosure(span) => {
1559 self.tcx.sess.span_note(
1561 "...so that closure is not invoked outside its lifetime");
1563 infer::DerefPointer(span) => {
1564 self.tcx.sess.span_note(
1566 "...so that pointer is not dereferenced \
1567 outside its lifetime");
1569 infer::FreeVariable(span, id) => {
1570 self.tcx.sess.span_note(
1572 format!("...so that captured variable `{}` \
1573 does not outlive the enclosing closure",
1574 ty::local_var_name_str(
1576 id).get().to_string()).as_slice());
1578 infer::ProcCapture(span, id) => {
1579 self.tcx.sess.span_note(
1581 format!("...so that captured variable `{}` \
1583 ty::local_var_name_str(
1585 id).get()).as_slice());
1587 infer::IndexSlice(span) => {
1588 self.tcx.sess.span_note(
1590 "...so that slice is not indexed outside the lifetime");
1592 infer::RelateObjectBound(span) => {
1593 self.tcx.sess.span_note(
1595 "...so that it can be closed over into an object");
1597 infer::RelateProcBound(span, var_node_id, _ty) => {
1598 self.tcx.sess.span_note(
1601 "...so that the variable `{}` can be captured \
1603 ty::local_var_name_str(self.tcx,
1604 var_node_id)).as_slice());
1606 infer::CallRcvr(span) => {
1607 self.tcx.sess.span_note(
1609 "...so that method receiver is valid for the method call");
1611 infer::CallArg(span) => {
1612 self.tcx.sess.span_note(
1614 "...so that argument is valid for the call");
1616 infer::CallReturn(span) => {
1617 self.tcx.sess.span_note(
1619 "...so that return value is valid for the call");
1621 infer::AddrOf(span) => {
1622 self.tcx.sess.span_note(
1624 "...so that reference is valid \
1625 at the time of borrow");
1627 infer::AutoBorrow(span) => {
1628 self.tcx.sess.span_note(
1630 "...so that auto-reference is valid \
1631 at the time of borrow");
1633 infer::ExprTypeIsNotInScope(t, span) => {
1634 self.tcx.sess.span_note(
1636 format!("...so type `{}` of expression is valid during the \
1638 self.ty_to_string(t)).as_slice());
1640 infer::BindingTypeIsNotValidAtDecl(span) => {
1641 self.tcx.sess.span_note(
1643 "...so that variable is valid at time of its declaration");
1645 infer::ReferenceOutlivesReferent(ty, span) => {
1646 self.tcx.sess.span_note(
1648 format!("...so that the reference type `{}` \
1649 does not outlive the data it points at",
1650 self.ty_to_string(ty)).as_slice());
1652 infer::RelateParamBound(span, t) => {
1653 self.tcx.sess.span_note(
1655 format!("...so that the type `{}` \
1656 will meet the declared lifetime bounds.",
1657 self.ty_to_string(t)).as_slice());
1659 infer::RelateDefaultParamBound(span, t) => {
1660 self.tcx.sess.span_note(
1662 format!("...so that type parameter \
1663 instantiated with `{}`, \
1664 will meet its declared lifetime bounds.",
1665 self.ty_to_string(t)).as_slice());
1667 infer::RelateRegionParamBound(span) => {
1668 self.tcx.sess.span_note(
1670 format!("...so that the declared lifetime parameter bounds \
1671 are satisfied").as_slice());
1677 pub trait Resolvable<'tcx> {
1678 fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Self;
1679 fn contains_error(&self) -> bool;
1682 impl<'tcx> Resolvable<'tcx> for Ty<'tcx> {
1683 fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Ty<'tcx> {
1684 infcx.resolve_type_vars_if_possible(*self)
1686 fn contains_error(&self) -> bool {
1687 ty::type_is_error(*self)
1691 impl<'tcx> Resolvable<'tcx> for Rc<ty::TraitRef<'tcx>> {
1692 fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>)
1693 -> Rc<ty::TraitRef<'tcx>> {
1694 Rc::new(infcx.resolve_type_vars_in_trait_ref_if_possible(&**self))
1696 fn contains_error(&self) -> bool {
1697 ty::trait_ref_contains_error(&**self)
1701 fn lifetimes_in_scope(tcx: &ty::ctxt,
1702 scope_id: ast::NodeId)
1703 -> Vec<ast::LifetimeDef> {
1704 let mut taken = Vec::new();
1705 let parent = tcx.map.get_parent(scope_id);
1706 let method_id_opt = match tcx.map.find(parent) {
1707 Some(node) => match node {
1708 ast_map::NodeItem(item) => match item.node {
1709 ast::ItemFn(_, _, _, ref gen, _) => {
1710 taken.push_all(gen.lifetimes.as_slice());
1715 ast_map::NodeImplItem(ii) => {
1717 ast::MethodImplItem(ref m) => {
1718 taken.push_all(m.pe_generics().lifetimes.as_slice());
1721 ast::TypeImplItem(_) => None,
1728 if method_id_opt.is_some() {
1729 let method_id = method_id_opt.unwrap();
1730 let parent = tcx.map.get_parent(method_id);
1731 match tcx.map.find(parent) {
1732 Some(node) => match node {
1733 ast_map::NodeItem(item) => match item.node {
1734 ast::ItemImpl(ref gen, _, _, _) => {
1735 taken.push_all(gen.lifetimes.as_slice());
1747 // LifeGiver is responsible for generating fresh lifetime names
1749 taken: HashSet<String>,
1750 counter: Cell<uint>,
1751 generated: RefCell<Vec<ast::Lifetime>>,
1755 fn with_taken(taken: &[ast::LifetimeDef]) -> LifeGiver {
1756 let mut taken_ = HashSet::new();
1757 for lt in taken.iter() {
1758 let lt_name = token::get_name(lt.lifetime.name).get().to_string();
1759 taken_.insert(lt_name);
1763 counter: Cell::new(0),
1764 generated: RefCell::new(Vec::new()),
1768 fn inc_counter(&self) {
1769 let c = self.counter.get();
1770 self.counter.set(c+1);
1773 fn give_lifetime(&self) -> ast::Lifetime {
1776 let mut s = String::from_str("'");
1777 s.push_str(num_to_string(self.counter.get()).as_slice());
1778 if !self.taken.contains(&s) {
1779 lifetime = name_to_dummy_lifetime(
1780 token::str_to_ident(s.as_slice()).name);
1781 self.generated.borrow_mut().push(lifetime);
1789 // 0 .. 25 generates a .. z, 26 .. 51 generates aa .. zz, and so on
1790 fn num_to_string(counter: uint) -> String {
1791 let mut s = String::new();
1792 let (n, r) = (counter/26 + 1, counter % 26);
1793 let letter: char = from_u32((r+97) as u32).unwrap();
1794 for _ in range(0, n) {
1801 fn get_generated_lifetimes(&self) -> Vec<ast::Lifetime> {
1802 self.generated.borrow().clone()