error_reporting.rs 69.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

S
Steve Klabnik 已提交
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
//! Error Reporting Code for the inference engine
//!
//! Because of the way inference, and in particular region inference,
//! works, it often happens that errors are not detected until far after
//! the relevant line of code has been type-checked. Therefore, there is
//! an elaborate system to track why a particular constraint in the
//! inference graph arose so that we can explain to the user what gave
//! rise to a particular error.
//!
//! The basis of the system are the "origin" types. An "origin" is the
//! reason that a constraint or inference variable arose. There are
//! different "origin" enums for different kinds of constraints/variables
//! (e.g., `TypeOrigin`, `RegionVariableOrigin`). An origin always has
//! a span, but also more information so that we can generate a meaningful
//! error message.
//!
//! Having a catalogue of all the different reasons an error can arise is
//! also useful for other reasons, like cross-referencing FAQs etc, though
//! we are not really taking advantage of this yet.
//!
//! # Region Inference
//!
//! Region inference is particularly tricky because it always succeeds "in
//! the moment" and simply registers a constraint. Then, at the end, we
//! can compute the full graph and report errors, so we need to be able to
//! store and later report what gave rise to the conflicting constraints.
//!
//! # Subtype Trace
//!
//! Determing whether `T1 <: T2` often involves a number of subtypes and
//! subconstraints along the way. A "TypeTrace" is an extended version
//! of an origin that traces the types and other values that were being
//! compared. It is not necessarily comprehensive (in fact, at the time of
//! this writing it only tracks the root values being compared) but I'd
//! like to extend it to include significant "waypoints". For example, if
//! you are comparing `(T1, T2) <: (T3, T4)`, and the problem is that `T2
//! <: T4` fails, I'd like the trace to include enough information to say
//! "in the 2nd element of the tuple". Similarly, failures when comparing
//! arguments or return types in fn types should be able to cite the
//! specific position, etc.
//!
//! # Reality vs plan
//!
//! Of course, there is still a LOT of code in typeck that has yet to be
//! ported to this system, and which relies on string concatenation at the
//! time of error detection.

S
Steven Fackler 已提交
58
use self::FreshOrKept::*;
59

60 61 62 63 64 65 66 67 68 69 70 71 72
use super::InferCtxt;
use super::TypeTrace;
use super::SubregionOrigin;
use super::RegionVariableOrigin;
use super::ValuePairs;
use super::region_inference::RegionResolutionError;
use super::region_inference::ConcreteFailure;
use super::region_inference::SubSupConflict;
use super::region_inference::SupSupConflict;
use super::region_inference::ParamBoundFailure;
use super::region_inference::ProcessedErrors;
use super::region_inference::SameRegions;

73
use std::collections::HashSet;
74
use middle::def;
75
use middle::infer;
76
use middle::subst;
77
use middle::ty::{mod, Ty};
78 79 80
use middle::ty::{Region, ReFree};
use std::cell::{Cell, RefCell};
use std::char::from_u32;
E
Eduard Burtescu 已提交
81
use std::rc::Rc;
82
use std::string::String;
83 84
use syntax::ast;
use syntax::ast_map;
85
use syntax::ast_util::{name_to_dummy_lifetime, PostExpansionMethod};
86
use syntax::owned_slice::OwnedSlice;
87
use syntax::codemap;
88
use syntax::parse::token;
89
use syntax::print::pprust;
90
use syntax::ptr::P;
91
use util::ppaux::bound_region_to_string;
92 93
use util::ppaux::note_and_explain_region;

94 95 96 97
// Note: only import UserString, not Repr, since user-facing error
// messages shouldn't include debug serializations.
use util::ppaux::UserString;

98
pub trait ErrorReporting<'tcx> {
E
Eduard Burtescu 已提交
99
    fn report_region_errors(&self,
100
                            errors: &Vec<RegionResolutionError<'tcx>>);
101

102 103
    fn process_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>)
                      -> Vec<RegionResolutionError<'tcx>>;
104

105
    fn report_type_error(&self, trace: TypeTrace<'tcx>, terr: &ty::type_err<'tcx>);
106

E
Eduard Burtescu 已提交
107
    fn report_and_explain_type_error(&self,
108 109
                                     trace: TypeTrace<'tcx>,
                                     terr: &ty::type_err<'tcx>);
110

111
    fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<String>;
112

113
    fn expected_found_str<T: UserString<'tcx> + Resolvable<'tcx>>(
E
Eduard Burtescu 已提交
114
        &self,
115
        exp_found: &ty::expected_found<T>)
116
        -> Option<String>;
117

E
Eduard Burtescu 已提交
118
    fn report_concrete_failure(&self,
119
                               origin: SubregionOrigin<'tcx>,
120 121 122
                               sub: Region,
                               sup: Region);

123
    fn report_param_bound_failure(&self,
124
                                  origin: SubregionOrigin<'tcx>,
125 126 127 128
                                  param_ty: ty::ParamTy,
                                  sub: Region,
                                  sups: Vec<Region>);

E
Eduard Burtescu 已提交
129
    fn report_sub_sup_conflict(&self,
130
                               var_origin: RegionVariableOrigin,
131
                               sub_origin: SubregionOrigin<'tcx>,
132
                               sub_region: Region,
133
                               sup_origin: SubregionOrigin<'tcx>,
134 135
                               sup_region: Region);

E
Eduard Burtescu 已提交
136
    fn report_sup_sup_conflict(&self,
137
                               var_origin: RegionVariableOrigin,
138
                               origin1: SubregionOrigin<'tcx>,
139
                               region1: Region,
140
                               origin2: SubregionOrigin<'tcx>,
141
                               region2: Region);
142 143 144

    fn report_processed_errors(&self,
                               var_origin: &[RegionVariableOrigin],
145
                               trace_origin: &[(TypeTrace<'tcx>, ty::type_err<'tcx>)],
146 147 148
                               same_regions: &[SameRegions]);

    fn give_suggestion(&self, same_regions: &[SameRegions]);
149 150
}

151
trait ErrorReportingHelpers<'tcx> {
E
Eduard Burtescu 已提交
152
    fn report_inference_failure(&self,
153 154
                                var_origin: RegionVariableOrigin);

E
Eduard Burtescu 已提交
155
    fn note_region_origin(&self,
156
                          origin: &SubregionOrigin<'tcx>);
157 158

    fn give_expl_lifetime_param(&self,
159
                                decl: &ast::FnDecl,
N
Niko Matsakis 已提交
160
                                unsafety: ast::Unsafety,
161
                                ident: ast::Ident,
162
                                opt_explicit_self: Option<&ast::ExplicitSelf_>,
163 164
                                generics: &ast::Generics,
                                span: codemap::Span);
165
}
166

167
impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
E
Eduard Burtescu 已提交
168
    fn report_region_errors(&self,
169
                            errors: &Vec<RegionResolutionError<'tcx>>) {
170 171
        let p_errors = self.process_errors(errors);
        let errors = if p_errors.is_empty() { errors } else { &p_errors };
D
Daniel Micay 已提交
172
        for error in errors.iter() {
E
Eduard Burtescu 已提交
173
            match error.clone() {
174 175 176 177
                ConcreteFailure(origin, sub, sup) => {
                    self.report_concrete_failure(origin, sub, sup);
                }

178 179 180 181
                ParamBoundFailure(origin, param_ty, sub, sups) => {
                    self.report_param_bound_failure(origin, param_ty, sub, sups);
                }

182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
                SubSupConflict(var_origin,
                               sub_origin, sub_r,
                               sup_origin, sup_r) => {
                    self.report_sub_sup_conflict(var_origin,
                                                 sub_origin, sub_r,
                                                 sup_origin, sup_r);
                }

                SupSupConflict(var_origin,
                               origin1, r1,
                               origin2, r2) => {
                    self.report_sup_sup_conflict(var_origin,
                                                 origin1, r1,
                                                 origin2, r2);
                }
197 198 199 200 201 202 203 204 205 206

                ProcessedErrors(ref var_origins,
                                ref trace_origins,
                                ref same_regions) => {
                    if !same_regions.is_empty() {
                        self.report_processed_errors(var_origins.as_slice(),
                                                     trace_origins.as_slice(),
                                                     same_regions.as_slice());
                    }
                }
207 208 209 210
            }
        }
    }

