Fix lifetime elision region accounting

This merges accumulate_regions_in_type with ty_fold::collect_regions.
Fixes #26638
This commit is contained in:
Ariel Ben-Yehuda 2015-06-30 00:32:39 +03:00
parent a1110bc3a3
commit bf164bc6e3
9 changed files with 187 additions and 179 deletions

View File

@ -359,7 +359,7 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>,
where T: TypeFoldable<'tcx>, where T: TypeFoldable<'tcx>,
F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region, F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region,
{ {
unbound_value.fold_with(&mut ty_fold::RegionFolder::new(tcx, &mut |region, current_depth| { ty_fold::fold_regions(tcx, unbound_value, &mut false, |region, current_depth| {
// we should only be encountering "escaping" late-bound regions here, // we should only be encountering "escaping" late-bound regions here,
// because the ones at the current level should have been replaced // because the ones at the current level should have been replaced
// with fresh variables // with fresh variables
@ -369,7 +369,7 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>,
}); });
fldr(region, ty::DebruijnIndex::new(current_depth)) fldr(region, ty::DebruijnIndex::new(current_depth))
})) })
} }
impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> { impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> {
@ -437,11 +437,10 @@ impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> {
let escaping_types = let escaping_types =
self.type_variables.borrow().types_escaping_snapshot(&snapshot.type_snapshot); self.type_variables.borrow().types_escaping_snapshot(&snapshot.type_snapshot);
let escaping_region_vars: FnvHashSet<_> = let mut escaping_region_vars = FnvHashSet();
escaping_types for ty in &escaping_types {
.iter() ty_fold::collect_regions(self.tcx, ty, &mut escaping_region_vars);
.flat_map(|&t| ty_fold::collect_regions(self.tcx, &t)) }
.collect();
region_vars.retain(|&region_vid| { region_vars.retain(|&region_vid| {
let r = ty::ReInfer(ty::ReVar(region_vid)); let r = ty::ReInfer(ty::ReVar(region_vid));
@ -649,7 +648,7 @@ pub fn plug_leaks<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
// binder is that we encountered in `value`. The caller is // binder is that we encountered in `value`. The caller is
// responsible for ensuring that (a) `value` contains at least one // responsible for ensuring that (a) `value` contains at least one
// binder and (b) that binder is the one we want to use. // binder and (b) that binder is the one we want to use.
let result = ty_fold::fold_regions(infcx.tcx, &value, |r, current_depth| { let result = ty_fold::fold_regions(infcx.tcx, &value, &mut false, |r, current_depth| {
match inv_skol_map.get(&r) { match inv_skol_map.get(&r) {
None => r, None => r,
Some(br) => { Some(br) => {

View File

@ -1713,6 +1713,16 @@ impl Region {
_ => false, _ => false,
} }
} }
/// Returns the depth of `self` from the (1-based) binding level `depth`
pub fn from_depth(&self, depth: u32) -> Region {
match *self {
ty::ReLateBound(debruijn, r) => ty::ReLateBound(DebruijnIndex {
depth: debruijn.depth - (depth - 1)
}, r),
r => r
}
}
} }
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash,
@ -6783,60 +6793,6 @@ pub enum ExplicitSelfCategory {
ByBoxExplicitSelfCategory, ByBoxExplicitSelfCategory,
} }
impl<'tcx> TyS<'tcx> {
/// Pushes all the lifetimes in the given type onto the given list. A
/// "lifetime in a type" is a lifetime specified by a reference or a lifetime
/// in a list of type substitutions. This does *not* traverse into nominal
/// types, nor does it resolve fictitious types.
pub fn accumulate_lifetimes_in_type(&self, accumulator: &mut Vec<ty::Region>) {
for ty in self.walk() {
match ty.sty {
TyRef(region, _) => {
accumulator.push(*region)
}
TyTrait(ref t) => {
accumulator.push_all(t.principal.0.substs.regions().as_slice());
}
TyEnum(_, substs) |
TyStruct(_, substs) => {
accum_substs(accumulator, substs);
}
TyClosure(_, substs) => {
accum_substs(accumulator, substs);
}
TyBool |
TyChar |
TyInt(_) |
TyUint(_) |
TyFloat(_) |
TyBox(_) |
TyStr |
TyArray(_, _) |
TySlice(_) |
TyRawPtr(_) |
TyBareFn(..) |
TyTuple(_) |
TyProjection(_) |
TyParam(_) |
TyInfer(_) |
TyError => {
}
}
}
fn accum_substs(accumulator: &mut Vec<Region>, substs: &Substs) {
match substs.regions {
subst::ErasedRegions => {}
subst::NonerasedRegions(ref regions) => {
for region in regions {
accumulator.push(*region)
}
}
}
}
}
}
/// A free variable referred to in a function. /// A free variable referred to in a function.
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] #[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
pub struct Freevar { pub struct Freevar {
@ -6917,7 +6873,8 @@ impl<'tcx> ctxt<'tcx> {
where T: TypeFoldable<'tcx> where T: TypeFoldable<'tcx>
{ {
let bound0_value = bound2_value.skip_binder().skip_binder(); let bound0_value = bound2_value.skip_binder().skip_binder();
let value = ty_fold::fold_regions(self, bound0_value, |region, current_depth| { let value = ty_fold::fold_regions(self, bound0_value, &mut false,
|region, current_depth| {
match region { match region {
ty::ReLateBound(debruijn, br) if debruijn.depth >= current_depth => { ty::ReLateBound(debruijn, br) if debruijn.depth >= current_depth => {
// should be true if no escaping regions from bound2_value // should be true if no escaping regions from bound2_value

View File

@ -44,7 +44,7 @@ use std::rc::Rc;
use syntax::abi; use syntax::abi;
use syntax::ast; use syntax::ast;
use syntax::owned_slice::OwnedSlice; use syntax::owned_slice::OwnedSlice;
use util::nodemap::FnvHashMap; use util::nodemap::{FnvHashMap, FnvHashSet};
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Two generic traits // Two generic traits
@ -783,38 +783,51 @@ impl<'a, 'tcx, F> TypeFolder<'tcx> for BottomUpFolder<'a, 'tcx, F> where
pub struct RegionFolder<'a, 'tcx: 'a> { pub struct RegionFolder<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>, tcx: &'a ty::ctxt<'tcx>,
skipped_regions: &'a mut bool,
current_depth: u32, current_depth: u32,
fld_r: &'a mut (FnMut(ty::Region, u32) -> ty::Region + 'a), fld_r: &'a mut (FnMut(ty::Region, u32) -> ty::Region + 'a),
} }
impl<'a, 'tcx> RegionFolder<'a, 'tcx> { impl<'a, 'tcx> RegionFolder<'a, 'tcx> {
pub fn new<F>(tcx: &'a ty::ctxt<'tcx>, fld_r: &'a mut F) -> RegionFolder<'a, 'tcx> pub fn new<F>(tcx: &'a ty::ctxt<'tcx>,
skipped_regions: &'a mut bool,
fld_r: &'a mut F) -> RegionFolder<'a, 'tcx>
where F : FnMut(ty::Region, u32) -> ty::Region where F : FnMut(ty::Region, u32) -> ty::Region
{ {
RegionFolder { RegionFolder {
tcx: tcx, tcx: tcx,
skipped_regions: skipped_regions,
current_depth: 1, current_depth: 1,
fld_r: fld_r, fld_r: fld_r,
} }
} }
} }
pub fn collect_regions<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> Vec<ty::Region> /// Collects the free and escaping regions in `value` into `region_set`. Returns
/// whether any late-bound regions were skipped
pub fn collect_regions<'tcx,T>(tcx: &ty::ctxt<'tcx>,
value: &T,
region_set: &mut FnvHashSet<ty::Region>) -> bool
where T : TypeFoldable<'tcx> where T : TypeFoldable<'tcx>
{ {
let mut vec = Vec::new(); let mut have_bound_regions = false;
fold_regions(tcx, value, |r, _| { vec.push(r); r }); fold_regions(tcx, value, &mut have_bound_regions,
vec |r, d| { region_set.insert(r.from_depth(d)); r });
have_bound_regions
} }
/// Folds the escaping and free regions in `value` using `f`, and
/// sets `skipped_regions` to true if any late-bound region was found
/// and skipped.
pub fn fold_regions<'tcx,T,F>(tcx: &ty::ctxt<'tcx>, pub fn fold_regions<'tcx,T,F>(tcx: &ty::ctxt<'tcx>,
value: &T, value: &T,
skipped_regions: &mut bool,
mut f: F) mut f: F)
-> T -> T
where F : FnMut(ty::Region, u32) -> ty::Region, where F : FnMut(ty::Region, u32) -> ty::Region,
T : TypeFoldable<'tcx>, T : TypeFoldable<'tcx>,
{ {
value.fold_with(&mut RegionFolder::new(tcx, &mut f)) value.fold_with(&mut RegionFolder::new(tcx, skipped_regions, &mut f))
} }
impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx>
@ -834,6 +847,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx>
ty::ReLateBound(debruijn, _) if debruijn.depth < self.current_depth => { ty::ReLateBound(debruijn, _) if debruijn.depth < self.current_depth => {
debug!("RegionFolder.fold_region({:?}) skipped bound region (current depth={})", debug!("RegionFolder.fold_region({:?}) skipped bound region (current depth={})",
r, self.current_depth); r, self.current_depth);
*self.skipped_regions = true;
r r
} }
_ => { _ => {
@ -989,7 +1003,7 @@ pub fn shift_regions<'tcx, T:TypeFoldable<'tcx>>(tcx: &ty::ctxt<'tcx>,
debug!("shift_regions(value={:?}, amount={})", debug!("shift_regions(value={:?}, amount={})",
value, amount); value, amount);
value.fold_with(&mut RegionFolder::new(tcx, &mut |region, _current_depth| { value.fold_with(&mut RegionFolder::new(tcx, &mut false, &mut |region, _current_depth| {
shift_region(region, amount) shift_region(region, amount)
})) }))
} }

View File

@ -9,6 +9,7 @@
// except according to those terms. // except according to those terms.
//! An iterator over the type substructure. //! An iterator over the type substructure.
//! WARNING: this does not keep track of the region depth.
use middle::ty::{self, Ty}; use middle::ty::{self, Ty};
use std::iter::Iterator; use std::iter::Iterator;

View File

@ -59,7 +59,8 @@ use middle::traits;
use middle::ty::{self, RegionEscape, Ty, ToPredicate, HasTypeFlags}; use middle::ty::{self, RegionEscape, Ty, ToPredicate, HasTypeFlags};
use middle::ty_fold; use middle::ty_fold;
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ExplicitRscope, use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ExplicitRscope,
ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope}; ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope,
ElisionFailureInfo, ElidedLifetime};
use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::common::{ErrorReported, FN_OUTPUT_NAME};
use util::nodemap::FnvHashSet; use util::nodemap::FnvHashSet;
@ -186,6 +187,58 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime)
r r
} }
fn report_elision_failure(
tcx: &ty::ctxt,
default_span: Span,
params: Vec<ElisionFailureInfo>)
{
let mut m = String::new();
let len = params.len();
for (i, info) in params.into_iter().enumerate() {
let ElisionFailureInfo {
name, lifetime_count: n, have_bound_regions
} = info;
let help_name = if name.is_empty() {
format!("argument {}", i + 1)
} else {
format!("`{}`", name)
};
m.push_str(&(if n == 1 {
help_name
} else {
format!("one of {}'s {} elided {}lifetimes", help_name, n,
if have_bound_regions { "free " } else { "" } )
})[..]);
if len == 2 && i == 0 {
m.push_str(" or ");
} else if i + 2 == len {
m.push_str(", or ");
} else if i + 1 != len {
m.push_str(", ");
}
}
if len == 1 {
fileline_help!(tcx.sess, default_span,
"this function's return type contains a borrowed value, but \
the signature does not say which {} it is borrowed from",
m);
} else if len == 0 {
fileline_help!(tcx.sess, default_span,
"this function's return type contains a borrowed value, but \
there is no value for it to be borrowed from");
fileline_help!(tcx.sess, default_span,
"consider giving it a 'static lifetime");
} else {
fileline_help!(tcx.sess, default_span,
"this function's return type contains a borrowed value, but \
the signature does not say whether it is borrowed from {}",
m);
}
}
pub fn opt_ast_region_to_region<'tcx>( pub fn opt_ast_region_to_region<'tcx>(
this: &AstConv<'tcx>, this: &AstConv<'tcx>,
rscope: &RegionScope, rscope: &RegionScope,
@ -197,61 +250,15 @@ pub fn opt_ast_region_to_region<'tcx>(
ast_region_to_region(this.tcx(), lifetime) ast_region_to_region(this.tcx(), lifetime)
} }
None => { None => match rscope.anon_regions(default_span, 1) {
match rscope.anon_regions(default_span, 1) { Ok(rs) => rs[0],
Err(v) => { Err(params) => {
debug!("optional region in illegal location"); span_err!(this.tcx().sess, default_span, E0106,
span_err!(this.tcx().sess, default_span, E0106, "missing lifetime specifier");
"missing lifetime specifier"); if let Some(params) = params {
match v { report_elision_failure(this.tcx(), default_span, params);
Some(v) => {
let mut m = String::new();
let len = v.len();
for (i, (name, n)) in v.into_iter().enumerate() {
let help_name = if name.is_empty() {
format!("argument {}", i + 1)
} else {
format!("`{}`", name)
};
m.push_str(&(if n == 1 {
help_name
} else {
format!("one of {}'s {} elided lifetimes", help_name, n)
})[..]);
if len == 2 && i == 0 {
m.push_str(" or ");
} else if i + 2 == len {
m.push_str(", or ");
} else if i + 1 != len {
m.push_str(", ");
}
}
if len == 1 {
fileline_help!(this.tcx().sess, default_span,
"this function's return type contains a borrowed value, but \
the signature does not say which {} it is borrowed from",
m);
} else if len == 0 {
fileline_help!(this.tcx().sess, default_span,
"this function's return type contains a borrowed value, but \
there is no value for it to be borrowed from");
fileline_help!(this.tcx().sess, default_span,
"consider giving it a 'static lifetime");
} else {
fileline_help!(this.tcx().sess, default_span,
"this function's return type contains a borrowed value, but \
the signature does not say whether it is borrowed from {}",
m);
}
}
None => {},
}
ty::ReStatic
} }
ty::ReStatic
Ok(rs) => rs[0],
} }
} }
}; };
@ -505,48 +512,54 @@ fn convert_angle_bracketed_parameters<'tcx>(this: &AstConv<'tcx>,
/// Returns the appropriate lifetime to use for any output lifetimes /// Returns the appropriate lifetime to use for any output lifetimes
/// (if one exists) and a vector of the (pattern, number of lifetimes) /// (if one exists) and a vector of the (pattern, number of lifetimes)
/// corresponding to each input type/pattern. /// corresponding to each input type/pattern.
fn find_implied_output_region(input_tys: &[Ty], input_pats: Vec<String>) fn find_implied_output_region<'tcx>(tcx: &ty::ctxt<'tcx>,
-> (Option<ty::Region>, Vec<(String, usize)>) input_tys: &[Ty<'tcx>],
input_pats: Vec<String>) -> ElidedLifetime
{ {
let mut lifetimes_for_params: Vec<(String, usize)> = Vec::new(); let mut lifetimes_for_params = Vec::new();
let mut possible_implied_output_region = None; let mut possible_implied_output_region = None;
for (input_type, input_pat) in input_tys.iter().zip(input_pats) { for (input_type, input_pat) in input_tys.iter().zip(input_pats) {
let mut accumulator = Vec::new(); let mut regions = FnvHashSet();
input_type.accumulate_lifetimes_in_type(&mut accumulator); let have_bound_regions = ty_fold::collect_regions(tcx,
input_type,
&mut regions);
if accumulator.len() == 1 { debug!("find_implied_output_regions: collected {:?} from {:?} \
have_bound_regions={:?}", &regions, input_type, have_bound_regions);
if regions.len() == 1 {
// there's a chance that the unique lifetime of this // there's a chance that the unique lifetime of this
// iteration will be the appropriate lifetime for output // iteration will be the appropriate lifetime for output
// parameters, so lets store it. // parameters, so lets store it.
possible_implied_output_region = Some(accumulator[0]) possible_implied_output_region = regions.iter().cloned().next();
} }
lifetimes_for_params.push((input_pat, accumulator.len())); lifetimes_for_params.push(ElisionFailureInfo {
name: input_pat,
lifetime_count: regions.len(),
have_bound_regions: have_bound_regions
});
} }
let implied_output_region = if lifetimes_for_params.iter().map(|e| e.lifetime_count).sum::<usize>() == 1 {
if lifetimes_for_params.iter().map(|&(_, n)| n).sum::<usize>() == 1 { Ok(possible_implied_output_region.unwrap())
assert!(possible_implied_output_region.is_some()); } else {
possible_implied_output_region Err(Some(lifetimes_for_params))
} else { }
None
};
(implied_output_region, lifetimes_for_params)
} }
fn convert_ty_with_lifetime_elision<'tcx>(this: &AstConv<'tcx>, fn convert_ty_with_lifetime_elision<'tcx>(this: &AstConv<'tcx>,
implied_output_region: Option<ty::Region>, elided_lifetime: ElidedLifetime,
param_lifetimes: Vec<(String, usize)>,
ty: &ast::Ty) ty: &ast::Ty)
-> Ty<'tcx> -> Ty<'tcx>
{ {
match implied_output_region { match elided_lifetime {
Some(implied_output_region) => { Ok(implied_output_region) => {
let rb = ElidableRscope::new(implied_output_region); let rb = ElidableRscope::new(implied_output_region);
ast_ty_to_ty(this, &rb, ty) ast_ty_to_ty(this, &rb, ty)
} }
None => { Err(param_lifetimes) => {
// All regions must be explicitly specified in the output // All regions must be explicitly specified in the output
// if the lifetime elision rules do not apply. This saves // if the lifetime elision rules do not apply. This saves
// the user from potentially-confusing errors. // the user from potentially-confusing errors.
@ -576,8 +589,7 @@ fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>,
.collect::<Vec<Ty<'tcx>>>(); .collect::<Vec<Ty<'tcx>>>();
let input_params: Vec<_> = repeat(String::new()).take(inputs.len()).collect(); let input_params: Vec<_> = repeat(String::new()).take(inputs.len()).collect();
let (implied_output_region, let implied_output_region = find_implied_output_region(this.tcx(), &inputs, input_params);
params_lifetimes) = find_implied_output_region(&*inputs, input_params);
let input_ty = this.tcx().mk_tup(inputs); let input_ty = this.tcx().mk_tup(inputs);
@ -585,8 +597,7 @@ fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>,
Some(ref output_ty) => { Some(ref output_ty) => {
(convert_ty_with_lifetime_elision(this, (convert_ty_with_lifetime_elision(this,
implied_output_region, implied_output_region,
params_lifetimes, &output_ty),
&**output_ty),
output_ty.span) output_ty.span)
} }
None => { None => {
@ -1705,7 +1716,7 @@ fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>,
// here), if self is by-reference, then the implied output region is the // here), if self is by-reference, then the implied output region is the
// region of the self parameter. // region of the self parameter.
let mut explicit_self_category_result = None; let mut explicit_self_category_result = None;
let (self_ty, mut implied_output_region) = match opt_self_info { let (self_ty, implied_output_region) = match opt_self_info {
None => (None, None), None => (None, None),
Some(self_info) => { Some(self_info) => {
// This type comes from an impl or trait; no late-bound // This type comes from an impl or trait; no late-bound
@ -1756,19 +1767,18 @@ fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>,
// Second, if there was exactly one lifetime (either a substitution or a // Second, if there was exactly one lifetime (either a substitution or a
// reference) in the arguments, then any anonymous regions in the output // reference) in the arguments, then any anonymous regions in the output
// have that lifetime. // have that lifetime.
let lifetimes_for_params = if implied_output_region.is_none() { let implied_output_region = match implied_output_region {
let input_tys = if self_ty.is_some() { Some(r) => Ok(r),
// Skip the first argument if `self` is present. None => {
&self_and_input_tys[1..] let input_tys = if self_ty.is_some() {
} else { // Skip the first argument if `self` is present.
&self_and_input_tys[..] &self_and_input_tys[1..]
}; } else {
&self_and_input_tys[..]
};
let (ior, lfp) = find_implied_output_region(input_tys, input_pats); find_implied_output_region(this.tcx(), input_tys, input_pats)
implied_output_region = ior; }
lfp
} else {
vec![]
}; };
let output_ty = match decl.output { let output_ty = match decl.output {
@ -1777,8 +1787,7 @@ fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>,
ast::Return(ref output) => ast::Return(ref output) =>
ty::FnConverging(convert_ty_with_lifetime_elision(this, ty::FnConverging(convert_ty_with_lifetime_elision(this,
implied_output_region, implied_output_region,
lifetimes_for_params, &output)),
&**output)),
ast::DefaultReturn(..) => ty::FnConverging(this.tcx().mk_nil()), ast::DefaultReturn(..) => ty::FnConverging(this.tcx().mk_nil()),
ast::NoReturn(..) => ty::FnDiverging ast::NoReturn(..) => ty::FnDiverging
}; };

View File

@ -97,7 +97,7 @@ use middle::ty::{Disr, ParamTy, ParameterEnvironment};
use middle::ty::{self, HasTypeFlags, RegionEscape, ToPolyTraitRef, Ty}; use middle::ty::{self, HasTypeFlags, RegionEscape, ToPolyTraitRef, Ty};
use middle::ty::{MethodCall, MethodCallee}; use middle::ty::{MethodCall, MethodCallee};
use middle::ty_fold::{TypeFolder, TypeFoldable}; use middle::ty_fold::{TypeFolder, TypeFoldable};
use rscope::RegionScope; use rscope::{ElisionFailureInfo, RegionScope};
use session::Session; use session::Session;
use {CrateCtxt, lookup_full_def, require_same_types}; use {CrateCtxt, lookup_full_def, require_same_types};
use TypeAndSubsts; use TypeAndSubsts;
@ -1796,7 +1796,7 @@ impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> {
} }
fn anon_regions(&self, span: Span, count: usize) fn anon_regions(&self, span: Span, count: usize)
-> Result<Vec<ty::Region>, Option<Vec<(String, usize)>>> { -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>> {
Ok((0..count).map(|_| { Ok((0..count).map(|_| {
self.infcx().next_region_var(infer::MiscVariable(span)) self.infcx().next_region_var(infer::MiscVariable(span))
}).collect()) }).collect())

View File

@ -2248,7 +2248,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
* before we really have a `ParameterEnvironment` to check. * before we really have a `ParameterEnvironment` to check.
*/ */
ty_fold::fold_regions(tcx, value, |region, _| { ty_fold::fold_regions(tcx, value, &mut false, |region, _| {
match region { match region {
ty::ReEarlyBound(data) => { ty::ReEarlyBound(data) => {
let def_id = local_def(data.param_id); let def_id = local_def(data.param_id);

View File

@ -16,6 +16,15 @@ use std::cell::Cell;
use std::iter::repeat; use std::iter::repeat;
use syntax::codemap::Span; use syntax::codemap::Span;
#[derive(Clone)]
pub struct ElisionFailureInfo {
pub name: String,
pub lifetime_count: usize,
pub have_bound_regions: bool
}
pub type ElidedLifetime = Result<ty::Region, Option<Vec<ElisionFailureInfo>>>;
/// Defines strategies for handling regions that are omitted. For /// Defines strategies for handling regions that are omitted. For
/// example, if one writes the type `&Foo`, then the lifetime of /// example, if one writes the type `&Foo`, then the lifetime of
/// this reference has been omitted. When converting this /// this reference has been omitted. When converting this
@ -30,7 +39,7 @@ pub trait RegionScope {
fn anon_regions(&self, fn anon_regions(&self,
span: Span, span: Span,
count: usize) count: usize)
-> Result<Vec<ty::Region>, Option<Vec<(String, usize)>>>; -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>>;
/// If an object omits any explicit lifetime bound, and none can /// If an object omits any explicit lifetime bound, and none can
/// be derived from the object traits, what should we use? If /// be derived from the object traits, what should we use? If
@ -51,16 +60,16 @@ impl RegionScope for ExplicitRscope {
fn anon_regions(&self, fn anon_regions(&self,
_span: Span, _span: Span,
_count: usize) _count: usize)
-> Result<Vec<ty::Region>, Option<Vec<(String, usize)>>> { -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>> {
Err(None) Err(None)
} }
} }
// Same as `ExplicitRscope`, but provides some extra information for diagnostics // Same as `ExplicitRscope`, but provides some extra information for diagnostics
pub struct UnelidableRscope(Vec<(String, usize)>); pub struct UnelidableRscope(Option<Vec<ElisionFailureInfo>>);
impl UnelidableRscope { impl UnelidableRscope {
pub fn new(v: Vec<(String, usize)>) -> UnelidableRscope { pub fn new(v: Option<Vec<ElisionFailureInfo>>) -> UnelidableRscope {
UnelidableRscope(v) UnelidableRscope(v)
} }
} }
@ -73,9 +82,9 @@ impl RegionScope for UnelidableRscope {
fn anon_regions(&self, fn anon_regions(&self,
_span: Span, _span: Span,
_count: usize) _count: usize)
-> Result<Vec<ty::Region>, Option<Vec<(String, usize)>>> { -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>> {
let UnelidableRscope(ref v) = *self; let UnelidableRscope(ref v) = *self;
Err(Some(v.clone())) Err(v.clone())
} }
} }
@ -104,7 +113,7 @@ impl RegionScope for ElidableRscope {
fn anon_regions(&self, fn anon_regions(&self,
_span: Span, _span: Span,
count: usize) count: usize)
-> Result<Vec<ty::Region>, Option<Vec<(String, usize)>>> -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>>
{ {
Ok(repeat(self.default).take(count).collect()) Ok(repeat(self.default).take(count).collect())
} }
@ -141,7 +150,7 @@ impl RegionScope for BindingRscope {
fn anon_regions(&self, fn anon_regions(&self,
_: Span, _: Span,
count: usize) count: usize)
-> Result<Vec<ty::Region>, Option<Vec<(String, usize)>>> -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>>
{ {
Ok((0..count).map(|_| self.next_region()).collect()) Ok((0..count).map(|_| self.next_region()).collect())
} }
@ -177,7 +186,7 @@ impl<'r> RegionScope for ObjectLifetimeDefaultRscope<'r> {
fn anon_regions(&self, fn anon_regions(&self,
span: Span, span: Span,
count: usize) count: usize)
-> Result<Vec<ty::Region>, Option<Vec<(String, usize)>>> -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>>
{ {
self.base_scope.anon_regions(span, count) self.base_scope.anon_regions(span, count)
} }
@ -204,7 +213,7 @@ impl<'r> RegionScope for ShiftedRscope<'r> {
fn anon_regions(&self, fn anon_regions(&self,
span: Span, span: Span,
count: usize) count: usize)
-> Result<Vec<ty::Region>, Option<Vec<(String, usize)>>> -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>>
{ {
match self.base_scope.anon_regions(span, count) { match self.base_scope.anon_regions(span, count) {
Ok(mut v) => { Ok(mut v) => {

View File

@ -0,0 +1,19 @@
// Copyright 2015 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.
fn parse_type(iter: Box<Iterator<Item=&str>+'static>) -> &str { iter.next() }
//~^ ERROR missing lifetime specifier [E0106]
//~^^ HELP 2 elided lifetimes
fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
//~^ ERROR missing lifetime specifier [E0106]
//~^^ HELP 0 elided free lifetimes
fn main() {}