adding E0623 for LateBound regions

This commit is contained in:
gaurikholkar 2017-08-25 11:51:22 +05:30
parent dead08cb33
commit cfc7cf3961
22 changed files with 342 additions and 176 deletions

View File

@ -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##"

View File

@ -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");
}
}

View File

@ -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,

View File

@ -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;
}
}

View File

@ -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,
}
}
}

View File

@ -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

View File

@ -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)

View File

@ -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) {

View File

@ -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) {

View File

@ -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() {}

View File

@ -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() {}

View File

@ -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() {}

View File

@ -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) {

View File

@ -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() {}

View File

@ -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() {}

View File

@ -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() {}

View File

@ -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() { }

View File

@ -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() {

View File

@ -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;
}

View File

@ -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

View File

@ -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() { }

View File

@ -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