211 212 213 214 215 216
    // This method goes through all the errors and try to group certain types
    // of error together, for the purpose of suggesting explicit lifetime
    // parameters to the user. This is done so that we can have a more
    // complete view of what lifetimes should be the same.
    // If the return value is an empty vector, it means that processing
    // failed (so the return value of this method should not be used)
217 218
    fn process_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>)
                      -> Vec<RegionResolutionError<'tcx>> {
219
        debug!("process_errors()");
220 221 222
        let mut var_origins = Vec::new();
        let mut trace_origins = Vec::new();
        let mut same_regions = Vec::new();
H
Huon Wilson 已提交
223
        let mut processed_errors = Vec::new();
224
        for error in errors.iter() {
E
Eduard Burtescu 已提交
225
            match error.clone() {
226
                ConcreteFailure(origin, sub, sup) => {
227
                    debug!("processing ConcreteFailure")
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
                    let trace = match origin {
                        infer::Subtype(trace) => Some(trace),
                        _ => None,
                    };
                    match free_regions_from_same_fn(self.tcx, sub, sup) {
                        Some(ref same_frs) if trace.is_some() => {
                            let trace = trace.unwrap();
                            let terr = ty::terr_regions_does_not_outlive(sup,
                                                                         sub);
                            trace_origins.push((trace, terr));
                            append_to_same_regions(&mut same_regions, same_frs);
                        }
                        _ => processed_errors.push((*error).clone()),
                    }
                }
                SubSupConflict(var_origin, _, sub_r, _, sup_r) => {
244
                    debug!("processing SubSupConflict")
245 246 247 248 249 250 251 252 253 254 255 256 257
                    match free_regions_from_same_fn(self.tcx, sub_r, sup_r) {
                        Some(ref same_frs) => {
                            var_origins.push(var_origin);
                            append_to_same_regions(&mut same_regions, same_frs);
                        }
                        None => processed_errors.push((*error).clone()),
                    }
                }
                SupSupConflict(..) => processed_errors.push((*error).clone()),
                _ => ()  // This shouldn't happen
            }
        }
        if !same_regions.is_empty() {
258
            let common_scope_id = same_regions[0].scope_id;
259 260 261 262 263
            for sr in same_regions.iter() {
                // Since ProcessedErrors is used to reconstruct the function
                // declaration, we want to make sure that they are, in fact,
                // from the same scope
                if sr.scope_id != common_scope_id {
264 265
                    debug!("returning empty result from process_errors because
                            {} != {}", sr.scope_id, common_scope_id);
H
Huon Wilson 已提交
266
                    return vec!();
267 268 269
                }
            }
            let pe = ProcessedErrors(var_origins, trace_origins, same_regions);
L
Luqman Aden 已提交
270
            debug!("errors processed: {}", pe);
271 272 273 274 275 276 277 278 279 280 281
            processed_errors.push(pe);
        }
        return processed_errors;


        struct FreeRegionsFromSameFn {
            sub_fr: ty::FreeRegion,
            sup_fr: ty::FreeRegion,
            scope_id: ast::NodeId
        }

282 283 284 285 286 287 288 289 290 291 292 293 294
        impl FreeRegionsFromSameFn {
            fn new(sub_fr: ty::FreeRegion,
                   sup_fr: ty::FreeRegion,
                   scope_id: ast::NodeId)
                   -> FreeRegionsFromSameFn {
                FreeRegionsFromSameFn {
                    sub_fr: sub_fr,
                    sup_fr: sup_fr,
                    scope_id: scope_id
                }
            }
        }

E
Eduard Burtescu 已提交
295
        fn free_regions_from_same_fn(tcx: &ty::ctxt,
296 297 298
                                     sub: Region,
                                     sup: Region)
                                     -> Option<FreeRegionsFromSameFn> {
L
Luqman Aden 已提交
299
            debug!("free_regions_from_same_fn(sub={}, sup={})", sub, sup);
300 301
            let (scope_id, fr1, fr2) = match (sub, sup) {
                (ReFree(fr1), ReFree(fr2)) => {
302
                    if fr1.scope != fr2.scope {
303 304
                        return None
                    }
305 306
                    assert!(fr1.scope == fr2.scope);
                    (fr1.scope.node_id(), fr1, fr2)
307 308 309 310 311 312 313 314 315
                },
                _ => return None
            };
            let parent = tcx.map.get_parent(scope_id);
            let parent_node = tcx.map.find(parent);
            match parent_node {
                Some(node) => match node {
                    ast_map::NodeItem(item) => match item.node {
                        ast::ItemFn(..) => {
316
                            Some(FreeRegionsFromSameFn::new(fr1, fr2, scope_id))
317 318 319
                        },
                        _ => None
                    },
320 321
                    ast_map::NodeImplItem(..) |
                    ast_map::NodeTraitItem(..) => {
322 323
                        Some(FreeRegionsFromSameFn::new(fr1, fr2, scope_id))
                    },
324 325
                    _ => None
                },
326 327 328 329
                None => {
                    debug!("no parent node of scope_id {}", scope_id)
                    None
                }
330 331 332 333 334 335 336
            }
        }

        fn append_to_same_regions(same_regions: &mut Vec<SameRegions>,
                                  same_frs: &FreeRegionsFromSameFn) {
            let scope_id = same_frs.scope_id;
            let (sub_fr, sup_fr) = (same_frs.sub_fr, same_frs.sup_fr);
A
Aaron Turon 已提交
337
            for sr in same_regions.iter_mut() {
338 339 340 341 342 343 344 345 346 347 348 349 350
                if sr.contains(&sup_fr.bound_region)
                   && scope_id == sr.scope_id {
                    sr.push(sub_fr.bound_region);
                    return
                }
            }
            same_regions.push(SameRegions {
                scope_id: scope_id,
                regions: vec!(sub_fr.bound_region, sup_fr.bound_region)
            })
        }
    }

351
    fn report_type_error(&self, trace: TypeTrace<'tcx>, terr: &ty::type_err<'tcx>) {
352 353 354 355 356 357 358 359 360 361 362 363
        let expected_found_str = match self.values_str(&trace.values) {
            Some(v) => v,
            None => {
                return; /* derived error */
            }
        };

        let message_root_str = match trace.origin {
            infer::Misc(_) => "mismatched types",
            infer::MethodCompatCheck(_) => "method not compatible with trait",
            infer::ExprAssignable(_) => "mismatched types",
            infer::RelateTraitRefs(_) => "mismatched traits",
364
            infer::RelateSelfType(_) => "mismatched types",
365
            infer::RelateOutputImplTypes(_) => "mismatched types",
366
            infer::MatchExpressionArm(_, _) => "match arms have incompatible types",
367
            infer::IfExpression(_) => "if and else have incompatible types",
368
            infer::IfExpressionWithNoElse(_) => "if may be missing an else clause",
369
            infer::EquatePredicate(_) => "equality predicate not satisfied",
370 371 372 373
        };

        self.tcx.sess.span_err(
            trace.origin.span(),
A
Alex Crichton 已提交
374
            format!("{}: {} ({})",
375 376
                 message_root_str,
                 expected_found_str,
377
                 ty::type_err_to_str(self.tcx, terr)).as_slice());
378 379 380 381 382 383

        match trace.origin {
            infer::MatchExpressionArm(_, arm_span) =>
                self.tcx.sess.span_note(arm_span, "match arm with an incompatible type"),
            _ => ()
        }
384
    }
385

386
    fn report_and_explain_type_error(&self,
387 388
                                     trace: TypeTrace<'tcx>,
                                     terr: &ty::type_err<'tcx>) {
389
        self.report_type_error(trace, terr);
390 391 392
        ty::note_and_explain_type_err(self.tcx, terr);
    }

S
Steve Klabnik 已提交
393 394
    /// Returns a string of the form "expected `{}`, found `{}`", or None if this is a derived
    /// error.
395
    fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<String> {
396
        match *values {
397 398
            infer::Types(ref exp_found) => self.expected_found_str(exp_found),
            infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found)
399 400 401
        }
    }

402
    fn expected_found_str<T: UserString<'tcx> + Resolvable<'tcx>>(
E
Eduard Burtescu 已提交
403
        &self,
404
        exp_found: &ty::expected_found<T>)
405
        -> Option<String>
