mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-26 22:53:28 +00:00
adding E0623 for LateBound regions
This commit is contained in:
parent
dead08cb33
commit
cfc7cf3961
@ -1389,30 +1389,66 @@ A lifetime of reference outlives lifetime of borrowed content.
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0312
|
||||
fn make_child<'human, 'elve>(x: &mut &'human isize, y: &mut &'elve isize) {
|
||||
*x = *y;
|
||||
// error: lifetime of reference outlives lifetime of borrowed content
|
||||
fn make_child<'tree, 'human>(
|
||||
x: &'human i32,
|
||||
y: &'tree i32
|
||||
) -> &'human i32 {
|
||||
if x > y
|
||||
{ x }
|
||||
else
|
||||
{ y }
|
||||
// error: lifetime of reference outlives lifetime of borrowed content
|
||||
}
|
||||
```
|
||||
|
||||
The compiler cannot determine if the `human` lifetime will live long enough
|
||||
to keep up on the elve one. To solve this error, you have to give an
|
||||
explicit lifetime hierarchy:
|
||||
The function declares that it returns a reference with the `'human`
|
||||
lifetime, but it may return data with the `'tree` lifetime. As neither
|
||||
lifetime is declared longer than the other, this results in an
|
||||
error. Sometimes, this error is because the function *body* is
|
||||
incorrect -- that is, maybe you did not *mean* to return data from
|
||||
`y`. In that case, you should fix the function body.
|
||||
|
||||
Often, however, the body is correct. In that case, the function
|
||||
signature needs to be altered to match the body, so that the caller
|
||||
understands that data from either `x` or `y` may be returned. The
|
||||
simplest way to do this is to give both function parameters the *same*
|
||||
named lifetime:
|
||||
|
||||
```
|
||||
fn make_child<'human, 'elve: 'human>(x: &mut &'human isize,
|
||||
y: &mut &'elve isize) {
|
||||
*x = *y; // ok!
|
||||
fn make_child<'human>(
|
||||
x: &'human i32,
|
||||
y: &'human i32
|
||||
) -> &'human i32 {
|
||||
if x > y
|
||||
{ x }
|
||||
else
|
||||
{ y } // ok!
|
||||
}
|
||||
```
|
||||
|
||||
Or use the same lifetime for every variable:
|
||||
However, in some cases, you may prefer to explicitly declare that one lifetime
|
||||
outlives another using a `where` clause:
|
||||
|
||||
```
|
||||
fn make_child<'elve>(x: &mut &'elve isize, y: &mut &'elve isize) {
|
||||
*x = *y; // ok!
|
||||
fn make_child<'tree, 'human>(
|
||||
x: &'human i32,
|
||||
y: &'tree i32
|
||||
) -> &'tree i32
|
||||
where
|
||||
'tree: 'human
|
||||
{
|
||||
if x > y
|
||||
{ x }
|
||||
else
|
||||
{ y } // ok!
|
||||
}
|
||||
```
|
||||
|
||||
Here, the where clause `'tree: 'human` can be read as "the lifetime
|
||||
'tree outlives the lifetime 'human" -- meaning, references with the
|
||||
`'tree` lifetime live *at least as long as* references with the
|
||||
`'human` lifetime. Therefore, it is safe to return data with lifetime
|
||||
`'tree` when data with the lifetime `'human` is needed.
|
||||
"##,
|
||||
|
||||
E0317: r##"
|
||||
|
@ -46,9 +46,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
};
|
||||
|
||||
// Determine whether the sub and sup consist of both anonymous (elided) regions.
|
||||
let anon_reg_sup = or_false!(self.is_suitable_anonymous_region(sup));
|
||||
let anon_reg_sup = or_false!(self.is_suitable_region(sup));
|
||||
|
||||
let anon_reg_sub = or_false!(self.is_suitable_anonymous_region(sub));
|
||||
let anon_reg_sub = or_false!(self.is_suitable_region(sub));
|
||||
let scope_def_id_sup = anon_reg_sup.def_id;
|
||||
let bregion_sup = anon_reg_sup.boundregion;
|
||||
let scope_def_id_sub = anon_reg_sub.def_id;
|
||||
@ -57,10 +57,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
let ty_sup = or_false!(self.find_anon_type(sup, &bregion_sup));
|
||||
|
||||
let ty_sub = or_false!(self.find_anon_type(sub, &bregion_sub));
|
||||
debug!("try_report_anon_anon_conflict: found_arg1={:?} sup={:?} br1={:?}",
|
||||
ty_sub,
|
||||
sup,
|
||||
bregion_sup);
|
||||
debug!("try_report_anon_anon_conflict: found_arg2={:?} sub={:?} br2={:?}",
|
||||
ty_sup,
|
||||
sub,
|
||||
bregion_sub);
|
||||
|
||||
let (main_label, label1, label2) = if let (Some(sup_arg), Some(sub_arg)) =
|
||||
(self.find_arg_with_anonymous_region(sup, sup),
|
||||
self.find_arg_with_anonymous_region(sub, sub)) {
|
||||
(self.find_arg_with_region(sup, sup), self.find_arg_with_region(sub, sub)) {
|
||||
|
||||
let (anon_arg_sup, is_first_sup, anon_arg_sub, is_first_sub) =
|
||||
(sup_arg.arg, sup_arg.is_first, sub_arg.arg, sub_arg.is_first);
|
||||
@ -97,6 +104,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
(span_label, span_label_var1, span_label_var2)
|
||||
}
|
||||
} else {
|
||||
debug!("no arg with anon region found");
|
||||
debug!("try_report_anon_anon_conflict: is_suitable(sub) = {:?}",
|
||||
self.is_suitable_region(sub));
|
||||
debug!("try_report_anon_anon_conflict: is_suitable(sup) = {:?}",
|
||||
self.is_suitable_region(sup));
|
||||
return false;
|
||||
};
|
||||
|
||||
@ -124,35 +136,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
/// The function returns the nested type corresponding to the anonymous region
|
||||
/// for e.g. `&u8` and Vec<`&u8`.
|
||||
pub fn find_anon_type(&self, region: Region<'tcx>, br: &ty::BoundRegion) -> Option<&hir::Ty> {
|
||||
if let Some(anon_reg) = self.is_suitable_anonymous_region(region) {
|
||||
if let Some(anon_reg) = self.is_suitable_region(region) {
|
||||
let def_id = anon_reg.def_id;
|
||||
if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
|
||||
let ret_ty = self.tcx.type_of(def_id);
|
||||
if let ty::TyFnDef(_, _) = ret_ty.sty {
|
||||
let inputs: &[_] =
|
||||
match self.tcx.hir.get(node_id) {
|
||||
hir_map::NodeItem(&hir::Item {
|
||||
node: hir::ItemFn(ref fndecl, ..), ..
|
||||
}) => &fndecl.inputs,
|
||||
hir_map::NodeTraitItem(&hir::TraitItem {
|
||||
node: hir::TraitItemKind::Method(ref fndecl, ..),
|
||||
..
|
||||
}) => &fndecl.decl.inputs,
|
||||
hir_map::NodeImplItem(&hir::ImplItem {
|
||||
node: hir::ImplItemKind::Method(ref fndecl, ..),
|
||||
..
|
||||
}) => &fndecl.decl.inputs,
|
||||
let inputs: &[_] = match self.tcx.hir.get(node_id) {
|
||||
hir_map::NodeItem(&hir::Item { node: hir::ItemFn(ref fndecl, ..), .. }) => {
|
||||
&fndecl.inputs
|
||||
}
|
||||
hir_map::NodeTraitItem(&hir::TraitItem {
|
||||
node: hir::TraitItemKind::Method(ref fndecl, ..), ..
|
||||
}) => &fndecl.decl.inputs,
|
||||
hir_map::NodeImplItem(&hir::ImplItem {
|
||||
node: hir::ImplItemKind::Method(ref fndecl, ..), ..
|
||||
}) => &fndecl.decl.inputs,
|
||||
|
||||
_ => &[],
|
||||
};
|
||||
_ => &[],
|
||||
};
|
||||
|
||||
return inputs
|
||||
.iter()
|
||||
.filter_map(|arg| {
|
||||
self.find_component_for_bound_region(&**arg, br)
|
||||
})
|
||||
.next();
|
||||
}
|
||||
return inputs
|
||||
.iter()
|
||||
.filter_map(|arg| self.find_component_for_bound_region(&**arg, br))
|
||||
.next();
|
||||
}
|
||||
}
|
||||
None
|
||||
@ -199,30 +203,62 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, arg: &'gcx hir::Ty) {
|
||||
// Find the index of the anonymous region that was part of the
|
||||
// error. We will then search the function parameters for a bound
|
||||
// region at the right depth with the same index.
|
||||
let br_index = match self.bound_region {
|
||||
ty::BrAnon(index) => index,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
match arg.node {
|
||||
hir::TyRptr(ref lifetime, _) => {
|
||||
// the lifetime of the TyRptr
|
||||
let hir_id = self.infcx.tcx.hir.node_to_hir_id(lifetime.id);
|
||||
match self.infcx.tcx.named_region(hir_id) {
|
||||
// the lifetime of the TyRptr
|
||||
Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)) => {
|
||||
match (self.infcx.tcx.named_region(hir_id), self.bound_region) {
|
||||
// Find the index of the anonymous region that was part of the
|
||||
// error. We will then search the function parameters for a bound
|
||||
// region at the right depth with the same index
|
||||
(Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)),
|
||||
ty::BrAnon(br_index)) => {
|
||||
debug!("LateBoundAnon depth = {:?} anon_index = {:?} br_index={:?}",
|
||||
debruijn_index.depth,
|
||||
anon_index,
|
||||
br_index);
|
||||
if debruijn_index.depth == 1 && anon_index == br_index {
|
||||
self.found_type = Some(arg);
|
||||
return; // we can stop visiting now
|
||||
}
|
||||
}
|
||||
Some(rl::Region::Static) |
|
||||
Some(rl::Region::EarlyBound(_, _)) |
|
||||
Some(rl::Region::LateBound(_, _)) |
|
||||
Some(rl::Region::Free(_, _)) |
|
||||
None => {
|
||||
|
||||
// Find the index of the named region that was part of the
|
||||
// error. We will then search the function parameters for a bound
|
||||
// region at the right depth with the same index
|
||||
(Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => {
|
||||
debug!("EarlyBound self.infcx.tcx.hir.local_def_id(id)={:?} \
|
||||
def_id={:?}",
|
||||
self.infcx.tcx.hir.local_def_id(id),
|
||||
def_id);
|
||||
if self.infcx.tcx.hir.local_def_id(id) == def_id {
|
||||
self.found_type = Some(arg);
|
||||
return; // we can stop visiting now
|
||||
}
|
||||
}
|
||||
|
||||
// Find the index of the named region that was part of the
|
||||
// error. We will then search the function parameters for a bound
|
||||
// region at the right depth with the same index
|
||||
(Some(rl::Region::LateBound(debruijn_index, id)), ty::BrNamed(def_id, _)) => {
|
||||
debug!("FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}",
|
||||
debruijn_index.depth);
|
||||
debug!("self.infcx.tcx.hir.local_def_id(id)={:?}",
|
||||
self.infcx.tcx.hir.local_def_id(id));
|
||||
debug!("def_id={:?}", def_id);
|
||||
if debruijn_index.depth == 1 &&
|
||||
self.infcx.tcx.hir.local_def_id(id) == def_id {
|
||||
self.found_type = Some(arg);
|
||||
return; // we can stop visiting now
|
||||
}
|
||||
}
|
||||
|
||||
(Some(rl::Region::Static), _) |
|
||||
(Some(rl::Region::Free(_, _)), _) |
|
||||
(Some(rl::Region::EarlyBound(_, _)), _) |
|
||||
(Some(rl::Region::LateBound(_, _)), _) |
|
||||
(Some(rl::Region::LateBoundAnon(_, _)), _) |
|
||||
(None, _) => {
|
||||
debug!("no arg found");
|
||||
}
|
||||
}
|
@ -79,7 +79,7 @@ mod need_type_info;
|
||||
mod named_anon_conflict;
|
||||
#[macro_use]
|
||||
mod util;
|
||||
mod anon_anon_conflict;
|
||||
mod different_lifetimes;
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
pub fn note_and_explain_region(self,
|
||||
|
@ -13,6 +13,7 @@
|
||||
use infer::InferCtxt;
|
||||
use infer::region_inference::RegionResolutionError::*;
|
||||
use infer::region_inference::RegionResolutionError;
|
||||
use ty;
|
||||
|
||||
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
// This method generates the error message for the case when
|
||||
@ -24,6 +25,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
_ => return false, // inapplicable
|
||||
};
|
||||
|
||||
debug!("try_report_named_anon_conflict(sub={:?}, sup={:?})",
|
||||
sub,
|
||||
sup);
|
||||
|
||||
// Determine whether the sub and sup consist of one named region ('a)
|
||||
// and one anonymous (elided) region. If so, find the parameter arg
|
||||
// where the anonymous region appears (there must always be one; we
|
||||
@ -31,32 +36,57 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
// version new_ty of its type where the anonymous region is replaced
|
||||
// with the named one.//scope_def_id
|
||||
let (named, anon_arg_info, region_info) =
|
||||
if sub.is_named_region() && self.is_suitable_anonymous_region(sup).is_some() {
|
||||
if self.is_named_region(sub) && self.is_suitable_region(sup).is_some() &&
|
||||
self.find_arg_with_region(sup, sub).is_some() {
|
||||
(sub,
|
||||
self.find_arg_with_anonymous_region(sup, sub).unwrap(),
|
||||
self.is_suitable_anonymous_region(sup).unwrap())
|
||||
} else if sup.is_named_region() && self.is_suitable_anonymous_region(sub).is_some() {
|
||||
self.find_arg_with_region(sup, sub).unwrap(),
|
||||
self.is_suitable_region(sup).unwrap())
|
||||
} else if self.is_named_region(sup) && self.is_suitable_region(sub).is_some() &&
|
||||
self.find_arg_with_region(sub, sup).is_some() {
|
||||
(sup,
|
||||
self.find_arg_with_anonymous_region(sub, sup).unwrap(),
|
||||
self.is_suitable_anonymous_region(sub).unwrap())
|
||||
self.find_arg_with_region(sub, sup).unwrap(),
|
||||
self.is_suitable_region(sub).unwrap())
|
||||
} else {
|
||||
return false; // inapplicable
|
||||
};
|
||||
|
||||
debug!("try_report_named_anon_conflict: named = {:?}", named);
|
||||
debug!("try_report_named_anon_conflict: anon_arg_info = {:?}",
|
||||
anon_arg_info);
|
||||
debug!("try_report_named_anon_conflict: region_info = {:?}",
|
||||
region_info);
|
||||
|
||||
let (arg, new_ty, br, is_first, scope_def_id, is_impl_item) = (anon_arg_info.arg,
|
||||
anon_arg_info.arg_ty,
|
||||
anon_arg_info.bound_region,
|
||||
anon_arg_info.is_first,
|
||||
region_info.def_id,
|
||||
region_info.is_impl_item);
|
||||
match br {
|
||||
ty::BrAnon(_) => {}
|
||||
_ => {
|
||||
/* not an anonymous region */
|
||||
debug!("try_report_named_anon_conflict: not an anonymous region");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if is_impl_item {
|
||||
debug!("try_report_named_anon_conflict: impl item, bail out");
|
||||
return false;
|
||||
}
|
||||
|
||||
if self.is_return_type_anon(scope_def_id, br) || self.is_self_anon(is_first, scope_def_id) {
|
||||
if self.is_return_type_anon(scope_def_id, br) {
|
||||
debug!("try_report_named_anon_conflict: is_return_type_anon({:?}, {:?}) = true",
|
||||
scope_def_id,
|
||||
br);
|
||||
return false;
|
||||
} else if self.is_self_anon(is_first, scope_def_id) {
|
||||
debug!("try_report_named_anon_conflict: is_self_anon({:?}, {:?}) = true",
|
||||
is_first,
|
||||
scope_def_id);
|
||||
return false;
|
||||
} else {
|
||||
|
||||
let (error_var, span_label_var) = if let Some(simple_name) = arg.pat.simple_name() {
|
||||
(format!("the type of `{}`", simple_name), format!("the type of `{}`", simple_name))
|
||||
} else {
|
||||
@ -72,9 +102,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
format!("consider changing {} to `{}`", span_label_var, new_ty))
|
||||
.span_label(span, format!("lifetime `{}` required", named))
|
||||
.emit();
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -18,15 +18,19 @@ use hir::map as hir_map;
|
||||
|
||||
macro_rules! or_false {
|
||||
($v:expr) => {
|
||||
match $v {
|
||||
Some(v) => v,
|
||||
None => return false,
|
||||
}
|
||||
match $v {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
debug!("or_false failed: {}", stringify!($v));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The struct contains the information about the anonymous region
|
||||
// we are searching for.
|
||||
#[derive(Debug)]
|
||||
pub struct AnonymousArgInfo<'tcx> {
|
||||
// the argument corresponding to the anonymous region
|
||||
pub arg: &'tcx hir::Arg,
|
||||
@ -41,6 +45,7 @@ pub struct AnonymousArgInfo<'tcx> {
|
||||
|
||||
// This struct contains information regarding the
|
||||
// Refree((FreeRegion) corresponding to lifetime conflict
|
||||
#[derive(Debug)]
|
||||
pub struct FreeRegionInfo {
|
||||
// def id corresponding to FreeRegion
|
||||
pub def_id: DefId,
|
||||
@ -62,47 +67,54 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
// i32, which is the type of y but with the anonymous region replaced
|
||||
// with 'a, the corresponding bound region and is_first which is true if
|
||||
// the hir::Arg is the first argument in the function declaration.
|
||||
pub fn find_arg_with_anonymous_region(&self,
|
||||
anon_region: Region<'tcx>,
|
||||
replace_region: Region<'tcx>)
|
||||
-> Option<AnonymousArgInfo> {
|
||||
pub fn find_arg_with_region(&self,
|
||||
anon_region: Region<'tcx>,
|
||||
replace_region: Region<'tcx>)
|
||||
-> Option<AnonymousArgInfo> {
|
||||
|
||||
if let ty::ReFree(ref free_region) = *anon_region {
|
||||
let id = free_region.scope;
|
||||
let hir = &self.tcx.hir;
|
||||
if let Some(node_id) = hir.as_local_node_id(id) {
|
||||
if let Some(body_id) = hir.maybe_body_owned_by(node_id) {
|
||||
let body = hir.body(body_id);
|
||||
if let Some(tables) = self.in_progress_tables {
|
||||
body.arguments
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(index, arg)| {
|
||||
let ty = tables.borrow().node_id_to_type(arg.hir_id);
|
||||
let mut found_anon_region = false;
|
||||
let new_arg_ty = self.tcx
|
||||
.fold_regions(&ty, &mut false, |r, _| if *r == *anon_region {
|
||||
found_anon_region = true;
|
||||
replace_region
|
||||
} else {
|
||||
r
|
||||
});
|
||||
if found_anon_region {
|
||||
let is_first = index == 0;
|
||||
Some(AnonymousArgInfo {
|
||||
arg: arg,
|
||||
arg_ty: new_arg_ty,
|
||||
bound_region: free_region.bound_region,
|
||||
is_first: is_first,
|
||||
})
|
||||
let (id, bound_region) = match *anon_region {
|
||||
ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
|
||||
ty::ReEarlyBound(ref ebr) => {
|
||||
(self.tcx.parent_def_id(ebr.def_id).unwrap(),
|
||||
ty::BoundRegion::BrNamed(ebr.def_id, ebr.name))
|
||||
}
|
||||
_ => return None, // not a free region
|
||||
};
|
||||
|
||||
let hir = &self.tcx.hir;
|
||||
if let Some(node_id) = hir.as_local_node_id(id) {
|
||||
if let Some(body_id) = hir.maybe_body_owned_by(node_id) {
|
||||
let body = hir.body(body_id);
|
||||
if let Some(tables) = self.in_progress_tables {
|
||||
body.arguments
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(index, arg)| {
|
||||
let ty = match tables.borrow().node_id_to_type_opt(arg.hir_id) {
|
||||
Some(v) => v,
|
||||
None => return None, // sometimes the tables are not yet populated
|
||||
};
|
||||
let mut found_anon_region = false;
|
||||
let new_arg_ty = self.tcx
|
||||
.fold_regions(&ty, &mut false, |r, _| if *r == *anon_region {
|
||||
found_anon_region = true;
|
||||
replace_region
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.next()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
r
|
||||
});
|
||||
if found_anon_region {
|
||||
let is_first = index == 0;
|
||||
Some(AnonymousArgInfo {
|
||||
arg: arg,
|
||||
arg_ty: new_arg_ty,
|
||||
bound_region: bound_region,
|
||||
is_first: is_first,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.next()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -114,37 +126,38 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
// This method returns whether the given Region is Anonymous
|
||||
// and returns the DefId and the BoundRegion corresponding to the given region.
|
||||
pub fn is_suitable_anonymous_region(&self, region: Region<'tcx>) -> Option<FreeRegionInfo> {
|
||||
if let ty::ReFree(ref free_region) = *region {
|
||||
if let ty::BrAnon(..) = free_region.bound_region {
|
||||
let anonymous_region_binding_scope = free_region.scope;
|
||||
let node_id = self.tcx
|
||||
.hir
|
||||
.as_local_node_id(anonymous_region_binding_scope)
|
||||
.unwrap();
|
||||
let mut is_impl_item = false;
|
||||
match self.tcx.hir.find(node_id) {
|
||||
// This method returns the DefId and the BoundRegion corresponding to the given region.
|
||||
pub fn is_suitable_region(&self, region: Region<'tcx>) -> Option<FreeRegionInfo> {
|
||||
|
||||
Some(hir_map::NodeItem(..)) |
|
||||
Some(hir_map::NodeTraitItem(..)) => {
|
||||
// Success -- proceed to return Some below
|
||||
}
|
||||
Some(hir_map::NodeImplItem(..)) => {
|
||||
is_impl_item =
|
||||
self.is_bound_region_in_impl_item(anonymous_region_binding_scope);
|
||||
}
|
||||
_ => return None,
|
||||
}
|
||||
return Some(FreeRegionInfo {
|
||||
def_id: anonymous_region_binding_scope,
|
||||
boundregion: free_region.bound_region,
|
||||
is_impl_item: is_impl_item,
|
||||
});
|
||||
let (suitable_region_binding_scope, bound_region) = match *region {
|
||||
ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
|
||||
ty::ReEarlyBound(ref ebr) => {
|
||||
(self.tcx.parent_def_id(ebr.def_id).unwrap(),
|
||||
ty::BoundRegion::BrNamed(ebr.def_id, ebr.name))
|
||||
}
|
||||
}
|
||||
None
|
||||
_ => return None, // not a free region
|
||||
};
|
||||
|
||||
let node_id = self.tcx
|
||||
.hir
|
||||
.as_local_node_id(suitable_region_binding_scope)
|
||||
.unwrap();
|
||||
let is_impl_item = match self.tcx.hir.find(node_id) {
|
||||
|
||||
Some(hir_map::NodeItem(..)) |
|
||||
Some(hir_map::NodeTraitItem(..)) => false,
|
||||
Some(hir_map::NodeImplItem(..)) => {
|
||||
self.is_bound_region_in_impl_item(suitable_region_binding_scope)
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
return Some(FreeRegionInfo {
|
||||
def_id: suitable_region_binding_scope,
|
||||
boundregion: bound_region,
|
||||
is_impl_item: is_impl_item,
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Here, we check for the case where the anonymous region
|
||||
@ -177,9 +190,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
// Here we check if the bound region is in Impl Item.
|
||||
pub fn is_bound_region_in_impl_item(&self, anonymous_region_binding_scope: DefId) -> bool {
|
||||
pub fn is_bound_region_in_impl_item(&self, suitable_region_binding_scope: DefId) -> bool {
|
||||
let container_id = self.tcx
|
||||
.associated_item(anonymous_region_binding_scope)
|
||||
.associated_item(suitable_region_binding_scope)
|
||||
.container
|
||||
.id();
|
||||
if self.tcx.impl_trait_ref(container_id).is_some() {
|
||||
@ -193,4 +206,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
// This method returns whether the given Region is Named
|
||||
pub fn is_named_region(&self, region: Region<'tcx>) -> bool {
|
||||
match *region {
|
||||
ty::ReFree(ref free_region) => {
|
||||
match free_region.bound_region {
|
||||
ty::BrNamed(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1041,19 +1041,6 @@ impl RegionKind {
|
||||
|
||||
flags
|
||||
}
|
||||
|
||||
// This method returns whether the given Region is Named
|
||||
pub fn is_named_region(&self) -> bool {
|
||||
match *self {
|
||||
ty::ReFree(ref free_region) => {
|
||||
match free_region.bound_region {
|
||||
ty::BrNamed(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Type utilities
|
||||
|
@ -31,7 +31,7 @@ fn method2<'a,'b,T>(x: &'a T, y: &'b T)
|
||||
// Note that &'static T <: &'a T.
|
||||
let a: <T as Trait<'a>>::Type = loop { };
|
||||
let b: <T as Trait<'b>>::Type = loop { };
|
||||
let _: <T as Trait<'b>>::Type = a; //~ ERROR mismatched types
|
||||
let _: <T as Trait<'b>>::Type = a; //~ ERROR E0623
|
||||
}
|
||||
|
||||
fn method3<'a,'b,T>(x: &'a T, y: &'b T)
|
||||
@ -40,7 +40,7 @@ fn method3<'a,'b,T>(x: &'a T, y: &'b T)
|
||||
// Note that &'static T <: &'a T.
|
||||
let a: <T as Trait<'a>>::Type = loop { };
|
||||
let b: <T as Trait<'b>>::Type = loop { };
|
||||
let _: <T as Trait<'a>>::Type = b; //~ ERROR mismatched types
|
||||
let _: <T as Trait<'a>>::Type = b; //~ ERROR E0623
|
||||
}
|
||||
|
||||
fn method4<'a,'b,T>(x: &'a T, y: &'b T)
|
||||
|
@ -15,7 +15,7 @@ fn a<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) where 'b: 'a {
|
||||
|
||||
fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
|
||||
// Illegal now because there is no `'b:'a` declaration.
|
||||
*x = *y; //~ ERROR E0312
|
||||
*x = *y; //~ ERROR E0623
|
||||
}
|
||||
|
||||
fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
|
||||
|
@ -16,8 +16,8 @@ fn a<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) where
|
||||
|
||||
fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
|
||||
// Illegal now because there is no `'b:'a` declaration.
|
||||
*x = *y; //~ ERROR E0312
|
||||
*z = *y; //~ ERROR E0312
|
||||
*x = *y; //~ ERROR E0623
|
||||
*z = *y; //~ ERROR E0623
|
||||
}
|
||||
|
||||
fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
|
||||
|
@ -15,20 +15,16 @@
|
||||
struct Paramd<'a> { x: &'a usize }
|
||||
|
||||
fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
|
||||
let z: Option<&'b &'a usize> = None;
|
||||
//~^ ERROR reference has a longer lifetime than the data it references
|
||||
let z: Option<&'b &'a usize> = None;//~ ERROR E0623
|
||||
}
|
||||
|
||||
fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
|
||||
let y: Paramd<'a> = Paramd { x: a };
|
||||
let z: Option<&'b Paramd<'a>> = None;
|
||||
//~^ ERROR reference has a longer lifetime than the data it references
|
||||
let z: Option<&'b Paramd<'a>> = None;//~ ERROR E0623
|
||||
}
|
||||
|
||||
fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
|
||||
let z: Option<&'a &'b usize> = None;
|
||||
//~^ ERROR reference has a longer lifetime than the data it references
|
||||
let z: Option<&'a &'b usize> = None;//~ ERROR E0623
|
||||
}
|
||||
|
||||
|
||||
fn main() {}
|
||||
|
@ -32,7 +32,7 @@ fn use_<'short,'long>(c: Contravariant<'short>,
|
||||
// 'short <= 'long, this would be true if the Contravariant type were
|
||||
// covariant with respect to its parameter 'a.
|
||||
|
||||
let _: Contravariant<'long> = c; //~ ERROR mismatched types
|
||||
let _: Contravariant<'long> = c; //~ ERROR E0623
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -29,7 +29,7 @@ fn use_<'short,'long>(c: Covariant<'long>,
|
||||
// 'short <= 'long, this would be true if the Covariant type were
|
||||
// contravariant with respect to its parameter 'a.
|
||||
|
||||
let _: Covariant<'short> = c; //~ ERROR mismatched types
|
||||
let _: Covariant<'short> = c; //~ ERROR E0623
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -15,7 +15,7 @@ fn a<'a, 'b:'a>(x: &mut &'a isize, y: &mut &'b isize) {
|
||||
|
||||
fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
|
||||
// Illegal now because there is no `'b:'a` declaration.
|
||||
*x = *y; //~ ERROR E0312
|
||||
*x = *y; //~ ERROR E0623
|
||||
}
|
||||
|
||||
fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
|
||||
|
@ -32,7 +32,7 @@ fn use_<'short,'long>(c: S<'long, 'short>,
|
||||
// 'short <= 'long, this would be true if the Contravariant type were
|
||||
// covariant with respect to its parameter 'a.
|
||||
|
||||
let _: S<'long, 'long> = c; //~ ERROR mismatched types
|
||||
let _: S<'long, 'long> = c; //~ ERROR E0623
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -30,7 +30,7 @@ fn use_<'short,'long>(c: Contravariant<'short>,
|
||||
// 'short <= 'long, this would be true if the Contravariant type were
|
||||
// covariant with respect to its parameter 'a.
|
||||
|
||||
let _: Contravariant<'long> = c; //~ ERROR mismatched types
|
||||
let _: Contravariant<'long> = c; //~ ERROR E0623
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -30,7 +30,7 @@ fn use_<'short,'long>(c: Covariant<'long>,
|
||||
// 'short <= 'long, this would be true if the Covariant type were
|
||||
// contravariant with respect to its parameter 'a.
|
||||
|
||||
let _: Covariant<'short> = c; //~ ERROR mismatched types
|
||||
let _: Covariant<'short> = c; //~ ERROR E0623
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -27,7 +27,7 @@ fn use_<'short,'long>(c: Invariant<'long>,
|
||||
// 'short <= 'long, this would be true if the Invariant type were
|
||||
// contravariant with respect to its parameter 'a.
|
||||
|
||||
let _: Invariant<'short> = c; //~ ERROR mismatched types
|
||||
let _: Invariant<'short> = c; //~ ERROR E0623
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
@ -21,7 +21,7 @@ fn use_<'short,'long>(c: Foo<'short>,
|
||||
s: &'short isize,
|
||||
l: &'long isize,
|
||||
_where:Option<&'short &'long ()>) {
|
||||
let _: Foo<'long> = c; //~ ERROR mismatched types
|
||||
let _: Foo<'long> = c; //~ ERROR E0623
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -0,0 +1,21 @@
|
||||
// Copyright 2017 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.
|
||||
trait Foo<'a> {}
|
||||
impl<'a, T> Foo<'a> for T {}
|
||||
|
||||
fn baz<'a, 'b, T>(x: &mut Vec<&'a T>, y: &T)
|
||||
where i32: Foo<'a>,
|
||||
u32: Foo<'b>
|
||||
{
|
||||
x.push(y);
|
||||
}
|
||||
fn main() {
|
||||
let x = baz;
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
error[E0623]: lifetime mismatch
|
||||
--> $DIR/ex3-both-anon-regions-earlybound-regions.rs:17:12
|
||||
|
|
||||
13 | fn baz<'a, 'b, T>(x: &mut Vec<&'a T>, y: &T)
|
||||
| ----- -- these two types are declared with different lifetimes...
|
||||
...
|
||||
17 | x.push(y);
|
||||
| ^ ...but data from `y` flows into `x` here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -0,0 +1,15 @@
|
||||
// Copyright 2017 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 foo<'a,'b>(x: &mut Vec<&'a u8>, y: &'b u8) {
|
||||
x.push(y);
|
||||
}
|
||||
|
||||
fn main() { }
|
@ -0,0 +1,10 @@
|
||||
error[E0623]: lifetime mismatch
|
||||
--> $DIR/ex3-both-anon-regions-latebound-regions.rs:12:12
|
||||
|
|
||||
11 | fn foo<'a,'b>(x: &mut Vec<&'a u8>, y: &'b u8) {
|
||||
| ------ ------ these two types are declared with different lifetimes...
|
||||
12 | x.push(y);
|
||||
| ^ ...but data from `y` flows into `x` here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
Reference in New Issue
Block a user