mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 17:24:06 +00:00
Fix lifetime elision region accounting
This merges accumulate_regions_in_type with ty_fold::collect_regions. Fixes #26638
This commit is contained in:
parent
a1110bc3a3
commit
bf164bc6e3
@ -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) => {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}))
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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())
|
||||
|
@ -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);
|
||||
|
@ -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) => {
|
||||
|
19
src/test/compile-fail/issue-26638.rs
Normal file
19
src/test/compile-fail/issue-26638.rs
Normal 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() {}
|
Loading…
Reference in New Issue
Block a user