406 407 408 409 410 411 412 413 414 415 416
    {
        let expected = exp_found.expected.resolve(self);
        if expected.contains_error() {
            return None;
        }

        let found = exp_found.found.resolve(self);
        if found.contains_error() {
            return None;
        }

417
        Some(format!("expected `{}`, found `{}`",
418 419
                     expected.user_string(self.tcx),
                     found.user_string(self.tcx)))
420 421
    }

422
    fn report_param_bound_failure(&self,
423
                                  origin: SubregionOrigin<'tcx>,
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
                                  param_ty: ty::ParamTy,
                                  sub: Region,
                                  _sups: Vec<Region>) {

        // FIXME: it would be better to report the first error message
        // with the span of the parameter itself, rather than the span
        // where the error was detected. But that span is not readily
        // accessible.

        match sub {
            ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
                // Does the required lifetime have a nice name we can print?
                self.tcx.sess.span_err(
                    origin.span(),
                    format!(
P
P1start 已提交
439 440 441 442 443 444
                        "the parameter type `{}` may not live long enough",
                        param_ty.user_string(self.tcx)).as_slice());
                self.tcx.sess.span_help(
                    origin.span(),
                    format!(
                        "consider adding an explicit lifetime bound `{}: {}`...",
445 446 447 448 449 450 451 452 453
                        param_ty.user_string(self.tcx),
                        sub.user_string(self.tcx)).as_slice());
            }

            ty::ReStatic => {
                // Does the required lifetime have a nice name we can print?
                self.tcx.sess.span_err(
                    origin.span(),
                    format!(
P
P1start 已提交
454 455 456 457 458 459
                        "the parameter type `{}` may not live long enough",
                        param_ty.user_string(self.tcx)).as_slice());
                self.tcx.sess.span_help(
                    origin.span(),
                    format!(
                        "consider adding an explicit lifetime bound `{}: 'static`...",
460 461 462 463 464 465 466 467
                        param_ty.user_string(self.tcx)).as_slice());
            }

            _ => {
                // If not, be less specific.
                self.tcx.sess.span_err(
                    origin.span(),
                    format!(
P
P1start 已提交
468 469 470 471 472 473
                        "the parameter type `{}` may not live long enough",
                        param_ty.user_string(self.tcx)).as_slice());
                self.tcx.sess.span_help(
                    origin.span(),
                    format!(
                        "consider adding an explicit lifetime bound to `{}`",
474 475 476 477 478 479 480 481 482 483 484 485 486
                        param_ty.user_string(self.tcx)).as_slice());
                note_and_explain_region(
                    self.tcx,
                    format!("the parameter type `{}` must be valid for ",
                            param_ty.user_string(self.tcx)).as_slice(),
                    sub,
                    "...");
            }
        }

        self.note_region_origin(&origin);
    }

