From bf164bc6e3b81b9999ad4baddb91079a99f49ab4 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda <arielb1@mail.tau.ac.il> Date: Tue, 30 Jun 2015 00:32:39 +0300 Subject: [PATCH] Fix lifetime elision region accounting This merges accumulate_regions_in_type with ty_fold::collect_regions. Fixes #26638 --- .../middle/infer/higher_ranked/mod.rs | 15 +- src/librustc/middle/ty.rs | 67 ++---- src/librustc/middle/ty_fold.rs | 30 ++- src/librustc/middle/ty_walk.rs | 1 + src/librustc_typeck/astconv.rs | 199 +++++++++--------- src/librustc_typeck/check/mod.rs | 4 +- src/librustc_typeck/collect.rs | 2 +- src/librustc_typeck/rscope.rs | 29 ++- src/test/compile-fail/issue-26638.rs | 19 ++ 9 files changed, 187 insertions(+), 179 deletions(-) create mode 100644 src/test/compile-fail/issue-26638.rs diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index 9005e1b8c53..64063623f67 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -359,7 +359,7 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>, where T: TypeFoldable<'tcx>, 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, // because the ones at the current level should have been replaced // 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)) - })) + }) } impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> { @@ -437,11 +437,10 @@ impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> { let escaping_types = self.type_variables.borrow().types_escaping_snapshot(&snapshot.type_snapshot); - let escaping_region_vars: FnvHashSet<_> = - escaping_types - .iter() - .flat_map(|&t| ty_fold::collect_regions(self.tcx, &t)) - .collect(); + let mut escaping_region_vars = FnvHashSet(); + for ty in &escaping_types { + ty_fold::collect_regions(self.tcx, ty, &mut escaping_region_vars); + } region_vars.retain(|®ion_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 // responsible for ensuring that (a) `value` contains at least one // 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) { None => r, Some(br) => { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 489ce7bc4cf..1bed9c4e0a8 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1713,6 +1713,16 @@ impl Region { _ => 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, @@ -6783,60 +6793,6 @@ pub enum ExplicitSelfCategory { 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. #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] pub struct Freevar { @@ -6917,7 +6873,8 @@ impl<'tcx> ctxt<'tcx> { where T: TypeFoldable<'tcx> { 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 { ty::ReLateBound(debruijn, br) if debruijn.depth >= current_depth => { // should be true if no escaping regions from bound2_value diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 012f5216ed7..284d26b3cd6 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -44,7 +44,7 @@ use std::rc::Rc; use syntax::abi; use syntax::ast; use syntax::owned_slice::OwnedSlice; -use util::nodemap::FnvHashMap; +use util::nodemap::{FnvHashMap, FnvHashSet}; /////////////////////////////////////////////////////////////////////////// // 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> { tcx: &'a ty::ctxt<'tcx>, + skipped_regions: &'a mut bool, current_depth: u32, fld_r: &'a mut (FnMut(ty::Region, u32) -> ty::Region + 'a), } 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 { RegionFolder { tcx: tcx, + skipped_regions: skipped_regions, current_depth: 1, 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> { - let mut vec = Vec::new(); - fold_regions(tcx, value, |r, _| { vec.push(r); r }); - vec + let mut have_bound_regions = false; + fold_regions(tcx, value, &mut have_bound_regions, + |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>, value: &T, + skipped_regions: &mut bool, mut f: F) -> T where F : FnMut(ty::Region, u32) -> ty::Region, 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> @@ -834,6 +847,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> ty::ReLateBound(debruijn, _) if debruijn.depth < self.current_depth => { debug!("RegionFolder.fold_region({:?}) skipped bound region (current depth={})", r, self.current_depth); + *self.skipped_regions = true; r } _ => { @@ -989,7 +1003,7 @@ pub fn shift_regions<'tcx, T:TypeFoldable<'tcx>>(tcx: &ty::ctxt<'tcx>, debug!("shift_regions(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) })) } diff --git a/src/librustc/middle/ty_walk.rs b/src/librustc/middle/ty_walk.rs index b34eb2ddb1e..3e9a402f949 100644 --- a/src/librustc/middle/ty_walk.rs +++ b/src/librustc/middle/ty_walk.rs @@ -9,6 +9,7 @@ // except according to those terms. //! An iterator over the type substructure. +//! WARNING: this does not keep track of the region depth. use middle::ty::{self, Ty}; use std::iter::Iterator; diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 2575dc0184f..a55a8ff109e 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -59,7 +59,8 @@ use middle::traits; use middle::ty::{self, RegionEscape, Ty, ToPredicate, HasTypeFlags}; use middle::ty_fold; use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ExplicitRscope, - ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope}; + ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope, + ElisionFailureInfo, ElidedLifetime}; use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::nodemap::FnvHashSet; @@ -186,6 +187,58 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime) 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>( this: &AstConv<'tcx>, rscope: &RegionScope, @@ -197,61 +250,15 @@ pub fn opt_ast_region_to_region<'tcx>( ast_region_to_region(this.tcx(), lifetime) } - None => { - match rscope.anon_regions(default_span, 1) { - Err(v) => { - debug!("optional region in illegal location"); - span_err!(this.tcx().sess, default_span, E0106, - "missing lifetime specifier"); - match v { - 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 + None => match rscope.anon_regions(default_span, 1) { + Ok(rs) => rs[0], + Err(params) => { + span_err!(this.tcx().sess, default_span, E0106, + "missing lifetime specifier"); + if let Some(params) = params { + report_elision_failure(this.tcx(), default_span, params); } - - Ok(rs) => rs[0], + ty::ReStatic } } }; @@ -505,48 +512,54 @@ fn convert_angle_bracketed_parameters<'tcx>(this: &AstConv<'tcx>, /// Returns the appropriate lifetime to use for any output lifetimes /// (if one exists) and a vector of the (pattern, number of lifetimes) /// corresponding to each input type/pattern. -fn find_implied_output_region(input_tys: &[Ty], input_pats: Vec<String>) - -> (Option<ty::Region>, Vec<(String, usize)>) +fn find_implied_output_region<'tcx>(tcx: &ty::ctxt<'tcx>, + 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; for (input_type, input_pat) in input_tys.iter().zip(input_pats) { - let mut accumulator = Vec::new(); - input_type.accumulate_lifetimes_in_type(&mut accumulator); + let mut regions = FnvHashSet(); + 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={:?}", ®ions, input_type, have_bound_regions); + + if regions.len() == 1 { // there's a chance that the unique lifetime of this // iteration will be the appropriate lifetime for output // 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(|&(_, n)| n).sum::<usize>() == 1 { - assert!(possible_implied_output_region.is_some()); - possible_implied_output_region - } else { - None - }; - (implied_output_region, lifetimes_for_params) + if lifetimes_for_params.iter().map(|e| e.lifetime_count).sum::<usize>() == 1 { + Ok(possible_implied_output_region.unwrap()) + } else { + Err(Some(lifetimes_for_params)) + } } fn convert_ty_with_lifetime_elision<'tcx>(this: &AstConv<'tcx>, - implied_output_region: Option<ty::Region>, - param_lifetimes: Vec<(String, usize)>, + elided_lifetime: ElidedLifetime, ty: &ast::Ty) -> Ty<'tcx> { - match implied_output_region { - Some(implied_output_region) => { + match elided_lifetime { + Ok(implied_output_region) => { let rb = ElidableRscope::new(implied_output_region); ast_ty_to_ty(this, &rb, ty) } - None => { + Err(param_lifetimes) => { // All regions must be explicitly specified in the output // if the lifetime elision rules do not apply. This saves // the user from potentially-confusing errors. @@ -576,8 +589,7 @@ fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>, .collect::<Vec<Ty<'tcx>>>(); let input_params: Vec<_> = repeat(String::new()).take(inputs.len()).collect(); - let (implied_output_region, - params_lifetimes) = find_implied_output_region(&*inputs, input_params); + let implied_output_region = find_implied_output_region(this.tcx(), &inputs, input_params); let input_ty = this.tcx().mk_tup(inputs); @@ -585,8 +597,7 @@ fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>, Some(ref output_ty) => { (convert_ty_with_lifetime_elision(this, implied_output_region, - params_lifetimes, - &**output_ty), + &output_ty), output_ty.span) } 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 // region of the self parameter. 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), Some(self_info) => { // 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 // reference) in the arguments, then any anonymous regions in the output // have that lifetime. - let lifetimes_for_params = if implied_output_region.is_none() { - let input_tys = if self_ty.is_some() { - // Skip the first argument if `self` is present. - &self_and_input_tys[1..] - } else { - &self_and_input_tys[..] - }; + let implied_output_region = match implied_output_region { + Some(r) => Ok(r), + None => { + let input_tys = if self_ty.is_some() { + // Skip the first argument if `self` is present. + &self_and_input_tys[1..] + } else { + &self_and_input_tys[..] + }; - let (ior, lfp) = find_implied_output_region(input_tys, input_pats); - implied_output_region = ior; - lfp - } else { - vec![] + find_implied_output_region(this.tcx(), input_tys, input_pats) + } }; 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) => ty::FnConverging(convert_ty_with_lifetime_elision(this, implied_output_region, - lifetimes_for_params, - &**output)), + &output)), ast::DefaultReturn(..) => ty::FnConverging(this.tcx().mk_nil()), ast::NoReturn(..) => ty::FnDiverging }; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7e87dc6540e..2db1598db4b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -97,7 +97,7 @@ use middle::ty::{Disr, ParamTy, ParameterEnvironment}; use middle::ty::{self, HasTypeFlags, RegionEscape, ToPolyTraitRef, Ty}; use middle::ty::{MethodCall, MethodCallee}; use middle::ty_fold::{TypeFolder, TypeFoldable}; -use rscope::RegionScope; +use rscope::{ElisionFailureInfo, RegionScope}; use session::Session; use {CrateCtxt, lookup_full_def, require_same_types}; use TypeAndSubsts; @@ -1796,7 +1796,7 @@ impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> { } 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(|_| { self.infcx().next_region_var(infer::MiscVariable(span)) }).collect()) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d4f04987a81..7909908079f 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2248,7 +2248,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( * 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 { ty::ReEarlyBound(data) => { let def_id = local_def(data.param_id); diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index c908e21626e..b416026ba01 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -16,6 +16,15 @@ use std::cell::Cell; use std::iter::repeat; 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 /// example, if one writes the type `&Foo`, then the lifetime of /// this reference has been omitted. When converting this @@ -30,7 +39,7 @@ pub trait RegionScope { fn anon_regions(&self, span: Span, 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 /// be derived from the object traits, what should we use? If @@ -51,16 +60,16 @@ impl RegionScope for ExplicitRscope { fn anon_regions(&self, _span: Span, _count: usize) - -> Result<Vec<ty::Region>, Option<Vec<(String, usize)>>> { + -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>> { Err(None) } } // Same as `ExplicitRscope`, but provides some extra information for diagnostics -pub struct UnelidableRscope(Vec<(String, usize)>); +pub struct UnelidableRscope(Option<Vec<ElisionFailureInfo>>); impl UnelidableRscope { - pub fn new(v: Vec<(String, usize)>) -> UnelidableRscope { + pub fn new(v: Option<Vec<ElisionFailureInfo>>) -> UnelidableRscope { UnelidableRscope(v) } } @@ -73,9 +82,9 @@ impl RegionScope for UnelidableRscope { fn anon_regions(&self, _span: Span, _count: usize) - -> Result<Vec<ty::Region>, Option<Vec<(String, usize)>>> { + -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>> { let UnelidableRscope(ref v) = *self; - Err(Some(v.clone())) + Err(v.clone()) } } @@ -104,7 +113,7 @@ impl RegionScope for ElidableRscope { fn anon_regions(&self, _span: Span, count: usize) - -> Result<Vec<ty::Region>, Option<Vec<(String, usize)>>> + -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>> { Ok(repeat(self.default).take(count).collect()) } @@ -141,7 +150,7 @@ impl RegionScope for BindingRscope { fn anon_regions(&self, _: Span, 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()) } @@ -177,7 +186,7 @@ impl<'r> RegionScope for ObjectLifetimeDefaultRscope<'r> { fn anon_regions(&self, span: Span, count: usize) - -> Result<Vec<ty::Region>, Option<Vec<(String, usize)>>> + -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>> { self.base_scope.anon_regions(span, count) } @@ -204,7 +213,7 @@ impl<'r> RegionScope for ShiftedRscope<'r> { fn anon_regions(&self, span: Span, 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) { Ok(mut v) => { diff --git a/src/test/compile-fail/issue-26638.rs b/src/test/compile-fail/issue-26638.rs new file mode 100644 index 00000000000..edb9ab47fc6 --- /dev/null +++ b/src/test/compile-fail/issue-26638.rs @@ -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() {}