2013-05-23 21:37:37 -04:00
|
|
|
// 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.
|
|
|
|
|
2014-11-25 21:17:11 -05:00
|
|
|
//! 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
|
|
|
|
//!
|
2015-01-06 20:53:18 -05:00
|
|
|
//! Determining whether `T1 <: T2` often involves a number of subtypes and
|
2014-11-25 21:17:11 -05:00
|
|
|
//! 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.
|
|
|
|
|
2014-11-06 00:05:53 -08:00
|
|
|
use self::FreshOrKept::*;
|
2013-05-23 21:37:37 -04:00
|
|
|
|
2014-11-25 16:59:02 -05:00
|
|
|
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;
|
2015-01-03 04:40:33 -05:00
|
|
|
use super::region_inference::GenericBoundFailure;
|
|
|
|
use super::region_inference::GenericKind;
|
2014-11-25 16:59:02 -05:00
|
|
|
use super::region_inference::ProcessedErrors;
|
|
|
|
use super::region_inference::SameRegions;
|
|
|
|
|
2014-05-29 19:03:06 -07:00
|
|
|
use std::collections::HashSet;
|
2015-06-10 02:40:45 +03:00
|
|
|
use ast_map;
|
2014-05-14 15:31:30 -04:00
|
|
|
use middle::def;
|
2014-11-25 16:59:02 -05:00
|
|
|
use middle::infer;
|
2015-06-16 01:10:55 +03:00
|
|
|
use middle::region;
|
2014-05-31 18:53:13 -04:00
|
|
|
use middle::subst;
|
2015-07-10 15:40:04 -07:00
|
|
|
use middle::ty::{self, Ty, TypeError, HasTypeFlags};
|
2014-02-15 01:26:51 -05:00
|
|
|
use middle::ty::{Region, ReFree};
|
2015-06-18 20:25:05 +03:00
|
|
|
|
2014-02-15 01:26:51 -05:00
|
|
|
use std::cell::{Cell, RefCell};
|
|
|
|
use std::char::from_u32;
|
2015-06-18 20:25:05 +03:00
|
|
|
use std::fmt;
|
2014-02-15 01:26:51 -05:00
|
|
|
use syntax::ast;
|
2015-03-11 23:38:58 +02:00
|
|
|
use syntax::ast_util::name_to_dummy_lifetime;
|
2014-03-24 19:11:44 -04:00
|
|
|
use syntax::owned_slice::OwnedSlice;
|
2015-06-16 01:10:55 +03:00
|
|
|
use syntax::codemap::{Pos, Span};
|
2014-03-07 08:43:39 +01:00
|
|
|
use syntax::parse::token;
|
2014-02-15 01:26:51 -05:00
|
|
|
use syntax::print::pprust;
|
2014-09-07 20:09:06 +03:00
|
|
|
use syntax::ptr::P;
|
2013-05-23 21:37:37 -04:00
|
|
|
|
2015-06-25 23:42:17 +03:00
|
|
|
impl<'tcx> ty::ctxt<'tcx> {
|
|
|
|
pub fn note_and_explain_region(&self,
|
|
|
|
prefix: &str,
|
|
|
|
region: ty::Region,
|
|
|
|
suffix: &str) {
|
|
|
|
fn item_scope_tag(item: &ast::Item) -> &'static str {
|
|
|
|
match item.node {
|
|
|
|
ast::ItemImpl(..) => "impl",
|
|
|
|
ast::ItemStruct(..) => "struct",
|
|
|
|
ast::ItemEnum(..) => "enum",
|
|
|
|
ast::ItemTrait(..) => "trait",
|
|
|
|
ast::ItemFn(..) => "function body",
|
|
|
|
_ => "item"
|
|
|
|
}
|
2015-06-16 01:10:55 +03:00
|
|
|
}
|
|
|
|
|
2015-06-25 23:42:17 +03:00
|
|
|
fn explain_span(tcx: &ty::ctxt, heading: &str, span: Span)
|
|
|
|
-> (String, Option<Span>) {
|
|
|
|
let lo = tcx.sess.codemap().lookup_char_pos_adj(span.lo);
|
|
|
|
(format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize()),
|
|
|
|
Some(span))
|
2015-06-16 01:10:55 +03:00
|
|
|
}
|
|
|
|
|
2015-06-25 23:42:17 +03:00
|
|
|
let (description, span) = match region {
|
|
|
|
ty::ReScope(scope) => {
|
|
|
|
let new_string;
|
|
|
|
let unknown_scope = || {
|
|
|
|
format!("{}unknown scope: {:?}{}. Please report a bug.",
|
|
|
|
prefix, scope, suffix)
|
|
|
|
};
|
|
|
|
let span = match scope.span(&self.map) {
|
|
|
|
Some(s) => s,
|
|
|
|
None => return self.sess.note(&unknown_scope())
|
|
|
|
};
|
|
|
|
let tag = match self.map.find(scope.node_id()) {
|
|
|
|
Some(ast_map::NodeBlock(_)) => "block",
|
|
|
|
Some(ast_map::NodeExpr(expr)) => match expr.node {
|
|
|
|
ast::ExprCall(..) => "call",
|
|
|
|
ast::ExprMethodCall(..) => "method call",
|
|
|
|
ast::ExprMatch(_, _, ast::MatchSource::IfLetDesugar { .. }) => "if let",
|
|
|
|
ast::ExprMatch(_, _, ast::MatchSource::WhileLetDesugar) => "while let",
|
|
|
|
ast::ExprMatch(_, _, ast::MatchSource::ForLoopDesugar) => "for",
|
|
|
|
ast::ExprMatch(..) => "match",
|
|
|
|
_ => "expression",
|
|
|
|
},
|
|
|
|
Some(ast_map::NodeStmt(_)) => "statement",
|
|
|
|
Some(ast_map::NodeItem(it)) => item_scope_tag(&*it),
|
|
|
|
Some(_) | None => {
|
|
|
|
return self.sess.span_note(span, &unknown_scope());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let scope_decorated_tag = match scope {
|
|
|
|
region::CodeExtent::Misc(_) => tag,
|
|
|
|
region::CodeExtent::ParameterScope { .. } => {
|
|
|
|
"scope of parameters for function"
|
|
|
|
}
|
|
|
|
region::CodeExtent::DestructionScope(_) => {
|
|
|
|
new_string = format!("destruction scope surrounding {}", tag);
|
|
|
|
&new_string[..]
|
|
|
|
}
|
|
|
|
region::CodeExtent::Remainder(r) => {
|
|
|
|
new_string = format!("block suffix following statement {}",
|
|
|
|
r.first_statement_index);
|
|
|
|
&new_string[..]
|
|
|
|
}
|
|
|
|
};
|
|
|
|
explain_span(self, scope_decorated_tag, span)
|
|
|
|
}
|
2015-06-16 01:10:55 +03:00
|
|
|
|
2015-06-25 23:42:17 +03:00
|
|
|
ty::ReFree(ref fr) => {
|
|
|
|
let prefix = match fr.bound_region {
|
|
|
|
ty::BrAnon(idx) => {
|
|
|
|
format!("the anonymous lifetime #{} defined on", idx + 1)
|
|
|
|
}
|
|
|
|
ty::BrFresh(_) => "an anonymous lifetime defined on".to_owned(),
|
|
|
|
_ => {
|
|
|
|
format!("the lifetime {} as defined on",
|
|
|
|
fr.bound_region)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
match self.map.find(fr.scope.node_id) {
|
|
|
|
Some(ast_map::NodeBlock(ref blk)) => {
|
|
|
|
let (msg, opt_span) = explain_span(self, "block", blk.span);
|
|
|
|
(format!("{} {}", prefix, msg), opt_span)
|
|
|
|
}
|
|
|
|
Some(ast_map::NodeItem(it)) => {
|
|
|
|
let tag = item_scope_tag(&*it);
|
|
|
|
let (msg, opt_span) = explain_span(self, tag, it.span);
|
|
|
|
(format!("{} {}", prefix, msg), opt_span)
|
|
|
|
}
|
|
|
|
Some(_) | None => {
|
|
|
|
// this really should not happen
|
|
|
|
(format!("{} unknown free region bounded by scope {:?}",
|
|
|
|
prefix, fr.scope), None)
|
|
|
|
}
|
2015-06-16 01:10:55 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-25 23:42:17 +03:00
|
|
|
ty::ReStatic => ("the static lifetime".to_owned(), None),
|
2015-06-16 01:10:55 +03:00
|
|
|
|
2015-06-25 23:42:17 +03:00
|
|
|
ty::ReEmpty => ("the empty lifetime".to_owned(), None),
|
2015-06-16 01:10:55 +03:00
|
|
|
|
2015-06-25 23:42:17 +03:00
|
|
|
ty::ReEarlyBound(ref data) => {
|
|
|
|
(format!("{}", token::get_name(data.name)), None)
|
|
|
|
}
|
2015-06-16 01:10:55 +03:00
|
|
|
|
2015-06-25 23:42:17 +03:00
|
|
|
// I believe these cases should not occur (except when debugging,
|
|
|
|
// perhaps)
|
|
|
|
ty::ReInfer(_) | ty::ReLateBound(..) => {
|
|
|
|
(format!("lifetime {:?}", region), None)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let message = format!("{}{}{}", prefix, description, suffix);
|
|
|
|
if let Some(span) = span {
|
|
|
|
self.sess.span_note(span, &message);
|
|
|
|
} else {
|
|
|
|
self.sess.note(&message);
|
2015-06-16 01:10:55 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
pub trait ErrorReporting<'tcx> {
|
2014-02-07 00:38:33 +02:00
|
|
|
fn report_region_errors(&self,
|
2014-09-29 22:11:30 +03:00
|
|
|
errors: &Vec<RegionResolutionError<'tcx>>);
|
2013-07-01 20:43:42 -04:00
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
fn process_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>)
|
|
|
|
-> Vec<RegionResolutionError<'tcx>>;
|
2014-02-15 01:26:51 -05:00
|
|
|
|
2015-07-08 12:27:32 -07:00
|
|
|
fn report_type_error(&self, trace: TypeTrace<'tcx>, terr: &ty::TypeError<'tcx>);
|
2014-02-15 01:26:51 -05:00
|
|
|
|
2014-02-07 00:38:33 +02:00
|
|
|
fn report_and_explain_type_error(&self,
|
2014-09-29 22:11:30 +03:00
|
|
|
trace: TypeTrace<'tcx>,
|
2015-07-08 12:27:32 -07:00
|
|
|
terr: &ty::TypeError<'tcx>);
|
2013-07-01 20:43:42 -04:00
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<String>;
|
2013-07-01 20:43:42 -04:00
|
|
|
|
2015-06-24 02:54:32 +03:00
|
|
|
fn expected_found_str<T: fmt::Display + Resolvable<'tcx> + HasTypeFlags>(
|
2014-02-07 00:38:33 +02:00
|
|
|
&self,
|
2015-07-08 12:27:32 -07:00
|
|
|
exp_found: &ty::ExpectedFound<T>)
|
2014-05-22 16:57:53 -07:00
|
|
|
-> Option<String>;
|
2013-07-01 20:43:42 -04:00
|
|
|
|
2014-02-07 00:38:33 +02:00
|
|
|
fn report_concrete_failure(&self,
|
2014-09-29 22:11:30 +03:00
|
|
|
origin: SubregionOrigin<'tcx>,
|
2013-07-01 20:43:42 -04:00
|
|
|
sub: Region,
|
|
|
|
sup: Region);
|
|
|
|
|
2015-01-03 04:40:33 -05:00
|
|
|
fn report_generic_bound_failure(&self,
|
|
|
|
origin: SubregionOrigin<'tcx>,
|
|
|
|
kind: GenericKind<'tcx>,
|
|
|
|
sub: Region,
|
|
|
|
sups: Vec<Region>);
|
2014-08-27 21:46:52 -04:00
|
|
|
|
2014-02-07 00:38:33 +02:00
|
|
|
fn report_sub_sup_conflict(&self,
|
2013-07-01 20:43:42 -04:00
|
|
|
var_origin: RegionVariableOrigin,
|
2014-09-29 22:11:30 +03:00
|
|
|
sub_origin: SubregionOrigin<'tcx>,
|
2013-07-01 20:43:42 -04:00
|
|
|
sub_region: Region,
|
2014-09-29 22:11:30 +03:00
|
|
|
sup_origin: SubregionOrigin<'tcx>,
|
2013-07-01 20:43:42 -04:00
|
|
|
sup_region: Region);
|
|
|
|
|
2014-02-07 00:38:33 +02:00
|
|
|
fn report_sup_sup_conflict(&self,
|
2013-07-01 20:43:42 -04:00
|
|
|
var_origin: RegionVariableOrigin,
|
2014-09-29 22:11:30 +03:00
|
|
|
origin1: SubregionOrigin<'tcx>,
|
2013-07-01 20:43:42 -04:00
|
|
|
region1: Region,
|
2014-09-29 22:11:30 +03:00
|
|
|
origin2: SubregionOrigin<'tcx>,
|
2013-07-01 20:43:42 -04:00
|
|
|
region2: Region);
|
2014-02-15 01:26:51 -05:00
|
|
|
|
|
|
|
fn report_processed_errors(&self,
|
|
|
|
var_origin: &[RegionVariableOrigin],
|
2015-07-08 12:27:32 -07:00
|
|
|
trace_origin: &[(TypeTrace<'tcx>, ty::TypeError<'tcx>)],
|
2014-02-15 01:26:51 -05:00
|
|
|
same_regions: &[SameRegions]);
|
|
|
|
|
|
|
|
fn give_suggestion(&self, same_regions: &[SameRegions]);
|
2013-07-01 20:43:42 -04:00
|
|
|
}
|
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
trait ErrorReportingHelpers<'tcx> {
|
2014-02-07 00:38:33 +02:00
|
|
|
fn report_inference_failure(&self,
|
2013-10-29 06:12:50 -04:00
|
|
|
var_origin: RegionVariableOrigin);
|
|
|
|
|
2014-02-07 00:38:33 +02:00
|
|
|
fn note_region_origin(&self,
|
2014-09-29 22:11:30 +03:00
|
|
|
origin: &SubregionOrigin<'tcx>);
|
2014-02-15 01:26:51 -05:00
|
|
|
|
|
|
|
fn give_expl_lifetime_param(&self,
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
decl: &ast::FnDecl,
|
2014-12-09 10:36:46 -05:00
|
|
|
unsafety: ast::Unsafety,
|
2015-02-25 22:05:07 +02:00
|
|
|
constness: ast::Constness,
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
ident: ast::Ident,
|
2014-09-07 20:09:06 +03:00
|
|
|
opt_explicit_self: Option<&ast::ExplicitSelf_>,
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
generics: &ast::Generics,
|
2015-06-16 01:10:55 +03:00
|
|
|
span: Span);
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
2013-07-01 20:43:42 -04:00
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
|
2014-02-07 00:38:33 +02:00
|
|
|
fn report_region_errors(&self,
|
2014-09-29 22:11:30 +03:00
|
|
|
errors: &Vec<RegionResolutionError<'tcx>>) {
|
2014-02-15 01:26:51 -05:00
|
|
|
let p_errors = self.process_errors(errors);
|
|
|
|
let errors = if p_errors.is_empty() { errors } else { &p_errors };
|
2015-01-31 12:20:46 -05:00
|
|
|
for error in errors {
|
2014-04-22 02:21:52 +03:00
|
|
|
match error.clone() {
|
2013-05-23 21:37:37 -04:00
|
|
|
ConcreteFailure(origin, sub, sup) => {
|
|
|
|
self.report_concrete_failure(origin, sub, sup);
|
|
|
|
}
|
|
|
|
|
2015-01-03 04:40:33 -05:00
|
|
|
GenericBoundFailure(kind, param_ty, sub, sups) => {
|
|
|
|
self.report_generic_bound_failure(kind, param_ty, sub, sups);
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
|
|
|
|
2013-05-23 21:37:37 -04:00
|
|
|
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);
|
|
|
|
}
|
2014-02-15 01:26:51 -05:00
|
|
|
|
|
|
|
ProcessedErrors(ref var_origins,
|
|
|
|
ref trace_origins,
|
|
|
|
ref same_regions) => {
|
|
|
|
if !same_regions.is_empty() {
|
2015-02-18 14:48:57 -05:00
|
|
|
self.report_processed_errors(&var_origins[..],
|
|
|
|
&trace_origins[..],
|
|
|
|
&same_regions[..]);
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
}
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-15 01:26:51 -05:00
|
|
|
// 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)
|
2014-09-29 22:11:30 +03:00
|
|
|
fn process_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>)
|
|
|
|
-> Vec<RegionResolutionError<'tcx>> {
|
2014-03-22 04:24:42 -04:00
|
|
|
debug!("process_errors()");
|
2014-02-15 01:26:51 -05:00
|
|
|
let mut var_origins = Vec::new();
|
|
|
|
let mut trace_origins = Vec::new();
|
|
|
|
let mut same_regions = Vec::new();
|
2014-03-19 23:16:56 +11:00
|
|
|
let mut processed_errors = Vec::new();
|
2015-01-31 12:20:46 -05:00
|
|
|
for error in errors {
|
2014-04-22 02:21:52 +03:00
|
|
|
match error.clone() {
|
2014-02-15 01:26:51 -05:00
|
|
|
ConcreteFailure(origin, sub, sup) => {
|
2014-11-14 09:18:10 -08:00
|
|
|
debug!("processing ConcreteFailure");
|
2014-02-15 01:26:51 -05:00
|
|
|
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();
|
2015-07-10 15:40:04 -07:00
|
|
|
let terr = TypeError::RegionsDoesNotOutlive(sup,
|
|
|
|
sub);
|
2014-02-15 01:26:51 -05:00
|
|
|
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) => {
|
2014-10-27 12:55:16 +01:00
|
|
|
debug!("processing SubSupConflict sub: {:?} sup: {:?}", sub_r, sup_r);
|
2014-02-15 01:26:51 -05:00
|
|
|
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() {
|
2014-10-14 23:05:01 -07:00
|
|
|
let common_scope_id = same_regions[0].scope_id;
|
2015-01-31 12:20:46 -05:00
|
|
|
for sr in &same_regions {
|
2014-02-15 01:26:51 -05:00
|
|
|
// 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 {
|
2014-03-22 04:24:42 -04:00
|
|
|
debug!("returning empty result from process_errors because
|
|
|
|
{} != {}", sr.scope_id, common_scope_id);
|
2014-03-19 23:16:56 +11:00
|
|
|
return vec!();
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
let pe = ProcessedErrors(var_origins, trace_origins, same_regions);
|
2014-12-20 00:09:35 -08:00
|
|
|
debug!("errors processed: {:?}", pe);
|
2014-02-15 01:26:51 -05:00
|
|
|
processed_errors.push(pe);
|
|
|
|
}
|
|
|
|
return processed_errors;
|
|
|
|
|
|
|
|
|
|
|
|
struct FreeRegionsFromSameFn {
|
|
|
|
sub_fr: ty::FreeRegion,
|
|
|
|
sup_fr: ty::FreeRegion,
|
|
|
|
scope_id: ast::NodeId
|
|
|
|
}
|
|
|
|
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-06 05:07:47 +02:00
|
|
|
fn free_regions_from_same_fn(tcx: &ty::ctxt,
|
2014-02-15 01:26:51 -05:00
|
|
|
sub: Region,
|
|
|
|
sup: Region)
|
|
|
|
-> Option<FreeRegionsFromSameFn> {
|
2014-12-20 00:09:35 -08:00
|
|
|
debug!("free_regions_from_same_fn(sub={:?}, sup={:?})", sub, sup);
|
2014-02-15 01:26:51 -05:00
|
|
|
let (scope_id, fr1, fr2) = match (sub, sup) {
|
|
|
|
(ReFree(fr1), ReFree(fr2)) => {
|
2014-11-18 14:22:59 +01:00
|
|
|
if fr1.scope != fr2.scope {
|
2014-02-15 01:26:51 -05:00
|
|
|
return None
|
|
|
|
}
|
2014-11-18 14:22:59 +01:00
|
|
|
assert!(fr1.scope == fr2.scope);
|
Added DestructionScope variant to CodeExtent, representing the area
immediately surrounding a node that is a terminating_scope
(e.g. statements, looping forms) during which the destructors run (the
destructors for temporaries from the execution of that node, that is).
Introduced DestructionScopeData newtype wrapper around ast::NodeId, to
preserve invariant that FreeRegion and ScopeChain::BlockScope carry
destruction scopes (rather than arbitrary CodeExtents).
Insert DestructionScope and block Remainder into enclosing CodeExtents
hierarchy.
Add more doc for DestructionScope, complete with ASCII art.
Switch to constructing DestructionScope rather than Misc in a number
of places, mostly related to `ty::ReFree` creation, and use
destruction-scopes of node-ids at various calls to
liberate_late_bound_regions.
middle::resolve_lifetime: Map BlockScope to DestructionScope in `fn resolve_free_lifetime`.
Add the InnermostDeclaringBlock and InnermostEnclosingExpr enums that
are my attempt to clarify the region::Context structure, and that
later commmts build upon.
Improve the debug output for `CodeExtent` attached to `ty::Region::ReScope`.
Loosened an assertion in `rustc_trans::trans::cleanup` to account for
`DestructionScope`. (Perhaps this should just be switched entirely
over to `DestructionScope`, rather than allowing for either `Misc` or
`DestructionScope`.)
----
Even though the DestructionScope is new, this particular commit should
not actually change the semantics of any current code.
2014-11-25 17:02:20 +01:00
|
|
|
(fr1.scope.node_id, fr1, fr2)
|
2014-02-15 01:26:51 -05:00
|
|
|
},
|
|
|
|
_ => 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(..) => {
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
Some(FreeRegionsFromSameFn::new(fr1, fr2, scope_id))
|
2014-02-15 01:26:51 -05:00
|
|
|
},
|
|
|
|
_ => None
|
|
|
|
},
|
2014-08-04 13:56:56 -07:00
|
|
|
ast_map::NodeImplItem(..) |
|
|
|
|
ast_map::NodeTraitItem(..) => {
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
Some(FreeRegionsFromSameFn::new(fr1, fr2, scope_id))
|
|
|
|
},
|
2014-02-15 01:26:51 -05:00
|
|
|
_ => None
|
|
|
|
},
|
2014-03-22 04:24:42 -04:00
|
|
|
None => {
|
2014-11-14 09:18:10 -08:00
|
|
|
debug!("no parent node of scope_id {}", scope_id);
|
2014-03-22 04:24:42 -04:00
|
|
|
None
|
|
|
|
}
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2015-01-31 20:02:00 -05:00
|
|
|
for sr in &mut *same_regions {
|
2014-02-15 01:26:51 -05:00
|
|
|
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)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-08 12:27:32 -07:00
|
|
|
fn report_type_error(&self, trace: TypeTrace<'tcx>, terr: &ty::TypeError<'tcx>) {
|
2013-05-23 21:37:37 -04:00
|
|
|
let expected_found_str = match self.values_str(&trace.values) {
|
|
|
|
Some(v) => v,
|
|
|
|
None => {
|
|
|
|
return; /* derived error */
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-01-18 16:58:25 -08:00
|
|
|
span_err!(self.tcx.sess, trace.origin.span(), E0308,
|
|
|
|
"{}: {} ({})",
|
2015-03-19 14:49:28 -07:00
|
|
|
trace.origin,
|
2013-05-23 21:37:37 -04:00
|
|
|
expected_found_str,
|
2015-06-18 08:51:23 +03:00
|
|
|
terr);
|
2014-05-31 00:16:33 +02:00
|
|
|
|
|
|
|
match trace.origin {
|
|
|
|
infer::MatchExpressionArm(_, arm_span) =>
|
|
|
|
self.tcx.sess.span_note(arm_span, "match arm with an incompatible type"),
|
|
|
|
_ => ()
|
|
|
|
}
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2013-05-23 21:37:37 -04:00
|
|
|
|
2014-02-15 01:26:51 -05:00
|
|
|
fn report_and_explain_type_error(&self,
|
2014-09-29 22:11:30 +03:00
|
|
|
trace: TypeTrace<'tcx>,
|
2015-07-08 12:27:32 -07:00
|
|
|
terr: &ty::TypeError<'tcx>) {
|
2015-04-04 14:30:23 -06:00
|
|
|
let span = trace.origin.span();
|
2014-02-15 01:26:51 -05:00
|
|
|
self.report_type_error(trace, terr);
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_type_err(terr, span);
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
|
|
|
|
2014-11-25 21:17:11 -05:00
|
|
|
/// Returns a string of the form "expected `{}`, found `{}`", or None if this is a derived
|
|
|
|
/// error.
|
2014-09-29 22:11:30 +03:00
|
|
|
fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<String> {
|
2013-05-23 21:37:37 -04:00
|
|
|
match *values {
|
Improve the readability of diagnostics that involve unresolved type variables
Diagnostics such as the following
```
mismatched types: expected `core::result::Result<uint,()>`, found `core::option::Option<<generic #1>>`
<anon>:6 let a: Result<uint, ()> = None;
^~~~
mismatched types: expected `&mut <generic #2>`, found `uint`
<anon>:7 f(42u);
^~~
```
tend to be fairly unappealing to new users. While specific type var IDs are valuable in
diagnostics that deal with more than one such variable, in practice many messages
only mention one. In those cases, leaving out the specific number makes the messages
slightly less terrifying.
In addition, type variables have been changed to use the type hole syntax `_` in diagnostics.
With a variable ID, they're printed as `_#id` (e.g. `_#1`). In cases where the ID is left out,
it's simply `_`. Integer and float variables have an additional suffix after the number, e.g.
`_#1i` or `_#3f`.
2014-10-23 22:35:19 +02:00
|
|
|
infer::Types(ref exp_found) => self.expected_found_str(exp_found),
|
2014-12-14 07:17:23 -05:00
|
|
|
infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found),
|
|
|
|
infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found)
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-24 02:54:32 +03:00
|
|
|
fn expected_found_str<T: fmt::Display + Resolvable<'tcx> + HasTypeFlags>(
|
2014-02-07 00:38:33 +02:00
|
|
|
&self,
|
2015-07-08 12:27:32 -07:00
|
|
|
exp_found: &ty::ExpectedFound<T>)
|
2014-05-22 16:57:53 -07:00
|
|
|
-> Option<String>
|
2013-05-23 21:37:37 -04:00
|
|
|
{
|
|
|
|
let expected = exp_found.expected.resolve(self);
|
2015-06-24 02:54:32 +03:00
|
|
|
if expected.references_error() {
|
2013-05-23 21:37:37 -04:00
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
let found = exp_found.found.resolve(self);
|
2015-06-24 02:54:32 +03:00
|
|
|
if found.references_error() {
|
2013-05-23 21:37:37 -04:00
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2014-08-23 12:41:32 +02:00
|
|
|
Some(format!("expected `{}`, found `{}`",
|
2015-06-18 20:25:05 +03:00
|
|
|
expected,
|
|
|
|
found))
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
|
|
|
|
2015-01-03 04:40:33 -05:00
|
|
|
fn report_generic_bound_failure(&self,
|
|
|
|
origin: SubregionOrigin<'tcx>,
|
|
|
|
bound_kind: GenericKind<'tcx>,
|
|
|
|
sub: Region,
|
|
|
|
_sups: Vec<Region>)
|
|
|
|
{
|
2014-08-27 21:46:52 -04:00
|
|
|
// 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.
|
|
|
|
|
2015-01-03 04:40:33 -05:00
|
|
|
let labeled_user_string = match bound_kind {
|
|
|
|
GenericKind::Param(ref p) =>
|
2015-06-18 20:25:05 +03:00
|
|
|
format!("the parameter type `{}`", p),
|
2015-01-03 04:40:33 -05:00
|
|
|
GenericKind::Projection(ref p) =>
|
2015-06-18 20:25:05 +03:00
|
|
|
format!("the associated type `{}`", p),
|
2015-01-03 04:40:33 -05:00
|
|
|
};
|
|
|
|
|
2014-08-27 21:46:52 -04:00
|
|
|
match sub {
|
|
|
|
ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
|
|
|
|
// Does the required lifetime have a nice name we can print?
|
2015-01-18 16:58:25 -08:00
|
|
|
span_err!(self.tcx.sess, origin.span(), E0309,
|
|
|
|
"{} may not live long enough", labeled_user_string);
|
2015-02-24 16:07:54 +02:00
|
|
|
self.tcx.sess.fileline_help(
|
2014-10-18 15:39:44 +13:00
|
|
|
origin.span(),
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!(
|
2014-10-18 15:39:44 +13:00
|
|
|
"consider adding an explicit lifetime bound `{}: {}`...",
|
2015-06-18 20:25:05 +03:00
|
|
|
bound_kind,
|
|
|
|
sub));
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
ty::ReStatic => {
|
|
|
|
// Does the required lifetime have a nice name we can print?
|
2015-01-18 16:58:25 -08:00
|
|
|
span_err!(self.tcx.sess, origin.span(), E0310,
|
|
|
|
"{} may not live long enough", labeled_user_string);
|
2015-02-24 16:07:54 +02:00
|
|
|
self.tcx.sess.fileline_help(
|
2014-10-18 15:39:44 +13:00
|
|
|
origin.span(),
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!(
|
2014-10-18 15:39:44 +13:00
|
|
|
"consider adding an explicit lifetime bound `{}: 'static`...",
|
2015-06-18 20:25:05 +03:00
|
|
|
bound_kind));
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
_ => {
|
|
|
|
// If not, be less specific.
|
2015-01-18 16:58:25 -08:00
|
|
|
span_err!(self.tcx.sess, origin.span(), E0311,
|
2015-01-03 04:40:33 -05:00
|
|
|
"{} may not live long enough",
|
2015-01-18 16:58:25 -08:00
|
|
|
labeled_user_string);
|
2015-02-24 16:07:54 +02:00
|
|
|
self.tcx.sess.fileline_help(
|
2014-10-18 15:39:44 +13:00
|
|
|
origin.span(),
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!(
|
2015-01-03 04:40:33 -05:00
|
|
|
"consider adding an explicit lifetime bound for `{}`",
|
2015-06-18 20:25:05 +03:00
|
|
|
bound_kind));
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2015-02-20 14:08:14 -05:00
|
|
|
&format!("{} must be valid for ", labeled_user_string),
|
2014-08-27 21:46:52 -04:00
|
|
|
sub,
|
|
|
|
"...");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.note_region_origin(&origin);
|
|
|
|
}
|
|
|
|
|
2014-02-07 00:38:33 +02:00
|
|
|
fn report_concrete_failure(&self,
|
2014-09-29 22:11:30 +03:00
|
|
|
origin: SubregionOrigin<'tcx>,
|
2013-05-23 21:37:37 -04:00
|
|
|
sub: Region,
|
|
|
|
sup: Region) {
|
|
|
|
match origin {
|
2015-07-14 19:36:15 -04:00
|
|
|
infer::Subtype(trace) => {
|
2015-07-10 15:40:04 -07:00
|
|
|
let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
|
2013-05-23 21:37:37 -04:00
|
|
|
self.report_and_explain_type_error(trace, &terr);
|
|
|
|
}
|
|
|
|
infer::Reborrow(span) => {
|
2015-01-18 16:58:25 -08:00
|
|
|
span_err!(self.tcx.sess, span, E0312,
|
2014-01-07 18:49:13 -08:00
|
|
|
"lifetime of reference outlines \
|
2013-05-23 21:37:37 -04:00
|
|
|
lifetime of borrowed content...");
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2014-01-07 18:49:13 -08:00
|
|
|
"...the reference is valid for ",
|
2013-05-23 21:37:37 -04:00
|
|
|
sub,
|
|
|
|
"...");
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2013-05-23 21:37:37 -04:00
|
|
|
"...but the borrowed content is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
|
|
|
}
|
2014-02-07 14:43:48 -05:00
|
|
|
infer::ReborrowUpvar(span, ref upvar_id) => {
|
2015-01-18 16:58:25 -08:00
|
|
|
span_err!(self.tcx.sess, span, E0313,
|
|
|
|
"lifetime of borrowed pointer outlives \
|
2014-02-07 14:43:48 -05:00
|
|
|
lifetime of captured variable `{}`...",
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.local_var_name_str(upvar_id.var_id));
|
|
|
|
self.tcx.note_and_explain_region(
|
2014-02-07 14:43:48 -05:00
|
|
|
"...the borrowed pointer is valid for ",
|
|
|
|
sub,
|
|
|
|
"...");
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!("...but `{}` is only valid for ",
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.local_var_name_str(upvar_id.var_id)),
|
2014-02-07 14:43:48 -05:00
|
|
|
sup,
|
|
|
|
"");
|
|
|
|
}
|
2013-06-25 12:04:50 -04:00
|
|
|
infer::InfStackClosure(span) => {
|
2015-01-18 16:58:25 -08:00
|
|
|
span_err!(self.tcx.sess, span, E0314,
|
2013-06-25 12:04:50 -04:00
|
|
|
"closure outlives stack frame");
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2013-06-25 12:04:50 -04:00
|
|
|
"...the closure must be valid for ",
|
|
|
|
sub,
|
|
|
|
"...");
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2013-06-25 12:04:50 -04:00
|
|
|
"...but the closure's stack frame is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
|
|
|
}
|
2013-05-23 21:37:37 -04:00
|
|
|
infer::InvokeClosure(span) => {
|
2015-01-18 16:58:25 -08:00
|
|
|
span_err!(self.tcx.sess, span, E0315,
|
2013-05-23 21:37:37 -04:00
|
|
|
"cannot invoke closure outside of its lifetime");
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2013-05-23 21:37:37 -04:00
|
|
|
"the closure is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
|
|
|
}
|
|
|
|
infer::DerefPointer(span) => {
|
|
|
|
self.tcx.sess.span_err(
|
|
|
|
span,
|
|
|
|
"dereference of reference outside its lifetime");
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2013-05-23 21:37:37 -04:00
|
|
|
"the reference is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
|
|
|
}
|
2014-02-07 14:43:48 -05:00
|
|
|
infer::FreeVariable(span, id) => {
|
2013-05-23 21:37:37 -04:00
|
|
|
self.tcx.sess.span_err(
|
|
|
|
span,
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!("captured variable `{}` does not \
|
2015-06-25 23:42:17 +03:00
|
|
|
outlive the enclosing closure",
|
|
|
|
self.tcx.local_var_name_str(id)));
|
|
|
|
self.tcx.note_and_explain_region(
|
2013-05-23 21:37:37 -04:00
|
|
|
"captured variable is valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2013-05-23 21:37:37 -04:00
|
|
|
"closure is valid for ",
|
|
|
|
sub,
|
|
|
|
"");
|
|
|
|
}
|
|
|
|
infer::IndexSlice(span) => {
|
2014-05-16 10:45:16 -07:00
|
|
|
self.tcx.sess.span_err(span,
|
|
|
|
"index of slice outside its lifetime");
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2013-05-23 21:37:37 -04:00
|
|
|
"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");
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2013-05-23 21:37:37 -04:00
|
|
|
"object type is valid for ",
|
|
|
|
sub,
|
|
|
|
"");
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2013-05-23 21:37:37 -04:00
|
|
|
"source pointer is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
|
|
|
}
|
2014-11-15 17:25:05 -05:00
|
|
|
infer::RelateParamBound(span, ty) => {
|
2014-08-27 21:46:52 -04:00
|
|
|
self.tcx.sess.span_err(
|
|
|
|
span,
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!("the type `{}` does not fulfill the \
|
2014-08-27 21:46:52 -04:00
|
|
|
required lifetime",
|
2015-02-20 14:08:14 -05:00
|
|
|
self.ty_to_string(ty)));
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2014-08-27 21:46:52 -04:00
|
|
|
"type must outlive ",
|
|
|
|
sub,
|
|
|
|
"");
|
|
|
|
}
|
|
|
|
infer::RelateRegionParamBound(span) => {
|
|
|
|
self.tcx.sess.span_err(
|
|
|
|
span,
|
2015-02-16 11:58:47 -05:00
|
|
|
"lifetime bound not satisfied");
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2014-08-27 21:46:52 -04:00
|
|
|
"lifetime parameter instantiated with ",
|
|
|
|
sup,
|
|
|
|
"");
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2014-08-27 21:46:52 -04:00
|
|
|
"but lifetime parameter must outlive ",
|
|
|
|
sub,
|
|
|
|
"");
|
|
|
|
}
|
|
|
|
infer::RelateDefaultParamBound(span, ty) => {
|
|
|
|
self.tcx.sess.span_err(
|
|
|
|
span,
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!("the type `{}` (provided as the value of \
|
2014-08-27 21:46:52 -04:00
|
|
|
a type parameter) is not valid at this point",
|
2015-02-20 14:08:14 -05:00
|
|
|
self.ty_to_string(ty)));
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2014-08-27 21:46:52 -04:00
|
|
|
"type must outlive ",
|
|
|
|
sub,
|
|
|
|
"");
|
|
|
|
}
|
2013-05-23 21:37:37 -04:00
|
|
|
infer::CallRcvr(span) => {
|
|
|
|
self.tcx.sess.span_err(
|
|
|
|
span,
|
|
|
|
"lifetime of method receiver does not outlive \
|
|
|
|
the method call");
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2013-05-23 21:37:37 -04:00
|
|
|
"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");
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2013-05-23 21:37:37 -04:00
|
|
|
"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");
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2013-05-23 21:37:37 -04:00
|
|
|
"the return value is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
|
|
|
}
|
2015-02-12 12:48:54 -05:00
|
|
|
infer::Operand(span) => {
|
|
|
|
self.tcx.sess.span_err(
|
|
|
|
span,
|
|
|
|
"lifetime of operand does not outlive \
|
|
|
|
the operation");
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2015-02-12 12:48:54 -05:00
|
|
|
"the operand is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
|
|
|
}
|
2013-05-23 21:37:37 -04:00
|
|
|
infer::AddrOf(span) => {
|
|
|
|
self.tcx.sess.span_err(
|
|
|
|
span,
|
2014-01-07 18:49:13 -08:00
|
|
|
"reference is not valid \
|
2013-05-23 21:37:37 -04:00
|
|
|
at the time of borrow");
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2013-05-23 21:37:37 -04:00
|
|
|
"the borrow is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
|
|
|
}
|
|
|
|
infer::AutoBorrow(span) => {
|
|
|
|
self.tcx.sess.span_err(
|
|
|
|
span,
|
2014-01-07 18:49:13 -08:00
|
|
|
"automatically reference is not valid \
|
2013-05-23 21:37:37 -04:00
|
|
|
at the time of borrow");
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2013-05-23 21:37:37 -04:00
|
|
|
"the automatic borrow is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
|
|
|
}
|
2014-08-27 21:46:52 -04:00
|
|
|
infer::ExprTypeIsNotInScope(t, span) => {
|
|
|
|
self.tcx.sess.span_err(
|
|
|
|
span,
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!("type of expression contains references \
|
2014-08-27 21:46:52 -04:00
|
|
|
that are not valid during the expression: `{}`",
|
2015-02-20 14:08:14 -05:00
|
|
|
self.ty_to_string(t)));
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2014-08-27 21:46:52 -04:00
|
|
|
"type is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
|
|
|
}
|
2014-10-27 12:55:16 +01:00
|
|
|
infer::SafeDestructor(span) => {
|
|
|
|
self.tcx.sess.span_err(
|
|
|
|
span,
|
|
|
|
"unsafe use of destructor: destructor might be called \
|
|
|
|
while references are dead");
|
|
|
|
// FIXME (22171): terms "super/subregion" are suboptimal
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2014-10-27 12:55:16 +01:00
|
|
|
"superregion: ",
|
|
|
|
sup,
|
|
|
|
"");
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2014-10-27 12:55:16 +01:00
|
|
|
"subregion: ",
|
|
|
|
sub,
|
|
|
|
"");
|
|
|
|
}
|
2013-05-23 21:37:37 -04:00
|
|
|
infer::BindingTypeIsNotValidAtDecl(span) => {
|
|
|
|
self.tcx.sess.span_err(
|
|
|
|
span,
|
|
|
|
"lifetime of variable does not enclose its declaration");
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2013-05-23 21:37:37 -04:00
|
|
|
"the variable is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
|
|
|
}
|
2013-07-10 10:04:22 -04:00
|
|
|
infer::ReferenceOutlivesReferent(ty, span) => {
|
2013-05-23 21:37:37 -04:00
|
|
|
self.tcx.sess.span_err(
|
2013-07-10 10:04:22 -04:00
|
|
|
span,
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!("in type `{}`, reference has a longer lifetime \
|
2014-08-27 21:46:52 -04:00
|
|
|
than the data it references",
|
2015-02-20 14:08:14 -05:00
|
|
|
self.ty_to_string(ty)));
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2013-05-23 21:37:37 -04:00
|
|
|
"the pointer is valid for ",
|
|
|
|
sub,
|
|
|
|
"");
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2013-05-23 21:37:37 -04:00
|
|
|
"but the referenced data is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-07 00:38:33 +02:00
|
|
|
fn report_sub_sup_conflict(&self,
|
2013-05-23 21:37:37 -04:00
|
|
|
var_origin: RegionVariableOrigin,
|
2014-09-29 22:11:30 +03:00
|
|
|
sub_origin: SubregionOrigin<'tcx>,
|
2013-05-23 21:37:37 -04:00
|
|
|
sub_region: Region,
|
2014-09-29 22:11:30 +03:00
|
|
|
sup_origin: SubregionOrigin<'tcx>,
|
2013-05-23 21:37:37 -04:00
|
|
|
sup_region: Region) {
|
2013-10-29 06:12:50 -04:00
|
|
|
self.report_inference_failure(var_origin);
|
2013-05-23 21:37:37 -04:00
|
|
|
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2013-05-23 21:37:37 -04:00
|
|
|
"first, the lifetime cannot outlive ",
|
|
|
|
sup_region,
|
|
|
|
"...");
|
|
|
|
|
2014-08-27 21:46:52 -04:00
|
|
|
self.note_region_origin(&sup_origin);
|
2013-05-23 21:37:37 -04:00
|
|
|
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2013-05-23 21:37:37 -04:00
|
|
|
"but, the lifetime must be valid for ",
|
|
|
|
sub_region,
|
|
|
|
"...");
|
|
|
|
|
2014-08-27 21:46:52 -04:00
|
|
|
self.note_region_origin(&sub_origin);
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
|
|
|
|
2014-02-07 00:38:33 +02:00
|
|
|
fn report_sup_sup_conflict(&self,
|
2013-05-23 21:37:37 -04:00
|
|
|
var_origin: RegionVariableOrigin,
|
2014-09-29 22:11:30 +03:00
|
|
|
origin1: SubregionOrigin<'tcx>,
|
2013-05-23 21:37:37 -04:00
|
|
|
region1: Region,
|
2014-09-29 22:11:30 +03:00
|
|
|
origin2: SubregionOrigin<'tcx>,
|
2013-05-23 21:37:37 -04:00
|
|
|
region2: Region) {
|
2013-10-29 06:12:50 -04:00
|
|
|
self.report_inference_failure(var_origin);
|
2013-05-23 21:37:37 -04:00
|
|
|
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2013-05-23 21:37:37 -04:00
|
|
|
"first, the lifetime must be contained by ",
|
|
|
|
region1,
|
|
|
|
"...");
|
|
|
|
|
2014-08-27 21:46:52 -04:00
|
|
|
self.note_region_origin(&origin1);
|
2013-05-23 21:37:37 -04:00
|
|
|
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2013-05-23 21:37:37 -04:00
|
|
|
"but, the lifetime must also be contained by ",
|
|
|
|
region2,
|
|
|
|
"...");
|
|
|
|
|
2014-08-27 21:46:52 -04:00
|
|
|
self.note_region_origin(&origin2);
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
2014-02-15 01:26:51 -05:00
|
|
|
|
|
|
|
fn report_processed_errors(&self,
|
|
|
|
var_origins: &[RegionVariableOrigin],
|
2015-07-08 12:27:32 -07:00
|
|
|
trace_origins: &[(TypeTrace<'tcx>, ty::TypeError<'tcx>)],
|
2014-02-15 01:26:51 -05:00
|
|
|
same_regions: &[SameRegions]) {
|
2015-01-31 12:20:46 -05:00
|
|
|
for vo in var_origins {
|
2014-04-22 02:21:52 +03:00
|
|
|
self.report_inference_failure(vo.clone());
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2014-07-05 12:54:26 +12:00
|
|
|
self.give_suggestion(same_regions);
|
2015-07-12 20:33:17 -07:00
|
|
|
for &(ref trace, ref terr) in trace_origins {
|
|
|
|
self.report_and_explain_type_error(trace.clone(), terr);
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2015-01-26 13:38:33 +01:00
|
|
|
let taken = lifetimes_in_scope(self.tcx, scope_id);
|
2015-02-18 14:48:57 -05:00
|
|
|
let life_giver = LifeGiver::with_taken(&taken[..]);
|
2014-02-15 01:26:51 -05:00
|
|
|
let node_inner = match parent_node {
|
2014-04-23 18:16:23 +02:00
|
|
|
Some(ref node) => match *node {
|
|
|
|
ast_map::NodeItem(ref item) => {
|
|
|
|
match item.node {
|
2015-02-25 22:05:07 +02:00
|
|
|
ast::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, _) => {
|
|
|
|
Some((fn_decl, gen, unsafety, constness,
|
|
|
|
item.ident, None, item.span))
|
2014-04-23 18:16:23 +02:00
|
|
|
},
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
2015-03-10 12:28:44 +02:00
|
|
|
ast_map::NodeImplItem(item) => {
|
|
|
|
match item.node {
|
2015-03-11 23:38:58 +02:00
|
|
|
ast::MethodImplItem(ref sig, _) => {
|
|
|
|
Some((&sig.decl,
|
|
|
|
&sig.generics,
|
|
|
|
sig.unsafety,
|
2015-02-25 22:05:07 +02:00
|
|
|
sig.constness,
|
2015-03-10 12:28:44 +02:00
|
|
|
item.ident,
|
2015-03-11 23:38:58 +02:00
|
|
|
Some(&sig.explicit_self.node),
|
2015-03-10 12:28:44 +02:00
|
|
|
item.span))
|
2014-08-04 13:56:56 -07:00
|
|
|
}
|
2015-03-14 12:05:00 -06:00
|
|
|
ast::MacImplItem(_) => self.tcx.sess.bug("unexpanded macro"),
|
|
|
|
_ => None,
|
2014-08-04 13:56:56 -07:00
|
|
|
}
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
},
|
2015-03-10 12:28:44 +02:00
|
|
|
ast_map::NodeTraitItem(item) => {
|
|
|
|
match item.node {
|
2015-03-11 23:38:58 +02:00
|
|
|
ast::MethodTraitItem(ref sig, Some(_)) => {
|
|
|
|
Some((&sig.decl,
|
|
|
|
&sig.generics,
|
|
|
|
sig.unsafety,
|
2015-02-25 22:05:07 +02:00
|
|
|
sig.constness,
|
2015-03-10 12:28:44 +02:00
|
|
|
item.ident,
|
2015-03-11 23:38:58 +02:00
|
|
|
Some(&sig.explicit_self.node),
|
2015-03-10 12:28:44 +02:00
|
|
|
item.span))
|
2014-10-03 22:35:16 -07:00
|
|
|
}
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
2014-02-15 01:26:51 -05:00
|
|
|
_ => None
|
|
|
|
},
|
|
|
|
None => None
|
|
|
|
};
|
2015-02-25 22:05:07 +02:00
|
|
|
let (fn_decl, generics, unsafety, constness, ident, expl_self, span)
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
= node_inner.expect("expect item fn");
|
2014-07-11 21:22:11 -07:00
|
|
|
let rebuilder = Rebuilder::new(self.tcx, fn_decl, expl_self,
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
generics, same_regions, &life_giver);
|
|
|
|
let (fn_decl, expl_self, generics) = rebuilder.rebuild();
|
2015-02-25 22:05:07 +02:00
|
|
|
self.give_expl_lifetime_param(&fn_decl, unsafety, constness, ident,
|
2014-09-07 20:09:06 +03:00
|
|
|
expl_self.as_ref(), &generics, span);
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-24 19:11:44 -04:00
|
|
|
struct RebuildPathInfo<'a> {
|
|
|
|
path: &'a ast::Path,
|
|
|
|
// indexes to insert lifetime on path.lifetimes
|
2014-12-04 12:06:42 -08:00
|
|
|
indexes: Vec<u32>,
|
2014-03-24 19:11:44 -04:00
|
|
|
// number of lifetimes we expect to see on the type referred by `path`
|
|
|
|
// (e.g., expected=1 for struct Foo<'a>)
|
2014-12-04 12:06:42 -08:00
|
|
|
expected: u32,
|
|
|
|
anon_nums: &'a HashSet<u32>,
|
2014-03-24 19:11:44 -04:00
|
|
|
region_names: &'a HashSet<ast::Name>
|
|
|
|
}
|
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
struct Rebuilder<'a, 'tcx: 'a> {
|
|
|
|
tcx: &'a ty::ctxt<'tcx>,
|
2014-09-07 20:09:06 +03:00
|
|
|
fn_decl: &'a ast::FnDecl,
|
|
|
|
expl_self_opt: Option<&'a ast::ExplicitSelf_>,
|
2014-02-15 01:26:51 -05:00
|
|
|
generics: &'a ast::Generics,
|
|
|
|
same_regions: &'a [SameRegions],
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
life_giver: &'a LifeGiver,
|
2014-12-04 12:06:42 -08:00
|
|
|
cur_anon: Cell<u32>,
|
|
|
|
inserted_anons: RefCell<HashSet<u32>>,
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
enum FreshOrKept {
|
|
|
|
Fresh,
|
|
|
|
Kept
|
|
|
|
}
|
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
|
|
|
|
fn new(tcx: &'a ty::ctxt<'tcx>,
|
2014-09-07 20:09:06 +03:00
|
|
|
fn_decl: &'a ast::FnDecl,
|
|
|
|
expl_self_opt: Option<&'a ast::ExplicitSelf_>,
|
2014-02-15 01:26:51 -05:00
|
|
|
generics: &'a ast::Generics,
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
same_regions: &'a [SameRegions],
|
|
|
|
life_giver: &'a LifeGiver)
|
2014-04-22 15:56:37 +03:00
|
|
|
-> Rebuilder<'a, 'tcx> {
|
2014-02-15 01:26:51 -05:00
|
|
|
Rebuilder {
|
|
|
|
tcx: tcx,
|
|
|
|
fn_decl: fn_decl,
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
expl_self_opt: expl_self_opt,
|
2014-02-15 01:26:51 -05:00
|
|
|
generics: generics,
|
|
|
|
same_regions: same_regions,
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
life_giver: life_giver,
|
2014-02-15 01:26:51 -05:00
|
|
|
cur_anon: Cell::new(0),
|
|
|
|
inserted_anons: RefCell::new(HashSet::new()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
fn rebuild(&self)
|
|
|
|
-> (ast::FnDecl, Option<ast::ExplicitSelf_>, ast::Generics) {
|
2015-02-13 07:33:44 +00:00
|
|
|
let mut expl_self_opt = self.expl_self_opt.cloned();
|
2014-02-15 01:26:51 -05:00
|
|
|
let mut inputs = self.fn_decl.inputs.clone();
|
2014-09-07 20:09:06 +03:00
|
|
|
let mut output = self.fn_decl.output.clone();
|
2014-03-24 19:11:44 -04:00
|
|
|
let mut ty_params = self.generics.ty_params.clone();
|
2014-08-11 09:32:26 -07:00
|
|
|
let where_clause = self.generics.where_clause.clone();
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
let mut kept_lifetimes = HashSet::new();
|
2015-01-31 12:20:46 -05:00
|
|
|
for sr in self.same_regions {
|
2014-02-15 01:26:51 -05:00
|
|
|
self.cur_anon.set(0);
|
|
|
|
self.offset_cur_anon();
|
|
|
|
let (anon_nums, region_names) =
|
|
|
|
self.extract_anon_nums_and_names(sr);
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
let (lifetime, fresh_or_kept) = self.pick_lifetime(®ion_names);
|
|
|
|
match fresh_or_kept {
|
|
|
|
Kept => { kept_lifetimes.insert(lifetime.name); }
|
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
expl_self_opt = self.rebuild_expl_self(expl_self_opt, lifetime,
|
|
|
|
&anon_nums, ®ion_names);
|
2015-02-18 14:48:57 -05:00
|
|
|
inputs = self.rebuild_args_ty(&inputs[..], lifetime,
|
2014-02-15 01:26:51 -05:00
|
|
|
&anon_nums, ®ion_names);
|
2014-11-09 16:14:15 +01:00
|
|
|
output = self.rebuild_output(&output, lifetime, &anon_nums, ®ion_names);
|
2014-03-24 19:11:44 -04:00
|
|
|
ty_params = self.rebuild_ty_params(ty_params, lifetime,
|
|
|
|
®ion_names);
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
let fresh_lifetimes = self.life_giver.get_generated_lifetimes();
|
2014-02-15 01:26:51 -05:00
|
|
|
let all_region_names = self.extract_all_region_names();
|
|
|
|
let generics = self.rebuild_generics(self.generics,
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
&fresh_lifetimes,
|
|
|
|
&kept_lifetimes,
|
|
|
|
&all_region_names,
|
2014-08-11 09:32:26 -07:00
|
|
|
ty_params,
|
|
|
|
where_clause);
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
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) {
|
2015-03-24 16:54:09 -07:00
|
|
|
if !region_names.is_empty() {
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
// 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();
|
2015-01-31 12:20:46 -05:00
|
|
|
for rn in region_names {
|
2015-02-04 00:03:39 +01:00
|
|
|
let lt_name = token::get_name(*rn).to_string();
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
names.push(lt_name);
|
|
|
|
}
|
|
|
|
names.sort();
|
2015-02-20 14:08:14 -05:00
|
|
|
let name = token::str_to_ident(&names[0]).name;
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
return (name_to_dummy_lifetime(name), Kept);
|
|
|
|
}
|
|
|
|
return (self.life_giver.give_lifetime(), Fresh);
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn extract_anon_nums_and_names(&self, same_regions: &SameRegions)
|
2014-12-04 12:06:42 -08:00
|
|
|
-> (HashSet<u32>, HashSet<ast::Name>) {
|
2014-02-15 01:26:51 -05:00
|
|
|
let mut anon_nums = HashSet::new();
|
|
|
|
let mut region_names = HashSet::new();
|
2015-01-31 12:20:46 -05:00
|
|
|
for br in &same_regions.regions {
|
2014-02-15 01:26:51 -05:00
|
|
|
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();
|
2015-01-31 12:20:46 -05:00
|
|
|
for sr in self.same_regions {
|
|
|
|
for br in &sr.regions {
|
2014-02-15 01:26:51 -05:00
|
|
|
match *br {
|
|
|
|
ty::BrNamed(_, name) => {
|
|
|
|
all_region_names.insert(name);
|
|
|
|
}
|
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
all_region_names
|
|
|
|
}
|
|
|
|
|
2014-12-04 12:06:42 -08:00
|
|
|
fn inc_cur_anon(&self, n: u32) {
|
2014-02-15 01:26:51 -05:00
|
|
|
let anon = self.cur_anon.get();
|
|
|
|
self.cur_anon.set(anon+n);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn offset_cur_anon(&self) {
|
|
|
|
let mut anon = self.cur_anon.get();
|
2014-03-20 19:49:20 -07:00
|
|
|
while self.inserted_anons.borrow().contains(&anon) {
|
2014-02-15 01:26:51 -05:00
|
|
|
anon += 1;
|
|
|
|
}
|
|
|
|
self.cur_anon.set(anon);
|
|
|
|
}
|
|
|
|
|
2014-12-04 12:06:42 -08:00
|
|
|
fn inc_and_offset_cur_anon(&self, n: u32) {
|
2014-02-15 01:26:51 -05:00
|
|
|
self.inc_cur_anon(n);
|
|
|
|
self.offset_cur_anon();
|
|
|
|
}
|
|
|
|
|
2014-12-04 12:06:42 -08:00
|
|
|
fn track_anon(&self, anon: u32) {
|
2014-03-20 19:49:20 -07:00
|
|
|
self.inserted_anons.borrow_mut().insert(anon);
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
|
2014-03-24 19:11:44 -04:00
|
|
|
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,
|
2014-09-07 20:09:06 +03:00
|
|
|
default: ty_param.default.clone(),
|
2014-04-03 13:38:45 +13:00
|
|
|
span: ty_param.span,
|
2014-03-24 19:11:44 -04:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2014-08-27 21:46:52 -04:00
|
|
|
&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)
|
|
|
|
}
|
2014-12-24 19:38:10 +13:00
|
|
|
&ast::TraitTyParamBound(ref poly_tr, modifier) => {
|
2014-11-07 06:53:45 -05:00
|
|
|
let tr = &poly_tr.trait_ref;
|
2014-03-24 19:11:44 -04:00
|
|
|
let last_seg = tr.path.segments.last().unwrap();
|
|
|
|
let mut insert = Vec::new();
|
2014-11-03 21:52:52 -05:00
|
|
|
let lifetimes = last_seg.parameters.lifetimes();
|
|
|
|
for (i, lt) in lifetimes.iter().enumerate() {
|
2014-03-24 19:11:44 -04:00
|
|
|
if region_names.contains(<.name) {
|
2014-12-04 12:06:42 -08:00
|
|
|
insert.push(i as u32);
|
2014-03-24 19:11:44 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
let rebuild_info = RebuildPathInfo {
|
|
|
|
path: &tr.path,
|
|
|
|
indexes: insert,
|
2014-12-04 12:06:42 -08:00
|
|
|
expected: lifetimes.len() as u32,
|
2014-03-24 19:11:44 -04:00
|
|
|
anon_nums: &HashSet::new(),
|
|
|
|
region_names: region_names
|
|
|
|
};
|
|
|
|
let new_path = self.rebuild_path(rebuild_info, lifetime);
|
2014-11-07 06:53:45 -05:00
|
|
|
ast::TraitTyParamBound(ast::PolyTraitRef {
|
|
|
|
bound_lifetimes: poly_tr.bound_lifetimes.clone(),
|
|
|
|
trait_ref: ast::TraitRef {
|
|
|
|
path: new_path,
|
|
|
|
ref_id: tr.ref_id,
|
2015-02-05 21:46:01 +13:00
|
|
|
},
|
|
|
|
span: poly_tr.span,
|
2014-12-24 19:38:10 +13:00
|
|
|
}, modifier)
|
2014-03-24 19:11:44 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
fn rebuild_expl_self(&self,
|
|
|
|
expl_self_opt: Option<ast::ExplicitSelf_>,
|
|
|
|
lifetime: ast::Lifetime,
|
2014-12-04 12:06:42 -08:00
|
|
|
anon_nums: &HashSet<u32>,
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
region_names: &HashSet<ast::Name>)
|
|
|
|
-> Option<ast::ExplicitSelf_> {
|
|
|
|
match expl_self_opt {
|
2014-09-07 20:09:06 +03:00
|
|
|
Some(ref expl_self) => match *expl_self {
|
2014-07-06 15:10:57 -07:00
|
|
|
ast::SelfRegion(lt_opt, muta, id) => match lt_opt {
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
Some(lt) => if region_names.contains(<.name) {
|
2014-07-06 15:10:57 -07:00
|
|
|
return Some(ast::SelfRegion(Some(lifetime), muta, id));
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
},
|
|
|
|
None => {
|
|
|
|
let anon = self.cur_anon.get();
|
|
|
|
self.inc_and_offset_cur_anon(1);
|
|
|
|
if anon_nums.contains(&anon) {
|
|
|
|
self.track_anon(anon);
|
2014-07-06 15:10:57 -07:00
|
|
|
return Some(ast::SelfRegion(Some(lifetime), muta, id));
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => ()
|
|
|
|
},
|
|
|
|
None => ()
|
|
|
|
}
|
|
|
|
expl_self_opt
|
|
|
|
}
|
|
|
|
|
2014-02-15 01:26:51 -05:00
|
|
|
fn rebuild_generics(&self,
|
|
|
|
generics: &ast::Generics,
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
add: &Vec<ast::Lifetime>,
|
|
|
|
keep: &HashSet<ast::Name>,
|
2014-03-24 19:11:44 -04:00
|
|
|
remove: &HashSet<ast::Name>,
|
2014-08-11 09:32:26 -07:00
|
|
|
ty_params: OwnedSlice<ast::TyParam>,
|
|
|
|
where_clause: ast::WhereClause)
|
2014-02-15 01:26:51 -05:00
|
|
|
-> ast::Generics {
|
|
|
|
let mut lifetimes = Vec::new();
|
2015-01-31 12:20:46 -05:00
|
|
|
for lt in add {
|
2014-08-05 22:59:24 -04:00
|
|
|
lifetimes.push(ast::LifetimeDef { lifetime: *lt,
|
|
|
|
bounds: Vec::new() });
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2015-01-31 12:20:46 -05:00
|
|
|
for lt in &generics.lifetimes {
|
2014-08-05 22:59:24 -04:00
|
|
|
if keep.contains(<.lifetime.name) ||
|
2014-08-11 09:32:26 -07:00
|
|
|
!remove.contains(<.lifetime.name) {
|
2014-02-15 01:26:51 -05:00
|
|
|
lifetimes.push((*lt).clone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast::Generics {
|
|
|
|
lifetimes: lifetimes,
|
2014-08-11 09:32:26 -07:00
|
|
|
ty_params: ty_params,
|
|
|
|
where_clause: where_clause,
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn rebuild_args_ty(&self,
|
|
|
|
inputs: &[ast::Arg],
|
|
|
|
lifetime: ast::Lifetime,
|
2014-12-04 12:06:42 -08:00
|
|
|
anon_nums: &HashSet<u32>,
|
2014-02-15 01:26:51 -05:00
|
|
|
region_names: &HashSet<ast::Name>)
|
|
|
|
-> Vec<ast::Arg> {
|
|
|
|
let mut new_inputs = Vec::new();
|
2015-01-31 12:20:46 -05:00
|
|
|
for arg in inputs {
|
2014-09-07 20:09:06 +03:00
|
|
|
let new_ty = self.rebuild_arg_ty_or_output(&*arg.ty, lifetime,
|
2014-02-15 01:26:51 -05:00
|
|
|
anon_nums, region_names);
|
|
|
|
let possibly_new_arg = ast::Arg {
|
|
|
|
ty: new_ty,
|
2014-09-07 20:09:06 +03:00
|
|
|
pat: arg.pat.clone(),
|
2014-02-15 01:26:51 -05:00
|
|
|
id: arg.id
|
|
|
|
};
|
|
|
|
new_inputs.push(possibly_new_arg);
|
|
|
|
}
|
|
|
|
new_inputs
|
|
|
|
}
|
|
|
|
|
2014-11-09 16:14:15 +01:00
|
|
|
fn rebuild_output(&self, ty: &ast::FunctionRetTy,
|
|
|
|
lifetime: ast::Lifetime,
|
2014-12-04 12:06:42 -08:00
|
|
|
anon_nums: &HashSet<u32>,
|
2014-11-09 16:14:15 +01:00
|
|
|
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)
|
|
|
|
),
|
2015-01-18 22:49:19 +09:00
|
|
|
ast::DefaultReturn(span) => ast::DefaultReturn(span),
|
2014-11-09 16:14:15 +01:00
|
|
|
ast::NoReturn(span) => ast::NoReturn(span)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-15 01:26:51 -05:00
|
|
|
fn rebuild_arg_ty_or_output(&self,
|
2014-09-07 20:09:06 +03:00
|
|
|
ty: &ast::Ty,
|
2014-02-15 01:26:51 -05:00
|
|
|
lifetime: ast::Lifetime,
|
2014-12-04 12:06:42 -08:00
|
|
|
anon_nums: &HashSet<u32>,
|
2014-02-15 01:26:51 -05:00
|
|
|
region_names: &HashSet<ast::Name>)
|
2014-09-07 20:09:06 +03:00
|
|
|
-> P<ast::Ty> {
|
|
|
|
let mut new_ty = P(ty.clone());
|
2014-02-15 01:26:51 -05:00
|
|
|
let mut ty_queue = vec!(ty);
|
|
|
|
while !ty_queue.is_empty() {
|
2014-12-30 10:51:18 -08:00
|
|
|
let cur_ty = ty_queue.remove(0);
|
2014-02-15 01:26:51 -05:00
|
|
|
match cur_ty.node {
|
2014-09-07 20:09:06 +03:00
|
|
|
ast::TyRptr(lt_opt, ref mut_ty) => {
|
|
|
|
let rebuild = match lt_opt {
|
|
|
|
Some(lt) => region_names.contains(<.name),
|
2014-02-15 01:26:51 -05:00
|
|
|
None => {
|
|
|
|
let anon = self.cur_anon.get();
|
2014-09-07 20:09:06 +03:00
|
|
|
let rebuild = anon_nums.contains(&anon);
|
|
|
|
if rebuild {
|
2014-02-15 01:26:51 -05:00
|
|
|
self.track_anon(anon);
|
|
|
|
}
|
|
|
|
self.inc_and_offset_cur_anon(1);
|
2014-09-07 20:09:06 +03:00
|
|
|
rebuild
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2014-09-07 20:09:06 +03:00
|
|
|
};
|
|
|
|
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));
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2014-09-07 20:09:06 +03:00
|
|
|
ty_queue.push(&*mut_ty.ty);
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2015-02-17 19:29:13 +02:00
|
|
|
ast::TyPath(ref maybe_qself, ref path) => {
|
2015-01-29 21:18:17 +02:00
|
|
|
let a_def = match self.tcx.def_map.borrow().get(&cur_ty.id) {
|
2014-05-16 10:45:16 -07:00
|
|
|
None => {
|
|
|
|
self.tcx
|
|
|
|
.sess
|
2015-01-07 11:58:31 -05:00
|
|
|
.fatal(&format!(
|
2014-05-16 10:45:16 -07:00
|
|
|
"unbound path {}",
|
2015-02-20 14:08:14 -05:00
|
|
|
pprust::path_to_string(path)))
|
2014-05-16 10:45:16 -07:00
|
|
|
}
|
2015-02-17 06:44:23 +02:00
|
|
|
Some(d) => d.full_def()
|
2014-02-15 01:26:51 -05:00
|
|
|
};
|
|
|
|
match a_def {
|
2014-09-16 09:13:00 +12:00
|
|
|
def::DefTy(did, _) | def::DefStruct(did) => {
|
2015-06-25 23:42:17 +03:00
|
|
|
let generics = self.tcx.lookup_item_type(did).generics;
|
2014-02-15 01:26:51 -05:00
|
|
|
|
2014-05-31 18:53:13 -04:00
|
|
|
let expected =
|
2014-12-04 12:06:42 -08:00
|
|
|
generics.regions.len(subst::TypeSpace) as u32;
|
2014-05-31 18:53:13 -04:00
|
|
|
let lifetimes =
|
2014-11-03 21:52:52 -05:00
|
|
|
path.segments.last().unwrap().parameters.lifetimes();
|
2014-02-15 01:26:51 -05:00
|
|
|
let mut insert = Vec::new();
|
2015-03-24 16:53:34 -07:00
|
|
|
if lifetimes.is_empty() {
|
2014-02-15 01:26:51 -05:00
|
|
|
let anon = self.cur_anon.get();
|
2015-01-26 16:05:07 -05:00
|
|
|
for (i, a) in (anon..anon+expected).enumerate() {
|
2014-02-15 01:26:51 -05:00
|
|
|
if anon_nums.contains(&a) {
|
2014-12-04 12:06:42 -08:00
|
|
|
insert.push(i as u32);
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
self.track_anon(a);
|
|
|
|
}
|
|
|
|
self.inc_and_offset_cur_anon(expected);
|
|
|
|
} else {
|
|
|
|
for (i, lt) in lifetimes.iter().enumerate() {
|
|
|
|
if region_names.contains(<.name) {
|
2014-12-04 12:06:42 -08:00
|
|
|
insert.push(i as u32);
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-03-24 19:11:44 -04:00
|
|
|
let rebuild_info = RebuildPathInfo {
|
|
|
|
path: path,
|
|
|
|
indexes: insert,
|
|
|
|
expected: expected,
|
|
|
|
anon_nums: anon_nums,
|
|
|
|
region_names: region_names
|
|
|
|
};
|
2014-09-07 20:09:06 +03:00
|
|
|
let new_path = self.rebuild_path(rebuild_info, lifetime);
|
2015-02-17 19:29:13 +02:00
|
|
|
let qself = maybe_qself.as_ref().map(|qself| {
|
|
|
|
ast::QSelf {
|
|
|
|
ty: self.rebuild_arg_ty_or_output(&qself.ty, lifetime,
|
|
|
|
anon_nums, region_names),
|
|
|
|
position: qself.position
|
|
|
|
}
|
|
|
|
});
|
2014-09-07 20:09:06 +03:00
|
|
|
let to = ast::Ty {
|
|
|
|
id: cur_ty.id,
|
2015-02-17 19:29:13 +02:00
|
|
|
node: ast::TyPath(qself, new_path),
|
2014-09-07 20:09:06 +03:00
|
|
|
span: cur_ty.span
|
|
|
|
};
|
|
|
|
new_ty = self.rebuild_ty(new_ty, P(to));
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2014-09-07 20:09:06 +03:00
|
|
|
|
|
|
|
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)),
|
|
|
|
_ => {}
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
new_ty
|
|
|
|
}
|
|
|
|
|
|
|
|
fn rebuild_ty(&self,
|
2014-09-07 20:09:06 +03:00
|
|
|
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),
|
|
|
|
})
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2014-09-07 20:09:06 +03:00
|
|
|
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) => {
|
2014-09-14 20:27:36 -07:00
|
|
|
ast::TyTup(tys.into_iter().map(|ty| build_to(ty, to)).collect())
|
2014-09-07 20:09:06 +03:00
|
|
|
}
|
|
|
|
ast::TyParen(typ) => ast::TyParen(build_to(typ, to)),
|
|
|
|
other => other
|
|
|
|
};
|
|
|
|
ast::Ty { id: id, node: new_node, span: span }
|
|
|
|
})
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
|
2014-09-07 20:09:06 +03:00
|
|
|
build_to(from, &mut Some(to))
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn rebuild_path(&self,
|
2014-03-24 19:11:44 -04:00
|
|
|
rebuild_info: RebuildPathInfo,
|
2014-02-15 01:26:51 -05:00
|
|
|
lifetime: ast::Lifetime)
|
2014-11-03 21:52:52 -05:00
|
|
|
-> ast::Path
|
|
|
|
{
|
2014-03-24 19:11:44 -04:00
|
|
|
let RebuildPathInfo {
|
2014-10-06 13:36:53 +13:00
|
|
|
path,
|
|
|
|
indexes,
|
|
|
|
expected,
|
|
|
|
anon_nums,
|
|
|
|
region_names,
|
2014-03-24 19:11:44 -04:00
|
|
|
} = rebuild_info;
|
|
|
|
|
2014-02-15 01:26:51 -05:00
|
|
|
let last_seg = path.segments.last().unwrap();
|
2014-11-03 21:52:52 -05:00
|
|
|
let new_parameters = match last_seg.parameters {
|
|
|
|
ast::ParenthesizedParameters(..) => {
|
|
|
|
last_seg.parameters.clone()
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2014-11-03 21:52:52 -05:00
|
|
|
|
|
|
|
ast::AngleBracketedParameters(ref data) => {
|
|
|
|
let mut new_lts = Vec::new();
|
2015-03-24 16:53:34 -07:00
|
|
|
if data.lifetimes.is_empty() {
|
2014-11-03 21:52:52 -05:00
|
|
|
// traverse once to see if there's a need to insert lifetime
|
2015-01-26 15:44:22 -05:00
|
|
|
let need_insert = (0..expected).any(|i| {
|
2014-11-03 21:52:52 -05:00
|
|
|
indexes.contains(&i)
|
|
|
|
});
|
|
|
|
if need_insert {
|
2015-01-26 15:46:12 -05:00
|
|
|
for i in 0..expected {
|
2014-11-03 21:52:52 -05:00
|
|
|
if indexes.contains(&i) {
|
|
|
|
new_lts.push(lifetime);
|
|
|
|
} else {
|
|
|
|
new_lts.push(self.life_giver.give_lifetime());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-02-15 01:26:51 -05:00
|
|
|
} else {
|
2014-11-03 21:52:52 -05:00
|
|
|
for (i, lt) in data.lifetimes.iter().enumerate() {
|
2014-12-04 12:06:42 -08:00
|
|
|
if indexes.contains(&(i as u32)) {
|
2014-11-03 21:52:52 -05:00
|
|
|
new_lts.push(lifetime);
|
|
|
|
} else {
|
|
|
|
new_lts.push(*lt);
|
|
|
|
}
|
|
|
|
}
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2014-11-03 21:52:52 -05:00
|
|
|
let new_types = data.types.map(|t| {
|
|
|
|
self.rebuild_arg_ty_or_output(&**t, lifetime, anon_nums, region_names)
|
|
|
|
});
|
2014-11-29 17:08:30 +13:00
|
|
|
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
|
|
|
|
})
|
|
|
|
});
|
2014-11-03 21:52:52 -05:00
|
|
|
ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
|
|
|
|
lifetimes: new_lts,
|
2014-11-29 17:08:30 +13:00
|
|
|
types: new_types,
|
|
|
|
bindings: new_bindings,
|
|
|
|
})
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2014-11-03 21:52:52 -05:00
|
|
|
};
|
2014-02-15 01:26:51 -05:00
|
|
|
let new_seg = ast::PathSegment {
|
|
|
|
identifier: last_seg.identifier,
|
2014-11-03 21:52:52 -05:00
|
|
|
parameters: new_parameters
|
2014-02-15 01:26:51 -05:00
|
|
|
};
|
|
|
|
let mut new_segs = Vec::new();
|
2015-07-11 14:34:57 +03:00
|
|
|
new_segs.push_all(path.segments.split_last().unwrap().1);
|
2014-02-15 01:26:51 -05:00
|
|
|
new_segs.push(new_seg);
|
|
|
|
ast::Path {
|
|
|
|
span: path.span,
|
|
|
|
global: path.global,
|
|
|
|
segments: new_segs
|
|
|
|
}
|
|
|
|
}
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
|
2014-02-15 01:26:51 -05:00
|
|
|
fn give_expl_lifetime_param(&self,
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
decl: &ast::FnDecl,
|
2014-12-09 10:36:46 -05:00
|
|
|
unsafety: ast::Unsafety,
|
2015-02-25 22:05:07 +02:00
|
|
|
constness: ast::Constness,
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
ident: ast::Ident,
|
2014-09-07 20:09:06 +03:00
|
|
|
opt_explicit_self: Option<&ast::ExplicitSelf_>,
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
generics: &ast::Generics,
|
2015-06-16 01:10:55 +03:00
|
|
|
span: Span) {
|
2015-02-25 22:05:07 +02:00
|
|
|
let suggested_fn = pprust::fun_to_string(decl, unsafety, constness, ident,
|
|
|
|
opt_explicit_self, generics);
|
2014-02-15 01:26:51 -05:00
|
|
|
let msg = format!("consider using an explicit lifetime \
|
|
|
|
parameter as shown: {}", suggested_fn);
|
2015-02-18 14:48:57 -05:00
|
|
|
self.tcx.sess.span_help(span, &msg[..]);
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
|
2014-02-07 00:38:33 +02:00
|
|
|
fn report_inference_failure(&self,
|
2013-10-29 06:12:50 -04:00
|
|
|
var_origin: RegionVariableOrigin) {
|
2015-06-14 06:46:04 +03:00
|
|
|
let br_string = |br: ty::BoundRegion| {
|
2015-06-18 20:25:05 +03:00
|
|
|
let mut s = br.to_string();
|
2015-06-14 06:46:04 +03:00
|
|
|
if !s.is_empty() {
|
|
|
|
s.push_str(" ");
|
|
|
|
}
|
|
|
|
s
|
|
|
|
};
|
2013-10-29 06:12:50 -04:00
|
|
|
let var_description = match var_origin {
|
2014-05-25 03:17:19 -07:00
|
|
|
infer::MiscVariable(_) => "".to_string(),
|
|
|
|
infer::PatternRegion(_) => " for pattern".to_string(),
|
|
|
|
infer::AddrOfRegion(_) => " for borrow expression".to_string(),
|
|
|
|
infer::Autoref(_) => " for autoref".to_string(),
|
|
|
|
infer::Coercion(_) => " for automatic coercion".to_string(),
|
2014-11-05 22:06:04 -05:00
|
|
|
infer::LateBoundRegion(_, br, infer::FnCall) => {
|
2015-06-14 06:46:04 +03:00
|
|
|
format!(" for lifetime parameter {}in function call",
|
|
|
|
br_string(br))
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
2014-11-15 16:22:22 -05:00
|
|
|
infer::LateBoundRegion(_, br, infer::HigherRankedType) => {
|
2015-06-14 06:46:04 +03:00
|
|
|
format!(" for lifetime parameter {}in generic type", br_string(br))
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
2014-12-17 14:16:28 -05:00
|
|
|
infer::LateBoundRegion(_, br, infer::AssocTypeProjection(type_name)) => {
|
2015-06-14 06:46:04 +03:00
|
|
|
format!(" for lifetime parameter {}in trait containing associated type `{}`",
|
|
|
|
br_string(br), token::get_name(type_name))
|
2014-12-17 14:16:28 -05:00
|
|
|
}
|
2014-03-07 08:43:39 +01:00
|
|
|
infer::EarlyBoundRegion(_, name) => {
|
2014-07-22 05:27:46 -04:00
|
|
|
format!(" for lifetime parameter `{}`",
|
2015-02-04 00:03:39 +01:00
|
|
|
&token::get_name(name))
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
2014-03-07 08:43:39 +01:00
|
|
|
infer::BoundRegionInCoherence(name) => {
|
2014-07-22 05:27:46 -04:00
|
|
|
format!(" for lifetime parameter `{}` in coherence check",
|
2015-02-04 21:48:12 +01:00
|
|
|
&token::get_name(name))
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
2014-02-07 14:43:48 -05:00
|
|
|
infer::UpvarRegion(ref upvar_id, _) => {
|
|
|
|
format!(" for capture of `{}` by closure",
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.local_var_name_str(upvar_id.var_id).to_string())
|
2014-02-07 14:43:48 -05:00
|
|
|
}
|
2013-10-29 06:12:50 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
self.tcx.sess.span_err(
|
|
|
|
var_origin.span(),
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!("cannot infer an appropriate lifetime{} \
|
2013-10-29 06:12:50 -04:00
|
|
|
due to conflicting requirements",
|
2015-02-20 14:08:14 -05:00
|
|
|
var_description));
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
fn note_region_origin(&self, origin: &SubregionOrigin<'tcx>) {
|
2014-08-27 21:46:52 -04:00
|
|
|
match *origin {
|
2015-07-14 19:36:15 -04:00
|
|
|
infer::Subtype(ref trace) => {
|
2013-10-29 06:12:50 -04:00
|
|
|
let desc = match trace.origin {
|
|
|
|
infer::Misc(_) => {
|
2015-03-24 20:59:17 -07:00
|
|
|
"types are compatible"
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
|
|
|
infer::MethodCompatCheck(_) => {
|
2015-03-24 20:59:17 -07:00
|
|
|
"method type is compatible with trait"
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
|
|
|
infer::ExprAssignable(_) => {
|
2015-03-24 20:59:17 -07:00
|
|
|
"expression is assignable"
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
|
|
|
infer::RelateTraitRefs(_) => {
|
2015-03-24 20:59:17 -07:00
|
|
|
"traits are compatible"
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
|
|
|
infer::RelateSelfType(_) => {
|
2015-03-24 20:59:17 -07:00
|
|
|
"self type matches impl self type"
|
2014-09-12 10:53:35 -04:00
|
|
|
}
|
|
|
|
infer::RelateOutputImplTypes(_) => {
|
2015-03-24 20:59:17 -07:00
|
|
|
"trait type parameters matches those \
|
|
|
|
specified on the impl"
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
2014-05-31 00:16:33 +02:00
|
|
|
infer::MatchExpressionArm(_, _) => {
|
2015-03-24 20:59:17 -07:00
|
|
|
"match arms have compatible types"
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
|
|
|
infer::IfExpression(_) => {
|
2015-03-24 20:59:17 -07:00
|
|
|
"if and else have compatible types"
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
2014-10-13 22:26:23 +02:00
|
|
|
infer::IfExpressionWithNoElse(_) => {
|
2015-03-24 20:59:17 -07:00
|
|
|
"if may be missing an else clause"
|
2014-10-13 22:26:23 +02:00
|
|
|
}
|
2014-12-16 16:25:33 +13:00
|
|
|
infer::RangeExpression(_) => {
|
2015-03-24 20:59:17 -07:00
|
|
|
"start and end of range have compatible types"
|
2014-12-16 16:25:33 +13:00
|
|
|
}
|
2014-12-06 01:30:41 -05:00
|
|
|
infer::EquatePredicate(_) => {
|
2015-03-24 20:59:17 -07:00
|
|
|
"equality where clause is satisfied"
|
2014-12-06 01:30:41 -05:00
|
|
|
}
|
2013-10-29 06:12:50 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
match self.values_str(&trace.values) {
|
|
|
|
Some(values_str) => {
|
|
|
|
self.tcx.sess.span_note(
|
|
|
|
trace.origin.span(),
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!("...so that {} ({})",
|
2015-02-20 14:08:14 -05:00
|
|
|
desc, values_str));
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
|
|
|
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(),
|
2015-02-20 14:08:14 -05:00
|
|
|
&format!("...so that {}", desc));
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
infer::Reborrow(span) => {
|
|
|
|
self.tcx.sess.span_note(
|
|
|
|
span,
|
2014-01-07 18:49:13 -08:00
|
|
|
"...so that reference does not outlive \
|
2013-10-29 06:12:50 -04:00
|
|
|
borrowed content");
|
|
|
|
}
|
2014-02-07 14:43:48 -05:00
|
|
|
infer::ReborrowUpvar(span, ref upvar_id) => {
|
|
|
|
self.tcx.sess.span_note(
|
|
|
|
span,
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!(
|
2014-05-16 10:45:16 -07:00
|
|
|
"...so that closure can access `{}`",
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.local_var_name_str(upvar_id.var_id)
|
2015-02-20 14:08:14 -05:00
|
|
|
.to_string()))
|
2014-02-07 14:43:48 -05:00
|
|
|
}
|
2013-10-29 06:12:50 -04:00
|
|
|
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");
|
|
|
|
}
|
2014-02-07 14:43:48 -05:00
|
|
|
infer::FreeVariable(span, id) => {
|
2013-10-29 06:12:50 -04:00
|
|
|
self.tcx.sess.span_note(
|
|
|
|
span,
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!("...so that captured variable `{}` \
|
2014-02-07 14:43:48 -05:00
|
|
|
does not outlive the enclosing closure",
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.local_var_name_str(id)));
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
|
|
|
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,
|
2014-08-27 21:46:52 -04:00
|
|
|
"...so that it can be closed over into an object");
|
|
|
|
}
|
2013-10-29 06:12:50 -04:00
|
|
|
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");
|
|
|
|
}
|
2015-02-12 12:48:54 -05:00
|
|
|
infer::Operand(span) => {
|
|
|
|
self.tcx.sess.span_err(
|
|
|
|
span,
|
|
|
|
"...so that operand is valid for operation");
|
|
|
|
}
|
2013-10-29 06:12:50 -04:00
|
|
|
infer::AddrOf(span) => {
|
|
|
|
self.tcx.sess.span_note(
|
|
|
|
span,
|
2014-01-07 18:49:13 -08:00
|
|
|
"...so that reference is valid \
|
2013-10-29 06:12:50 -04:00
|
|
|
at the time of borrow");
|
|
|
|
}
|
|
|
|
infer::AutoBorrow(span) => {
|
|
|
|
self.tcx.sess.span_note(
|
|
|
|
span,
|
2014-07-22 05:27:46 -04:00
|
|
|
"...so that auto-reference is valid \
|
|
|
|
at the time of borrow");
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
2014-08-27 21:46:52 -04:00
|
|
|
infer::ExprTypeIsNotInScope(t, span) => {
|
|
|
|
self.tcx.sess.span_note(
|
|
|
|
span,
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!("...so type `{}` of expression is valid during the \
|
2014-08-27 21:46:52 -04:00
|
|
|
expression",
|
2015-02-20 14:08:14 -05:00
|
|
|
self.ty_to_string(t)));
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
2013-10-29 06:12:50 -04:00
|
|
|
infer::BindingTypeIsNotValidAtDecl(span) => {
|
|
|
|
self.tcx.sess.span_note(
|
|
|
|
span,
|
|
|
|
"...so that variable is valid at time of its declaration");
|
|
|
|
}
|
2014-08-27 21:46:52 -04:00
|
|
|
infer::ReferenceOutlivesReferent(ty, span) => {
|
|
|
|
self.tcx.sess.span_note(
|
|
|
|
span,
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!("...so that the reference type `{}` \
|
2014-08-27 21:46:52 -04:00
|
|
|
does not outlive the data it points at",
|
2015-02-20 14:08:14 -05:00
|
|
|
self.ty_to_string(ty)));
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
2014-11-15 17:25:05 -05:00
|
|
|
infer::RelateParamBound(span, t) => {
|
2014-08-27 21:46:52 -04:00
|
|
|
self.tcx.sess.span_note(
|
|
|
|
span,
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!("...so that the type `{}` \
|
2015-02-16 11:58:47 -05:00
|
|
|
will meet its required lifetime bounds",
|
2015-02-20 14:08:14 -05:00
|
|
|
self.ty_to_string(t)));
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
|
|
|
infer::RelateDefaultParamBound(span, t) => {
|
|
|
|
self.tcx.sess.span_note(
|
|
|
|
span,
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!("...so that type parameter \
|
2014-08-27 21:46:52 -04:00
|
|
|
instantiated with `{}`, \
|
2014-11-28 19:01:41 +13:00
|
|
|
will meet its declared lifetime bounds",
|
2015-02-20 14:08:14 -05:00
|
|
|
self.ty_to_string(t)));
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
|
|
|
infer::RelateRegionParamBound(span) => {
|
2013-10-29 06:12:50 -04:00
|
|
|
self.tcx.sess.span_note(
|
|
|
|
span,
|
2015-03-24 20:59:17 -07:00
|
|
|
"...so that the declared lifetime parameter bounds \
|
|
|
|
are satisfied");
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
2014-10-27 12:55:16 +01:00
|
|
|
infer::SafeDestructor(span) => {
|
|
|
|
self.tcx.sess.span_note(
|
|
|
|
span,
|
|
|
|
"...so that references are valid when the destructor \
|
|
|
|
runs")
|
|
|
|
}
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
pub trait Resolvable<'tcx> {
|
|
|
|
fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Self;
|
2014-10-29 18:59:04 +01:00
|
|
|
}
|
|
|
|
|
2014-09-29 22:11:30 +03:00
|
|
|
impl<'tcx> Resolvable<'tcx> for Ty<'tcx> {
|
|
|
|
fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Ty<'tcx> {
|
2014-12-01 10:11:59 -05:00
|
|
|
infcx.resolve_type_vars_if_possible(self)
|
2014-10-29 18:59:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-21 18:59:58 +03:00
|
|
|
impl<'tcx> Resolvable<'tcx> for ty::TraitRef<'tcx> {
|
2014-12-14 07:17:23 -05:00
|
|
|
fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>)
|
2015-04-21 18:59:58 +03:00
|
|
|
-> ty::TraitRef<'tcx> {
|
|
|
|
infcx.resolve_type_vars_if_possible(self)
|
2014-12-14 07:17:23 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-17 14:16:28 -05:00
|
|
|
impl<'tcx> Resolvable<'tcx> for ty::PolyTraitRef<'tcx> {
|
|
|
|
fn resolve<'a>(&self,
|
|
|
|
infcx: &InferCtxt<'a, 'tcx>)
|
|
|
|
-> ty::PolyTraitRef<'tcx>
|
|
|
|
{
|
|
|
|
infcx.resolve_type_vars_if_possible(self)
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
fn lifetimes_in_scope(tcx: &ty::ctxt,
|
|
|
|
scope_id: ast::NodeId)
|
2014-08-05 22:59:24 -04:00
|
|
|
-> Vec<ast::LifetimeDef> {
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
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 {
|
2015-02-25 22:05:07 +02:00
|
|
|
ast::ItemFn(_, _, _, _, ref gen, _) => {
|
2015-02-20 14:08:14 -05:00
|
|
|
taken.push_all(&gen.lifetimes);
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
None
|
|
|
|
},
|
|
|
|
_ => None
|
|
|
|
},
|
2014-08-04 13:56:56 -07:00
|
|
|
ast_map::NodeImplItem(ii) => {
|
2015-03-10 12:28:44 +02:00
|
|
|
match ii.node {
|
2015-03-11 23:38:58 +02:00
|
|
|
ast::MethodImplItem(ref sig, _) => {
|
|
|
|
taken.push_all(&sig.generics.lifetimes);
|
2015-03-10 12:28:44 +02:00
|
|
|
Some(ii.id)
|
2014-08-04 13:56:56 -07:00
|
|
|
}
|
2015-03-14 12:05:00 -06:00
|
|
|
ast::MacImplItem(_) => tcx.sess.bug("unexpanded macro"),
|
|
|
|
_ => None,
|
2014-08-04 13:56:56 -07:00
|
|
|
}
|
|
|
|
}
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
_ => 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 {
|
2014-12-28 23:33:18 +01:00
|
|
|
ast::ItemImpl(_, _, ref gen, _, _, _) => {
|
2015-02-01 21:53:25 -05:00
|
|
|
taken.push_all(&gen.lifetimes);
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
}
|
|
|
|
_ => ()
|
|
|
|
},
|
|
|
|
_ => ()
|
|
|
|
},
|
|
|
|
None => ()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return taken;
|
|
|
|
}
|
|
|
|
|
2014-02-15 01:26:51 -05:00
|
|
|
// LifeGiver is responsible for generating fresh lifetime names
|
|
|
|
struct LifeGiver {
|
2014-05-22 16:57:53 -07:00
|
|
|
taken: HashSet<String>,
|
2015-03-25 17:06:52 -07:00
|
|
|
counter: Cell<usize>,
|
2014-02-15 01:26:51 -05:00
|
|
|
generated: RefCell<Vec<ast::Lifetime>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl LifeGiver {
|
2014-08-05 22:59:24 -04:00
|
|
|
fn with_taken(taken: &[ast::LifetimeDef]) -> LifeGiver {
|
2014-02-15 01:26:51 -05:00
|
|
|
let mut taken_ = HashSet::new();
|
2015-01-31 12:20:46 -05:00
|
|
|
for lt in taken {
|
2015-02-04 00:03:39 +01:00
|
|
|
let lt_name = token::get_name(lt.lifetime.name).to_string();
|
2014-02-15 01:26:51 -05:00
|
|
|
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 {
|
2015-06-18 01:02:58 +03:00
|
|
|
let lifetime;
|
2014-02-15 01:26:51 -05:00
|
|
|
loop {
|
2015-06-08 16:55:35 +02:00
|
|
|
let mut s = String::from("'");
|
2015-02-20 14:08:14 -05:00
|
|
|
s.push_str(&num_to_string(self.counter.get()));
|
2014-02-15 01:26:51 -05:00
|
|
|
if !self.taken.contains(&s) {
|
|
|
|
lifetime = name_to_dummy_lifetime(
|
2015-02-18 14:48:57 -05:00
|
|
|
token::str_to_ident(&s[..]).name);
|
2014-03-20 19:49:20 -07:00
|
|
|
self.generated.borrow_mut().push(lifetime);
|
2014-02-15 01:26:51 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
self.inc_counter();
|
|
|
|
}
|
|
|
|
self.inc_counter();
|
|
|
|
return lifetime;
|
|
|
|
|
|
|
|
// 0 .. 25 generates a .. z, 26 .. 51 generates aa .. zz, and so on
|
2015-03-25 17:06:52 -07:00
|
|
|
fn num_to_string(counter: usize) -> String {
|
2014-05-22 16:57:53 -07:00
|
|
|
let mut s = String::new();
|
2014-02-15 01:26:51 -05:00
|
|
|
let (n, r) = (counter/26 + 1, counter % 26);
|
|
|
|
let letter: char = from_u32((r+97) as u32).unwrap();
|
2015-01-26 15:46:12 -05:00
|
|
|
for _ in 0..n {
|
2014-10-14 23:05:01 -07:00
|
|
|
s.push(letter);
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2014-05-09 18:45:36 -07:00
|
|
|
s
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_generated_lifetimes(&self) -> Vec<ast::Lifetime> {
|
2014-03-28 10:29:55 -07:00
|
|
|
self.generated.borrow().clone()
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
}
|