E
Eduard Burtescu 已提交
487
    fn report_concrete_failure(&self,
488
                               origin: SubregionOrigin<'tcx>,
489 490 491 492
                               sub: Region,
                               sup: Region) {
        match origin {
            infer::Subtype(trace) => {
493
                let terr = ty::terr_regions_does_not_outlive(sup, sub);
494 495 496 497 498
                self.report_and_explain_type_error(trace, &terr);
            }
            infer::Reborrow(span) => {
                self.tcx.sess.span_err(
                    span,
499
                    "lifetime of reference outlines \
500 501 502
                     lifetime of borrowed content...");
                note_and_explain_region(
                    self.tcx,
503
                    "...the reference is valid for ",
504 505 506 507 508 509 510 511
                    sub,
                    "...");
                note_and_explain_region(
                    self.tcx,
                    "...but the borrowed content is only valid for ",
                    sup,
                    "");
            }
512 513 514 515 516
            infer::ReborrowUpvar(span, ref upvar_id) => {
                self.tcx.sess.span_err(
                    span,
                    format!("lifetime of borrowed pointer outlives \
                            lifetime of captured variable `{}`...",
517 518 519
                            ty::local_var_name_str(self.tcx,
                                                   upvar_id.var_id)
                                .get()
520
                                .to_string()).as_slice());
521 522 523 524 525 526 527 528
                note_and_explain_region(
                    self.tcx,
                    "...the borrowed pointer is valid for ",
                    sub,
                    "...");
                note_and_explain_region(
                    self.tcx,
                    format!("...but `{}` is only valid for ",
529 530 531
                            ty::local_var_name_str(self.tcx,
                                                   upvar_id.var_id)
                                .get()
532
                                .to_string()).as_slice(),
533 534 535
                    sup,
                    "");
            }
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
            infer::InfStackClosure(span) => {
                self.tcx.sess.span_err(
                    span,
                    "closure outlives stack frame");
                note_and_explain_region(
                    self.tcx,
                    "...the closure must be valid for ",
                    sub,
                    "...");
                note_and_explain_region(
                    self.tcx,
                    "...but the closure's stack frame is only valid for ",
                    sup,
                    "");
            }
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
            infer::InvokeClosure(span) => {
                self.tcx.sess.span_err(
                    span,
                    "cannot invoke closure outside of its lifetime");
                note_and_explain_region(
                    self.tcx,
                    "the closure is only valid for ",
                    sup,
                    "");
            }
            infer::DerefPointer(span) => {
                self.tcx.sess.span_err(
                    span,
                    "dereference of reference outside its lifetime");
                note_and_explain_region(
                    self.tcx,
                    "the reference is only valid for ",
                    sup,
                    "");
            }
571
            infer::FreeVariable(span, id) => {
572 573
                self.tcx.sess.span_err(
                    span,
574 575
                    format!("captured variable `{}` does not \
                            outlive the enclosing closure",
576 577
                            ty::local_var_name_str(self.tcx,
                                                   id).get()
578
                                                      .to_string()).as_slice());
579 580 581 582 583 584 585 586 587 588 589 590
                note_and_explain_region(
                    self.tcx,
                    "captured variable is valid for ",
                    sup,
                    "");
                note_and_explain_region(
                    self.tcx,
                    "closure is valid for ",
                    sub,
                    "");
            }
            infer::IndexSlice(span) => {
591 592
                self.tcx.sess.span_err(span,
                                       "index of slice outside its lifetime");
593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
                note_and_explain_region(
                    self.tcx,
                    "the slice is only valid for ",
                    sup,
                    "");
            }
            infer::RelateObjectBound(span) => {
                self.tcx.sess.span_err(
                    span,
                    "lifetime of the source pointer does not outlive \
                     lifetime bound of the object type");
                note_and_explain_region(
                    self.tcx,
                    "object type is valid for ",
                    sub,
                    "");
                note_and_explain_region(
                    self.tcx,
                    "source pointer is only valid for ",
                    sup,
                    "");
            }
615
            infer::RelateParamBound(span, ty) => {
616 617
                self.tcx.sess.span_err(
                    span,
618
                    format!("the type `{}` does not fulfill the \
619
                             required lifetime",
620
                            self.ty_to_string(ty)).as_slice());
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651
                note_and_explain_region(self.tcx,
                                        "type must outlive ",
                                        sub,
                                        "");
            }
            infer::RelateRegionParamBound(span) => {
                self.tcx.sess.span_err(
                    span,
                    "declared lifetime bound not satisfied");
                note_and_explain_region(
                    self.tcx,
                    "lifetime parameter instantiated with ",
                    sup,
                    "");
                note_and_explain_region(
                    self.tcx,
                    "but lifetime parameter must outlive ",
                    sub,
                    "");
            }
            infer::RelateDefaultParamBound(span, ty) => {
                self.tcx.sess.span_err(
                    span,
                    format!("the type `{}` (provided as the value of \
                             a type parameter) is not valid at this point",
                            self.ty_to_string(ty)).as_slice());
                note_and_explain_region(self.tcx,
                                        "type must outlive ",
                                        sub,
                                        "");
            }
652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
            infer::CallRcvr(span) => {
                self.tcx.sess.span_err(
                    span,
                    "lifetime of method receiver does not outlive \
                     the method call");
                note_and_explain_region(
                    self.tcx,
                    "the receiver is only valid for ",
                    sup,
                    "");
            }
            infer::CallArg(span) => {
                self.tcx.sess.span_err(
                    span,
                    "lifetime of function argument does not outlive \
                     the function call");
                note_and_explain_region(
                    self.tcx,
                    "the function argument is only valid for ",
                    sup,
                    "");
            }
            infer::CallReturn(span) => {
                self.tcx.sess.span_err(
                    span,
                    "lifetime of return value does not outlive \
                     the function call");
                note_and_explain_region(
                    self.tcx,
                    "the return value is only valid for ",
                    sup,
                    "");
            }
            infer::AddrOf(span) => {
                self.tcx.sess.span_err(
                    span,
688
                    "reference is not valid \
689 690 691 692 693 694 695 696 697 698
                     at the time of borrow");
                note_and_explain_region(
                    self.tcx,
                    "the borrow is only valid for ",
                    sup,
                    "");
            }
            infer::AutoBorrow(span) => {
                self.tcx.sess.span_err(
                    span,
699
                    "automatically reference is not valid \
700 701 702 703 704 705 706
                     at the time of borrow");
                note_and_explain_region(
                    self.tcx,
                    "the automatic borrow is only valid for ",
                    sup,
                    "");
            }
707 708 709 710 711 712 713 714 715 716 717 718
            infer::ExprTypeIsNotInScope(t, span) => {
                self.tcx.sess.span_err(
                    span,
                    format!("type of expression contains references \
                             that are not valid during the expression: `{}`",
                            self.ty_to_string(t)).as_slice());
                note_and_explain_region(
                    self.tcx,
                    "type is only valid for ",
                    sup,
                    "");
            }
719 720 721 722 723 724 725 726 727 728
            infer::BindingTypeIsNotValidAtDecl(span) => {
                self.tcx.sess.span_err(
                    span,
                    "lifetime of variable does not enclose its declaration");
                note_and_explain_region(
                    self.tcx,
                    "the variable is only valid for ",
                    sup,
                    "");
            }
N
Niko Matsakis 已提交
729
            infer::ReferenceOutlivesReferent(ty, span) => {
730
                self.tcx.sess.span_err(
N
Niko Matsakis 已提交
731
                    span,
732 733 734
                    format!("in type `{}`, reference has a longer lifetime \
                             than the data it references",
                            self.ty_to_string(ty)).as_slice());
735 736 737 738 739 740 741 742 743 744 745 746 747 748
                note_and_explain_region(
                    self.tcx,
                    "the pointer is valid for ",
                    sub,
                    "");
                note_and_explain_region(
                    self.tcx,
                    "but the referenced data is only valid for ",
                    sup,
                    "");
            }
        }
    }

E
Eduard Burtescu 已提交
749
    fn report_sub_sup_conflict(&self,
750
                               var_origin: RegionVariableOrigin,
751
                               sub_origin: SubregionOrigin<'tcx>,
752
                               sub_region: Region,
753
                               sup_origin: SubregionOrigin<'tcx>,
754
                               sup_region: Region) {
755
        self.report_inference_failure(var_origin);
756 757 758 759 760 761 762

        note_and_explain_region(
            self.tcx,
            "first, the lifetime cannot outlive ",
            sup_region,
            "...");

763
        self.note_region_origin(&sup_origin);
764 765 766 767 768 769 770

        note_and_explain_region(
            self.tcx,
            "but, the lifetime must be valid for ",
            sub_region,
            "...");

771
        self.note_region_origin(&sub_origin);
772 773
    }

E
Eduard Burtescu 已提交
774
    fn report_sup_sup_conflict(&self,
775
                               var_origin: RegionVariableOrigin,
776
                               origin1: SubregionOrigin<'tcx>,
777
                               region1: Region,
778
                               origin2: SubregionOrigin<'tcx>,
779
                               region2: Region) {
780
        self.report_inference_failure(var_origin);
781 782 783 784 785 786 787

        note_and_explain_region(
            self.tcx,
            "first, the lifetime must be contained by ",
            region1,
            "...");

788
        self.note_region_origin(&origin1);
789 790 791 792 793 794 795

        note_and_explain_region(
            self.tcx,
            "but, the lifetime must also be contained by ",
            region2,
            "...");

796
        self.note_region_origin(&origin2);
797
    }
798 799 800

    fn report_processed_errors(&self,
                               var_origins: &[RegionVariableOrigin],
801
                               trace_origins: &[(TypeTrace<'tcx>, ty::type_err<'tcx>)],
802 803
                               same_regions: &[SameRegions]) {
        for vo in var_origins.iter() {
E
Eduard Burtescu 已提交
804
            self.report_inference_failure(vo.clone());
805
        }
806
        self.give_suggestion(same_regions);
E
Eduard Burtescu 已提交
807 808
        for &(ref trace, terr) in trace_origins.iter() {
            self.report_type_error(trace.clone(), &terr);
809 810 811 812 813 814 815 816
        }
    }

    fn give_suggestion(&self, same_regions: &[SameRegions]) {
        let scope_id = same_regions[0].scope_id;
        let parent = self.tcx.map.get_parent(scope_id);
        let parent_node = self.tcx.map.find(parent);
        let node_inner = match parent_node {
F
Flavio Percoco 已提交
817 818 819
            Some(ref node) => match *node {
                ast_map::NodeItem(ref item) => {
                    match item.node {
820 821
                        ast::ItemFn(ref fn_decl, pur, _, ref gen, _) => {
                            Some((&**fn_decl, gen, pur, item.ident, None, item.span))
F
Flavio Percoco 已提交
822 823 824 825
                        },
                        _ => None
                    }
                }
826 827 828 829 830
                ast_map::NodeImplItem(ref item) => {
                    match **item {
                        ast::MethodImplItem(ref m) => {
                            Some((m.pe_fn_decl(),
                                  m.pe_generics(),
N
Niko Matsakis 已提交
831
                                  m.pe_unsafety(),
832
                                  m.pe_ident(),
833
                                  Some(&m.pe_explicit_self().node),
834 835
                                  m.span))
                        }
836
                        ast::TypeImplItem(_) => None,
837
                    }
838
                },
839 840 841 842 843
                ast_map::NodeTraitItem(ref item) => {
                    match **item {
                        ast::ProvidedMethod(ref m) => {
                            Some((m.pe_fn_decl(),
                                  m.pe_generics(),
N
Niko Matsakis 已提交
844
                                  m.pe_unsafety(),
845 846 847 848 849 850 851
                                  m.pe_ident(),
                                  Some(&m.pe_explicit_self().node),
                                  m.span))
                        }
                        _ => None
                    }
                }
852 853 854 855
                _ => None
            },
            None => None
        };
N
Niko Matsakis 已提交
856
        let (fn_decl, generics, unsafety, ident, expl_self, span)
857 858 859
                                    = node_inner.expect("expect item fn");
        let taken = lifetimes_in_scope(self.tcx, scope_id);
        let life_giver = LifeGiver::with_taken(taken.as_slice());
860
        let rebuilder = Rebuilder::new(self.tcx, fn_decl, expl_self,
861 862
                                       generics, same_regions, &life_giver);
        let (fn_decl, expl_self, generics) = rebuilder.rebuild();
N
Niko Matsakis 已提交
863
        self.give_expl_lifetime_param(&fn_decl, unsafety, ident,
864
                                      expl_self.as_ref(), &generics, span);
865 866 867
    }
}

868 869 870 871 872 873 874 875 876 877 878
struct RebuildPathInfo<'a> {
    path: &'a ast::Path,
    // indexes to insert lifetime on path.lifetimes
    indexes: Vec<uint>,
    // number of lifetimes we expect to see on the type referred by `path`
    // (e.g., expected=1 for struct Foo<'a>)
    expected: uint,
    anon_nums: &'a HashSet<uint>,
    region_names: &'a HashSet<ast::Name>
}

879 880
struct Rebuilder<'a, 'tcx: 'a> {
    tcx: &'a ty::ctxt<'tcx>,
881 882
    fn_decl: &'a ast::FnDecl,
    expl_self_opt: Option<&'a ast::ExplicitSelf_>,
883 884
    generics: &'a ast::Generics,
    same_regions: &'a [SameRegions],
885
    life_giver: &'a LifeGiver,
886 887 888 889
    cur_anon: Cell<uint>,
    inserted_anons: RefCell<HashSet<uint>>,
}

890 891 892 893 894
enum FreshOrKept {
    Fresh,
    Kept
}

