track anonymous regions in return types, fix tidy errors

This commit is contained in:
gaurikholkar 2017-06-20 06:42:11 -07:00
parent 8fb6f74e57
commit 2d99ffd11b
5 changed files with 91 additions and 17 deletions

View File

@ -272,7 +272,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
for error in errors {
debug!("report_region_errors: error = {:?}", error);
if !self.try_report_named_anon_conflict(&error){
match error.clone() {

View File

@ -15,6 +15,7 @@ use ty::{self, Region};
use infer::region_inference::RegionResolutionError::*;
use infer::region_inference::RegionResolutionError;
use hir::map as hir_map;
use hir::def_id::DefId;
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
// This method walks the Type of the function body arguments using
@ -24,13 +25,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
// Currently only the case where the function declaration consists of
// one named region and one anonymous region is handled.
// Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32`
// Here, we would return the hir::Arg for y, and we return the type &'a
// Here, we would return the hir::Arg for y, we return the type &'a
// i32, which is the type of y but with the anonymous region replaced
// with 'a.
// with 'a and also the corresponding bound region.
fn find_arg_with_anonymous_region(&self,
anon_region: Region<'tcx>,
named_region: Region<'tcx>)
-> Option<(&hir::Arg, ty::Ty<'tcx>)> {
-> Option<(&hir::Arg, ty::Ty<'tcx>, ty::BoundRegion)> {
match *anon_region {
ty::ReFree(ref free_region) => {
@ -55,7 +56,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
r
});
if found_anon_region {
return Some((arg, new_arg_ty));
return Some((arg, new_arg_ty, free_region.bound_region));
} else {
None
}
@ -85,15 +86,36 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
// only introduced anonymous regions in parameters) as well as a
// version new_ty of its type where the anonymous region is replaced
// with the named one.
let (named, (arg, new_ty)) =
if self.is_named_region(sub) && self.is_suitable_anonymous_region(sup) {
(sub, self.find_arg_with_anonymous_region(sup, sub).unwrap())
} else if self.is_named_region(sup) && self.is_suitable_anonymous_region(sub) {
(sup, self.find_arg_with_anonymous_region(sub, sup).unwrap())
let (named, (arg, new_ty, br), scope_def_id) =
if self.is_named_region(sub) && self.is_suitable_anonymous_region(sup).is_some() {
(sub,
self.find_arg_with_anonymous_region(sup, sub).unwrap(),
self.is_suitable_anonymous_region(sup).unwrap())
} else if self.is_named_region(sup) &&
self.is_suitable_anonymous_region(sub).is_some() {
(sup,
self.find_arg_with_anonymous_region(sub, sup).unwrap(),
self.is_suitable_anonymous_region(sub).unwrap())
} else {
return false; // inapplicable
};
// Here, we check for the case where the anonymous region
// is in the return type.
// FIXME(#42703) - Need to handle certain cases here.
let ret_ty = self.tcx.type_of(scope_def_id);
match ret_ty.sty {
ty::TyFnDef(_, _, sig) => {
let late_bound_regions = self.tcx
.collect_referenced_late_bound_regions(&sig.output());
if late_bound_regions.iter().any(|r| *r == br) {
return false;
} else {
}
}
_ => {}
}
if let Some(simple_name) = arg.pat.simple_name() {
struct_span_err!(self.tcx.sess,
span,
@ -122,7 +144,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
// This method returns whether the given Region is Anonymous
pub fn is_suitable_anonymous_region(&self, region: Region<'tcx>) -> bool {
// and returns the DefId corresponding to the region.
pub fn is_suitable_anonymous_region(&self, region: Region<'tcx>) -> Option<DefId> {
match *region {
ty::ReFree(ref free_region) => {
@ -147,20 +170,20 @@ associated_item(anonymous_region_binding_scope).container.id()).is_some() {
// since the signature must match the trait.
//
// FIXME(#42706) -- in some cases, we could do better here.
return false;//None;
return None;
}
else{ }
}
_ => return false, // inapplicable
_ => return None, // inapplicable
// we target only top-level functions
}
return true;
return Some(anonymous_region_binding_scope);
}
_ => false,
_ => None,
}
}
_ => false,
_ => None,
}
}
}

View File

@ -14,7 +14,7 @@ struct Foo {
impl Foo {
fn foo<'a>(&'a self, x: &i32) -> &i32 {
if true { &self.field } else { x }
}

View File

@ -0,0 +1,24 @@
// Copyright 2016 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.
struct Foo {
field: i32
}
impl Foo {
fn foo<'a>(&self, x: &'a i32) -> &i32 {
x
}
}
fn main() { }

View File

@ -0,0 +1,27 @@
error[E0312]: lifetime of reference outlives lifetime of borrowed content...
--> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:18:5
|
18 | x
| ^
|
note: ...the reference is valid for the anonymous lifetime #1 defined on the method body at 16:3...
--> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:16:3
|
16 | / fn foo<'a>(&self, x: &'a i32) -> &i32 {
17 | |
18 | | x
19 | |
20 | | }
| |___^
note: ...but the borrowed content is only valid for the lifetime 'a as defined on the method body at 16:3
--> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:16:3
|
16 | / fn foo<'a>(&self, x: &'a i32) -> &i32 {
17 | |
18 | | x
19 | |
20 | | }
| |___^
error: aborting due to previous error(s)