Skip to content

Commit 2d99ffd

Browse files
committed
track anonymous regions in return types, fix tidy errors
1 parent 8fb6f74 commit 2d99ffd

File tree

5 files changed

+91
-17
lines changed

5 files changed

+91
-17
lines changed

src/librustc/infer/error_reporting/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
272272
for error in errors {
273273

274274
debug!("report_region_errors: error = {:?}", error);
275-
275+
276276
if !self.try_report_named_anon_conflict(&error){
277277

278278
match error.clone() {

src/librustc/infer/error_reporting/named_anon_conflict.rs

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use ty::{self, Region};
1515
use infer::region_inference::RegionResolutionError::*;
1616
use infer::region_inference::RegionResolutionError;
1717
use hir::map as hir_map;
18+
use hir::def_id::DefId;
1819

1920
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
2021
// This method walks the Type of the function body arguments using
@@ -24,13 +25,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
2425
// Currently only the case where the function declaration consists of
2526
// one named region and one anonymous region is handled.
2627
// Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32`
27-
// Here, we would return the hir::Arg for y, and we return the type &'a
28+
// Here, we would return the hir::Arg for y, we return the type &'a
2829
// i32, which is the type of y but with the anonymous region replaced
29-
// with 'a.
30+
// with 'a and also the corresponding bound region.
3031
fn find_arg_with_anonymous_region(&self,
3132
anon_region: Region<'tcx>,
3233
named_region: Region<'tcx>)
33-
-> Option<(&hir::Arg, ty::Ty<'tcx>)> {
34+
-> Option<(&hir::Arg, ty::Ty<'tcx>, ty::BoundRegion)> {
3435

3536
match *anon_region {
3637
ty::ReFree(ref free_region) => {
@@ -55,7 +56,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
5556
r
5657
});
5758
if found_anon_region {
58-
return Some((arg, new_arg_ty));
59+
return Some((arg, new_arg_ty, free_region.bound_region));
5960
} else {
6061
None
6162
}
@@ -85,15 +86,36 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
8586
// only introduced anonymous regions in parameters) as well as a
8687
// version new_ty of its type where the anonymous region is replaced
8788
// with the named one.
88-
let (named, (arg, new_ty)) =
89-
if self.is_named_region(sub) && self.is_suitable_anonymous_region(sup) {
90-
(sub, self.find_arg_with_anonymous_region(sup, sub).unwrap())
91-
} else if self.is_named_region(sup) && self.is_suitable_anonymous_region(sub) {
92-
(sup, self.find_arg_with_anonymous_region(sub, sup).unwrap())
89+
let (named, (arg, new_ty, br), scope_def_id) =
90+
if self.is_named_region(sub) && self.is_suitable_anonymous_region(sup).is_some() {
91+
(sub,
92+
self.find_arg_with_anonymous_region(sup, sub).unwrap(),
93+
self.is_suitable_anonymous_region(sup).unwrap())
94+
} else if self.is_named_region(sup) &&
95+
self.is_suitable_anonymous_region(sub).is_some() {
96+
(sup,
97+
self.find_arg_with_anonymous_region(sub, sup).unwrap(),
98+
self.is_suitable_anonymous_region(sub).unwrap())
9399
} else {
94100
return false; // inapplicable
95101
};
96102

103+
// Here, we check for the case where the anonymous region
104+
// is in the return type.
105+
// FIXME(#42703) - Need to handle certain cases here.
106+
let ret_ty = self.tcx.type_of(scope_def_id);
107+
match ret_ty.sty {
108+
ty::TyFnDef(_, _, sig) => {
109+
let late_bound_regions = self.tcx
110+
.collect_referenced_late_bound_regions(&sig.output());
111+
if late_bound_regions.iter().any(|r| *r == br) {
112+
return false;
113+
} else {
114+
}
115+
}
116+
_ => {}
117+
}
118+
97119
if let Some(simple_name) = arg.pat.simple_name() {
98120
struct_span_err!(self.tcx.sess,
99121
span,
@@ -122,7 +144,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
122144
}
123145

124146
// This method returns whether the given Region is Anonymous
125-
pub fn is_suitable_anonymous_region(&self, region: Region<'tcx>) -> bool {
147+
// and returns the DefId corresponding to the region.
148+
pub fn is_suitable_anonymous_region(&self, region: Region<'tcx>) -> Option<DefId> {
126149

127150
match *region {
128151
ty::ReFree(ref free_region) => {
@@ -147,20 +170,20 @@ associated_item(anonymous_region_binding_scope).container.id()).is_some() {
147170
// since the signature must match the trait.
148171
//
149172
// FIXME(#42706) -- in some cases, we could do better here.
150-
return false;//None;
173+
return None;
151174
}
152175
else{ }
153176

154177
}
155-
_ => return false, // inapplicable
178+
_ => return None, // inapplicable
156179
// we target only top-level functions
157180
}
158-
return true;
181+
return Some(anonymous_region_binding_scope);
159182
}
160-
_ => false,
183+
_ => None,
161184
}
162185
}
163-
_ => false,
186+
_ => None,
164187
}
165188
}
166189
}

src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ struct Foo {
1414

1515
impl Foo {
1616
fn foo<'a>(&'a self, x: &i32) -> &i32 {
17-
17+
1818
if true { &self.field } else { x }
1919

2020
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct Foo {
12+
field: i32
13+
}
14+
15+
impl Foo {
16+
fn foo<'a>(&self, x: &'a i32) -> &i32 {
17+
18+
x
19+
20+
}
21+
22+
}
23+
24+
fn main() { }
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0312]: lifetime of reference outlives lifetime of borrowed content...
2+
--> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:18:5
3+
|
4+
18 | x
5+
| ^
6+
|
7+
note: ...the reference is valid for the anonymous lifetime #1 defined on the method body at 16:3...
8+
--> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:16:3
9+
|
10+
16 | / fn foo<'a>(&self, x: &'a i32) -> &i32 {
11+
17 | |
12+
18 | | x
13+
19 | |
14+
20 | | }
15+
| |___^
16+
note: ...but the borrowed content is only valid for the lifetime 'a as defined on the method body at 16:3
17+
--> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:16:3
18+
|
19+
16 | / fn foo<'a>(&self, x: &'a i32) -> &i32 {
20+
17 | |
21+
18 | | x
22+
19 | |
23+
20 | | }
24+
| |___^
25+
26+
error: aborting due to previous error(s)
27+

0 commit comments

Comments
 (0)