895 896
impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
    fn new(tcx: &'a ty::ctxt<'tcx>,
897 898
           fn_decl: &'a ast::FnDecl,
           expl_self_opt: Option<&'a ast::ExplicitSelf_>,
899
           generics: &'a ast::Generics,
900 901
           same_regions: &'a [SameRegions],
           life_giver: &'a LifeGiver)
902
           -> Rebuilder<'a, 'tcx> {
903 904 905
        Rebuilder {
            tcx: tcx,
            fn_decl: fn_decl,
906
            expl_self_opt: expl_self_opt,
907 908
            generics: generics,
            same_regions: same_regions,
909
            life_giver: life_giver,
910 911 912 913 914
            cur_anon: Cell::new(0),
            inserted_anons: RefCell::new(HashSet::new()),
        }
    }

915 916
    fn rebuild(&self)
               -> (ast::FnDecl, Option<ast::ExplicitSelf_>, ast::Generics) {
917
        let mut expl_self_opt = self.expl_self_opt.map(|x| x.clone());
918
        let mut inputs = self.fn_decl.inputs.clone();
919
        let mut output = self.fn_decl.output.clone();
920
        let mut ty_params = self.generics.ty_params.clone();
921
        let where_clause = self.generics.where_clause.clone();
922
        let mut kept_lifetimes = HashSet::new();
923 924 925 926 927
        for sr in self.same_regions.iter() {
            self.cur_anon.set(0);
            self.offset_cur_anon();
            let (anon_nums, region_names) =
                                self.extract_anon_nums_and_names(sr);
928 929 930 931 932 933 934
            let (lifetime, fresh_or_kept) = self.pick_lifetime(&region_names);
            match fresh_or_kept {
                Kept => { kept_lifetimes.insert(lifetime.name); }
                _ => ()
            }
            expl_self_opt = self.rebuild_expl_self(expl_self_opt, lifetime,
                                                   &anon_nums, &region_names);
935 936
            inputs = self.rebuild_args_ty(inputs.as_slice(), lifetime,
                                          &anon_nums, &region_names);
937
            output = self.rebuild_output(&output, lifetime, &anon_nums, &region_names);
938 939
            ty_params = self.rebuild_ty_params(ty_params, lifetime,
                                               &region_names);
940
        }
941
        let fresh_lifetimes = self.life_giver.get_generated_lifetimes();
942 943
        let all_region_names = self.extract_all_region_names();
        let generics = self.rebuild_generics(self.generics,
944 945 946
                                             &fresh_lifetimes,
                                             &kept_lifetimes,
                                             &all_region_names,
947 948
                                             ty_params,
                                             where_clause);
949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965
        let new_fn_decl = ast::FnDecl {
            inputs: inputs,
            output: output,
            variadic: self.fn_decl.variadic
        };
        (new_fn_decl, expl_self_opt, generics)
    }

    fn pick_lifetime(&self,
                     region_names: &HashSet<ast::Name>)
                     -> (ast::Lifetime, FreshOrKept) {
        if region_names.len() > 0 {
            // It's not necessary to convert the set of region names to a
            // vector of string and then sort them. However, it makes the
            // choice of lifetime name deterministic and thus easier to test.
            let mut names = Vec::new();
            for rn in region_names.iter() {
R
Richo Healey 已提交
966
                let lt_name = token::get_name(*rn).get().to_string();
967 968 969
                names.push(lt_name);
            }
            names.sort();
970
            let name = token::str_to_ident(names[0].as_slice()).name;
971 972 973
            return (name_to_dummy_lifetime(name), Kept);
        }
        return (self.life_giver.give_lifetime(), Fresh);
974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
    }

    fn extract_anon_nums_and_names(&self, same_regions: &SameRegions)
                                   -> (HashSet<uint>, HashSet<ast::Name>) {
        let mut anon_nums = HashSet::new();
        let mut region_names = HashSet::new();
        for br in same_regions.regions.iter() {
            match *br {
                ty::BrAnon(i) => {
                    anon_nums.insert(i);
                }
                ty::BrNamed(_, name) => {
                    region_names.insert(name);
                }
                _ => ()
            }
        }
        (anon_nums, region_names)
    }

    fn extract_all_region_names(&self) -> HashSet<ast::Name> {
        let mut all_region_names = HashSet::new();
        for sr in self.same_regions.iter() {
            for br in sr.regions.iter() {
                match *br {
                    ty::BrNamed(_, name) => {
                        all_region_names.insert(name);
                    }
                    _ => ()
                }
            }
        }
        all_region_names
    }

    fn inc_cur_anon(&self, n: uint) {
        let anon = self.cur_anon.get();
        self.cur_anon.set(anon+n);
    }

    fn offset_cur_anon(&self) {
        let mut anon = self.cur_anon.get();
1016
        while self.inserted_anons.borrow().contains(&anon) {
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027
            anon += 1;
        }
        self.cur_anon.set(anon);
    }

    fn inc_and_offset_cur_anon(&self, n: uint) {
        self.inc_cur_anon(n);
        self.offset_cur_anon();
    }

    fn track_anon(&self, anon: uint) {
1028
        self.inserted_anons.borrow_mut().insert(anon);
1029 1030
    }

1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043
    fn rebuild_ty_params(&self,
                         ty_params: OwnedSlice<ast::TyParam>,
                         lifetime: ast::Lifetime,
                         region_names: &HashSet<ast::Name>)
                         -> OwnedSlice<ast::TyParam> {
        ty_params.map(|ty_param| {
            let bounds = self.rebuild_ty_param_bounds(ty_param.bounds.clone(),
                                                      lifetime,
                                                      region_names);
            ast::TyParam {
                ident: ty_param.ident,
                id: ty_param.id,
                bounds: bounds,
N
Nick Cameron 已提交
1044
                unbound: ty_param.unbound.clone(),
1045
                default: ty_param.default.clone(),
1046
                span: ty_param.span,
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057
            }
        })
    }

    fn rebuild_ty_param_bounds(&self,
                               ty_param_bounds: OwnedSlice<ast::TyParamBound>,
                               lifetime: ast::Lifetime,
                               region_names: &HashSet<ast::Name>)
                               -> OwnedSlice<ast::TyParamBound> {
        ty_param_bounds.map(|tpb| {
            match tpb {
1058 1059 1060 1061 1062 1063
                &ast::RegionTyParamBound(lt) => {
                    // FIXME -- it's unclear whether I'm supposed to
                    // substitute lifetime here. I suspect we need to
                    // be passing down a map.
                    ast::RegionTyParamBound(lt)
                }
N
Niko Matsakis 已提交
1064 1065
                &ast::TraitTyParamBound(ref poly_tr) => {
                    let tr = &poly_tr.trait_ref;
1066 1067
                    let last_seg = tr.path.segments.last().unwrap();
                    let mut insert = Vec::new();
1068 1069
                    let lifetimes = last_seg.parameters.lifetimes();
                    for (i, lt) in lifetimes.iter().enumerate() {
1070 1071 1072 1073 1074 1075 1076
                        if region_names.contains(&lt.name) {
                            insert.push(i);
                        }
                    }
                    let rebuild_info = RebuildPathInfo {
                        path: &tr.path,
                        indexes: insert,
1077
                        expected: lifetimes.len(),
1078 1079 1080 1081
                        anon_nums: &HashSet::new(),
                        region_names: region_names
                    };
                    let new_path = self.rebuild_path(rebuild_info, lifetime);
N
Niko Matsakis 已提交
1082 1083 1084 1085 1086 1087
                    ast::TraitTyParamBound(ast::PolyTraitRef {
                        bound_lifetimes: poly_tr.bound_lifetimes.clone(),
                        trait_ref: ast::TraitRef {
                            path: new_path,
                            ref_id: tr.ref_id,
                        }
1088 1089 1090 1091 1092 1093
                    })
                }
            }
        })
    }

1094 1095 1096 1097 1098 1099 1100
    fn rebuild_expl_self(&self,
                         expl_self_opt: Option<ast::ExplicitSelf_>,
                         lifetime: ast::Lifetime,
                         anon_nums: &HashSet<uint>,
                         region_names: &HashSet<ast::Name>)
                         -> Option<ast::ExplicitSelf_> {
        match expl_self_opt {
1101
            Some(ref expl_self) => match *expl_self {
1102
                ast::SelfRegion(lt_opt, muta, id) => match lt_opt {
1103
                    Some(lt) => if region_names.contains(&lt.name) {
1104
                        return Some(ast::SelfRegion(Some(lifetime), muta, id));
1105 1106 1107 1108 1109 1110
                    },
                    None => {
                        let anon = self.cur_anon.get();
                        self.inc_and_offset_cur_anon(1);
                        if anon_nums.contains(&anon) {
                            self.track_anon(anon);
1111
                            return Some(ast::SelfRegion(Some(lifetime), muta, id));
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
                        }
                    }
                },
                _ => ()
            },
            None => ()
        }
        expl_self_opt
    }

1122 1123
    fn rebuild_generics(&self,
                        generics: &ast::Generics,
1124 1125
                        add: &Vec<ast::Lifetime>,
                        keep: &HashSet<ast::Name>,
1126
                        remove: &HashSet<ast::Name>,
1127 1128
                        ty_params: OwnedSlice<ast::TyParam>,
                        where_clause: ast::WhereClause)
1129 1130 1131
                        -> ast::Generics {
        let mut lifetimes = Vec::new();
        for lt in add.iter() {
1132 1133
            lifetimes.push(ast::LifetimeDef { lifetime: *lt,
                                              bounds: Vec::new() });
1134 1135
        }
        for lt in generics.lifetimes.iter() {
1136
            if keep.contains(&lt.lifetime.name) ||
1137
                !remove.contains(&lt.lifetime.name) {
1138 1139 1140 1141 1142
                lifetimes.push((*lt).clone());
            }
        }
        ast::Generics {
            lifetimes: lifetimes,
1143 1144
            ty_params: ty_params,
            where_clause: where_clause,
1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155
        }
    }

    fn rebuild_args_ty(&self,
                       inputs: &[ast::Arg],
                       lifetime: ast::Lifetime,
                       anon_nums: &HashSet<uint>,
                       region_names: &HashSet<ast::Name>)
                       -> Vec<ast::Arg> {
        let mut new_inputs = Vec::new();
        for arg in inputs.iter() {
1156
            let new_ty = self.rebuild_arg_ty_or_output(&*arg.ty, lifetime,
1157 1158 1159
                                                       anon_nums, region_names);
            let possibly_new_arg = ast::Arg {
                ty: new_ty,
1160
                pat: arg.pat.clone(),
1161 1162 1163 1164 1165 1166 1167
                id: arg.id
            };
            new_inputs.push(possibly_new_arg);
        }
        new_inputs
    }

1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179
    fn rebuild_output(&self, ty: &ast::FunctionRetTy,
                      lifetime: ast::Lifetime,
                      anon_nums: &HashSet<uint>,
                      region_names: &HashSet<ast::Name>) -> ast::FunctionRetTy {
        match *ty {
            ast::Return(ref ret_ty) => ast::Return(
                self.rebuild_arg_ty_or_output(&**ret_ty, lifetime, anon_nums, region_names)
            ),
            ast::NoReturn(span) => ast::NoReturn(span)
        }
    }

1180
    fn rebuild_arg_ty_or_output(&self,
1181
                                ty: &ast::Ty,
1182 1183 1184
                                lifetime: ast::Lifetime,
                                anon_nums: &HashSet<uint>,
                                region_names: &HashSet<ast::Name>)
1185 1186
                                -> P<ast::Ty> {
        let mut new_ty = P(ty.clone());
1187 1188
        let mut ty_queue = vec!(ty);
        while !ty_queue.is_empty() {
1189
            let cur_ty = ty_queue.remove(0).unwrap();
1190
            match cur_ty.node {
1191 1192 1193
                ast::TyRptr(lt_opt, ref mut_ty) => {
                    let rebuild = match lt_opt {
                        Some(lt) => region_names.contains(&lt.name),
1194 1195
                        None => {
                            let anon = self.cur_anon.get();
1196 1197
                            let rebuild = anon_nums.contains(&anon);
                            if rebuild {
1198 1199 1200
                                self.track_anon(anon);
                            }
                            self.inc_and_offset_cur_anon(1);
1201
                            rebuild
1202
                        }
1203 1204 1205 1206 1207 1208 1209 1210
                    };
                    if rebuild {
                        let to = ast::Ty {
                            id: cur_ty.id,
                            node: ast::TyRptr(Some(lifetime), mut_ty.clone()),
                            span: cur_ty.span
                        };
                        new_ty = self.rebuild_ty(new_ty, P(to));
1211
                    }
1212
                    ty_queue.push(&*mut_ty.ty);
1213
                }
1214
                ast::TyPath(ref path, id) => {
1215
                    let a_def = match self.tcx.def_map.borrow().get(&id) {
1216 1217 1218 1219 1220
                        None => {
                            self.tcx
                                .sess
                                .fatal(format!(
                                        "unbound path {}",
1221
                                        pprust::path_to_string(path)).as_slice())
1222
                        }
1223 1224 1225
                        Some(&d) => d
                    };
                    match a_def {
1226
                        def::DefTy(did, _) | def::DefStruct(did) => {
1227
                            let generics = ty::lookup_item_type(self.tcx, did).generics;
1228

1229 1230 1231
                            let expected =
                                generics.regions.len(subst::TypeSpace);
                            let lifetimes =
1232
                                path.segments.last().unwrap().parameters.lifetimes();
1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250
                            let mut insert = Vec::new();
                            if lifetimes.len() == 0 {
                                let anon = self.cur_anon.get();
                                for (i, a) in range(anon,
                                                    anon+expected).enumerate() {
                                    if anon_nums.contains(&a) {
                                        insert.push(i);
                                    }
                                    self.track_anon(a);
                                }
                                self.inc_and_offset_cur_anon(expected);
                            } else {
                                for (i, lt) in lifetimes.iter().enumerate() {
                                    if region_names.contains(&lt.name) {
                                        insert.push(i);
                                    }
                                }
                            }
1251 1252 1253 1254 1255 1256 1257
                            let rebuild_info = RebuildPathInfo {
                                path: path,
                                indexes: insert,
                                expected: expected,
                                anon_nums: anon_nums,
                                region_names: region_names
                            };
1258 1259 1260
                            let new_path = self.rebuild_path(rebuild_info, lifetime);
                            let to = ast::Ty {
                                id: cur_ty.id,
1261
                                node: ast::TyPath(new_path, id),
1262 1263 1264
                                span: cur_ty.span
                            };
                            new_ty = self.rebuild_ty(new_ty, P(to));
1265 1266 1267 1268 1269
                        }
                        _ => ()
                    }

                }
1270 1271 1272 1273 1274 1275 1276 1277 1278 1279

                ast::TyPtr(ref mut_ty) => {
                    ty_queue.push(&*mut_ty.ty);
                }
                ast::TyVec(ref ty) |
                ast::TyFixedLengthVec(ref ty, _) => {
                    ty_queue.push(&**ty);
                }
                ast::TyTup(ref tys) => ty_queue.extend(tys.iter().map(|ty| &**ty)),
                _ => {}
1280 1281 1282 1283 1284 1285
            }
        }
        new_ty
    }

    fn rebuild_ty(&self,
1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302
                  from: P<ast::Ty>,
                  to: P<ast::Ty>)
                  -> P<ast::Ty> {

        fn build_to(from: P<ast::Ty>,
                    to: &mut Option<P<ast::Ty>>)
                    -> P<ast::Ty> {
            if Some(from.id) == to.as_ref().map(|ty| ty.id) {
                return to.take().expect("`to` type found more than once during rebuild");
            }
            from.map(|ast::Ty {id, node, span}| {
                let new_node = match node {
                    ast::TyRptr(lifetime, mut_ty) => {
                        ast::TyRptr(lifetime, ast::MutTy {
                            mutbl: mut_ty.mutbl,
                            ty: build_to(mut_ty.ty, to),
                        })
1303
                    }
1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314
                    ast::TyPtr(mut_ty) => {
                        ast::TyPtr(ast::MutTy {
                            mutbl: mut_ty.mutbl,
                            ty: build_to(mut_ty.ty, to),
                        })
                    }
                    ast::TyVec(ty) => ast::TyVec(build_to(ty, to)),
                    ast::TyFixedLengthVec(ty, e) => {
                        ast::TyFixedLengthVec(build_to(ty, to), e)
                    }
                    ast::TyTup(tys) => {
A
Aaron Turon 已提交
1315
                        ast::TyTup(tys.into_iter().map(|ty| build_to(ty, to)).collect())
1316 1317 1318 1319 1320 1321
                    }
                    ast::TyParen(typ) => ast::TyParen(build_to(typ, to)),
                    other => other
                };
                ast::Ty { id: id, node: new_node, span: span }
            })
1322 1323
        }

1324
        build_to(from, &mut Some(to))
1325 1326 1327
    }

    fn rebuild_path(&self,
1328
                    rebuild_info: RebuildPathInfo,
1329
                    lifetime: ast::Lifetime)
1330 1331
                    -> ast::Path
    {
1332
        let RebuildPathInfo {
1333 1334 1335 1336 1337
            path,
            indexes,
            expected,
            anon_nums,
            region_names,
1338 1339
        } = rebuild_info;

1340
        let last_seg = path.segments.last().unwrap();
1341 1342 1343
        let new_parameters = match last_seg.parameters {
            ast::ParenthesizedParameters(..) => {
                last_seg.parameters.clone()
1344
            }
1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361

            ast::AngleBracketedParameters(ref data) => {
                let mut new_lts = Vec::new();
                if data.lifetimes.len() == 0 {
                    // traverse once to see if there's a need to insert lifetime
                    let need_insert = range(0, expected).any(|i| {
                        indexes.contains(&i)
                    });
                    if need_insert {
                        for i in range(0, expected) {
                            if indexes.contains(&i) {
                                new_lts.push(lifetime);
                            } else {
                                new_lts.push(self.life_giver.give_lifetime());
                            }
                        }
                    }
1362
                } else {
1363 1364 1365 1366 1367 1368 1369
                    for (i, lt) in data.lifetimes.iter().enumerate() {
                        if indexes.contains(&i) {
                            new_lts.push(lifetime);
                        } else {
                            new_lts.push(*lt);
                        }
                    }
1370
                }
1371 1372 1373
                let new_types = data.types.map(|t| {
                    self.rebuild_arg_ty_or_output(&**t, lifetime, anon_nums, region_names)
                });
1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384
                let new_bindings = data.bindings.map(|b| {
                    P(ast::TypeBinding {
                        id: b.id,
                        ident: b.ident,
                        ty: self.rebuild_arg_ty_or_output(&*b.ty,
                                                          lifetime,
                                                          anon_nums,
                                                          region_names),
                        span: b.span
                    })
                });
1385 1386
                ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
                    lifetimes: new_lts,
1387 1388 1389
                    types: new_types,
                    bindings: new_bindings,
               })
1390
            }
1391
        };
1392 1393
        let new_seg = ast::PathSegment {
            identifier: last_seg.identifier,
1394
            parameters: new_parameters
1395 1396 1397 1398 1399 1400 1401 1402 1403 1404
        };
        let mut new_segs = Vec::new();
        new_segs.push_all(path.segments.init());
        new_segs.push(new_seg);
        ast::Path {
            span: path.span,
            global: path.global,
            segments: new_segs
        }
    }
1405 1406
}

1407
impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
1408
    fn give_expl_lifetime_param(&self,
1409
                                decl: &ast::FnDecl,
N
Niko Matsakis 已提交
1410
                                unsafety: ast::Unsafety,
1411
                                ident: ast::Ident,
1412
                                opt_explicit_self: Option<&ast::ExplicitSelf_>,
1413 1414
                                generics: &ast::Generics,
                                span: codemap::Span) {
N
Niko Matsakis 已提交
1415
        let suggested_fn = pprust::fun_to_string(decl, unsafety, ident,
1416
                                              opt_explicit_self, generics);
1417 1418
        let msg = format!("consider using an explicit lifetime \
                           parameter as shown: {}", suggested_fn);
P
P1start 已提交
1419
        self.tcx.sess.span_help(span, msg.as_slice());
1420 1421
    }

E
Eduard Burtescu 已提交
1422
    fn report_inference_failure(&self,
1423 1424
                                var_origin: RegionVariableOrigin) {
        let var_description = match var_origin {
1425 1426 1427 1428 1429 1430
            infer::MiscVariable(_) => "".to_string(),
            infer::PatternRegion(_) => " for pattern".to_string(),
            infer::AddrOfRegion(_) => " for borrow expression".to_string(),
            infer::AddrOfSlice(_) => " for slice expression".to_string(),
            infer::Autoref(_) => " for autoref".to_string(),
            infer::Coercion(_) => " for automatic coercion".to_string(),
1431
            infer::LateBoundRegion(_, br, infer::FnCall) => {
1432
                format!(" for {}in function call",
1433
                        bound_region_to_string(self.tcx, "lifetime parameter ", true, br))
1434
            }
1435 1436
            infer::LateBoundRegion(_, br, infer::HigherRankedType) => {
                format!(" for {}in generic type",
1437
                        bound_region_to_string(self.tcx, "lifetime parameter ", true, br))
1438
            }
1439
            infer::EarlyBoundRegion(_, name) => {
1440
                format!(" for lifetime parameter `{}`",
1441
                        token::get_name(name).get())
1442
            }
1443
            infer::BoundRegionInCoherence(name) => {
1444
                format!(" for lifetime parameter `{}` in coherence check",
1445
                        token::get_name(name).get())
1446
            }
1447 1448
            infer::UpvarRegion(ref upvar_id, _) => {
                format!(" for capture of `{}` by closure",
1449
                        ty::local_var_name_str(self.tcx, upvar_id.var_id).get().to_string())
1450
            }
1451 1452 1453 1454 1455 1456
        };

        self.tcx.sess.span_err(
            var_origin.span(),
            format!("cannot infer an appropriate lifetime{} \
                    due to conflicting requirements",
1457
                    var_description).as_slice());
1458 1459
    }

1460
    fn note_region_origin(&self, origin: &SubregionOrigin<'tcx>) {
1461
        match *origin {
1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476
            infer::Subtype(ref trace) => {
                let desc = match trace.origin {
                    infer::Misc(_) => {
                        format!("types are compatible")
                    }
                    infer::MethodCompatCheck(_) => {
                        format!("method type is compatible with trait")
                    }
                    infer::ExprAssignable(_) => {
                        format!("expression is assignable")
                    }
                    infer::RelateTraitRefs(_) => {
                        format!("traits are compatible")
                    }
                    infer::RelateSelfType(_) => {
1477 1478 1479 1480 1481
                        format!("self type matches impl self type")
                    }
                    infer::RelateOutputImplTypes(_) => {
                        format!("trait type parameters matches those \
                                 specified on the impl")
1482
                    }
1483
                    infer::MatchExpressionArm(_, _) => {
1484 1485 1486 1487 1488
                        format!("match arms have compatible types")
                    }
                    infer::IfExpression(_) => {
                        format!("if and else have compatible types")
                    }
1489 1490 1491
                    infer::IfExpressionWithNoElse(_) => {
                        format!("if may be missing an else clause")
                    }
1492 1493 1494
                    infer::EquatePredicate(_) => {
                        format!("equality where clause is satisfied")
                    }
1495 1496 1497 1498 1499 1500 1501
                };

                match self.values_str(&trace.values) {
                    Some(values_str) => {
                        self.tcx.sess.span_note(
                            trace.origin.span(),
                            format!("...so that {} ({})",
1502
                                    desc, values_str).as_slice());
1503 1504 1505 1506 1507 1508 1509 1510
                    }
                    None => {
                        // Really should avoid printing this error at
                        // all, since it is derived, but that would
                        // require more refactoring than I feel like
                        // doing right now. - nmatsakis
                        self.tcx.sess.span_note(
                            trace.origin.span(),
1511
                            format!("...so that {}", desc).as_slice());
1512 1513 1514 1515 1516 1517
                    }
                }
            }
            infer::Reborrow(span) => {
                self.tcx.sess.span_note(
                    span,
1518
                    "...so that reference does not outlive \
1519 1520
                    borrowed content");
            }
1521 1522 1523
            infer::ReborrowUpvar(span, ref upvar_id) => {
                self.tcx.sess.span_note(
                    span,
1524 1525 1526 1527
                    format!(
                        "...so that closure can access `{}`",
                        ty::local_var_name_str(self.tcx, upvar_id.var_id)
                            .get()
1528
                            .to_string()).as_slice())
1529
            }
1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545
            infer::InfStackClosure(span) => {
                self.tcx.sess.span_note(
                    span,
                    "...so that closure does not outlive its stack frame");
            }
            infer::InvokeClosure(span) => {
                self.tcx.sess.span_note(
                    span,
                    "...so that closure is not invoked outside its lifetime");
            }
            infer::DerefPointer(span) => {
                self.tcx.sess.span_note(
                    span,
                    "...so that pointer is not dereferenced \
                    outside its lifetime");
            }
1546
            infer::FreeVariable(span, id) => {
1547 1548
                self.tcx.sess.span_note(
                    span,
1549 1550
                    format!("...so that captured variable `{}` \
                            does not outlive the enclosing closure",
1551 1552
                            ty::local_var_name_str(
                                self.tcx,
1553
                                id).get().to_string()).as_slice());
1554 1555 1556 1557 1558 1559 1560 1561 1562
            }
            infer::IndexSlice(span) => {
                self.tcx.sess.span_note(
                    span,
                    "...so that slice is not indexed outside the lifetime");
            }
            infer::RelateObjectBound(span) => {
                self.tcx.sess.span_note(
                    span,
1563 1564
                    "...so that it can be closed over into an object");
            }
1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582
            infer::CallRcvr(span) => {
                self.tcx.sess.span_note(
                    span,
                    "...so that method receiver is valid for the method call");
            }
            infer::CallArg(span) => {
                self.tcx.sess.span_note(
                    span,
                    "...so that argument is valid for the call");
            }
            infer::CallReturn(span) => {
                self.tcx.sess.span_note(
                    span,
                    "...so that return value is valid for the call");
            }
            infer::AddrOf(span) => {
                self.tcx.sess.span_note(
                    span,
1583
                    "...so that reference is valid \
1584 1585 1586 1587 1588
                     at the time of borrow");
            }
            infer::AutoBorrow(span) => {
                self.tcx.sess.span_note(
                    span,
1589 1590
                    "...so that auto-reference is valid \
                     at the time of borrow");
1591
            }
1592 1593 1594 1595 1596 1597 1598
            infer::ExprTypeIsNotInScope(t, span) => {
                self.tcx.sess.span_note(
                    span,
                    format!("...so type `{}` of expression is valid during the \
                             expression",
                            self.ty_to_string(t)).as_slice());
            }
1599 1600 1601 1602 1603
            infer::BindingTypeIsNotValidAtDecl(span) => {
                self.tcx.sess.span_note(
                    span,
                    "...so that variable is valid at time of its declaration");
            }
1604 1605 1606 1607 1608 1609 1610
            infer::ReferenceOutlivesReferent(ty, span) => {
                self.tcx.sess.span_note(
                    span,
                    format!("...so that the reference type `{}` \
                             does not outlive the data it points at",
                            self.ty_to_string(ty)).as_slice());
            }
1611
            infer::RelateParamBound(span, t) => {
1612 1613
                self.tcx.sess.span_note(
                    span,
1614
                    format!("...so that the type `{}` \
1615
                             will meet the declared lifetime bounds",
1616 1617 1618 1619 1620 1621 1622
                            self.ty_to_string(t)).as_slice());
            }
            infer::RelateDefaultParamBound(span, t) => {
                self.tcx.sess.span_note(
                    span,
                    format!("...so that type parameter \
                             instantiated with `{}`, \
1623
                             will meet its declared lifetime bounds",
1624 1625 1626
                            self.ty_to_string(t)).as_slice());
            }
            infer::RelateRegionParamBound(span) => {
1627 1628
                self.tcx.sess.span_note(
                    span,
1629 1630
                    format!("...so that the declared lifetime parameter bounds \
                                are satisfied").as_slice());
1631 1632
            }
        }
1633 1634 1635
    }
}

1636 1637
pub trait Resolvable<'tcx> {
    fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Self;
1638
    fn contains_error(&self) -> bool;
J
Jakub Bukaj 已提交
1639 1640
}

1641 1642
impl<'tcx> Resolvable<'tcx> for Ty<'tcx> {
    fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Ty<'tcx> {
J
Jakub Bukaj 已提交
1643 1644 1645 1646 1647 1648 1649
        infcx.resolve_type_vars_if_possible(*self)
    }
    fn contains_error(&self) -> bool {
        ty::type_is_error(*self)
    }
}

1650 1651 1652
impl<'tcx> Resolvable<'tcx> for Rc<ty::TraitRef<'tcx>> {
    fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>)
                   -> Rc<ty::TraitRef<'tcx>> {
E
Eduard Burtescu 已提交
1653
        Rc::new(infcx.resolve_type_vars_in_trait_ref_if_possible(&**self))
1654 1655
    }
    fn contains_error(&self) -> bool {
E
Eduard Burtescu 已提交
1656
        ty::trait_ref_contains_error(&**self)
1657 1658 1659
    }
}

1660 1661
fn lifetimes_in_scope(tcx: &ty::ctxt,
                      scope_id: ast::NodeId)
1662
                      -> Vec<ast::LifetimeDef> {
1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673
    let mut taken = Vec::new();
    let parent = tcx.map.get_parent(scope_id);
    let method_id_opt = match tcx.map.find(parent) {
        Some(node) => match node {
            ast_map::NodeItem(item) => match item.node {
                ast::ItemFn(_, _, _, ref gen, _) => {
                    taken.push_all(gen.lifetimes.as_slice());
                    None
                },
                _ => None
            },
1674 1675
            ast_map::NodeImplItem(ii) => {
                match *ii {
1676
                    ast::MethodImplItem(ref m) => {
1677 1678 1679
                        taken.push_all(m.pe_generics().lifetimes.as_slice());
                        Some(m.id)
                    }
1680
                    ast::TypeImplItem(_) => None,
1681 1682
                }
            }
1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705
            _ => None
        },
        None => None
    };
    if method_id_opt.is_some() {
        let method_id = method_id_opt.unwrap();
        let parent = tcx.map.get_parent(method_id);
        match tcx.map.find(parent) {
            Some(node) => match node {
                ast_map::NodeItem(item) => match item.node {
                    ast::ItemImpl(ref gen, _, _, _) => {
                        taken.push_all(gen.lifetimes.as_slice());
                    }
                    _ => ()
                },
                _ => ()
            },
            None => ()
        }
    }
    return taken;
}

1706 1707
// LifeGiver is responsible for generating fresh lifetime names
struct LifeGiver {
1708
    taken: HashSet<String>,
1709 1710 1711 1712 1713
    counter: Cell<uint>,
    generated: RefCell<Vec<ast::Lifetime>>,
}

impl LifeGiver {
1714
    fn with_taken(taken: &[ast::LifetimeDef]) -> LifeGiver {
1715 1716
        let mut taken_ = HashSet::new();
        for lt in taken.iter() {
1717
            let lt_name = token::get_name(lt.lifetime.name).get().to_string();
1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734
            taken_.insert(lt_name);
        }
        LifeGiver {
            taken: taken_,
            counter: Cell::new(0),
            generated: RefCell::new(Vec::new()),
        }
    }

    fn inc_counter(&self) {
        let c = self.counter.get();
        self.counter.set(c+1);
    }

    fn give_lifetime(&self) -> ast::Lifetime {
        let mut lifetime;
        loop {
1735
            let mut s = String::from_str("'");
1736
            s.push_str(num_to_string(self.counter.get()).as_slice());
1737 1738 1739
            if !self.taken.contains(&s) {
                lifetime = name_to_dummy_lifetime(
                                    token::str_to_ident(s.as_slice()).name);
1740
                self.generated.borrow_mut().push(lifetime);
1741 1742 1743 1744 1745 1746 1747 1748
                break;
            }
            self.inc_counter();
        }
        self.inc_counter();
        return lifetime;

        // 0 .. 25 generates a .. z, 26 .. 51 generates aa .. zz, and so on
1749
        fn num_to_string(counter: uint) -> String {
1750
            let mut s = String::new();
1751 1752 1753
            let (n, r) = (counter/26 + 1, counter % 26);
            let letter: char = from_u32((r+97) as u32).unwrap();
            for _ in range(0, n) {
1754
                s.push(letter);
1755
            }
1756
            s
1757 1758 1759 1760
        }
    }

    fn get_generated_lifetimes(&self) -> Vec<ast::Lifetime> {
E
Erick Tryzelaar 已提交
1761
        self.generated.borrow().clone()
1762 1763
    }
}