Skip to content

Commit a851e1e

Browse files
committed
Adding changes to track anonymous region in self
1 parent 2d99ffd commit a851e1e

5 files changed

+93
-23
lines changed

src/librustc/infer/error_reporting/named_anon_conflict.rs

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
2727
// Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32`
2828
// Here, we would return the hir::Arg for y, we return the type &'a
2929
// i32, which is the type of y but with the anonymous region replaced
30-
// with 'a and also the corresponding bound region.
31-
fn find_arg_with_anonymous_region(&self,
32-
anon_region: Region<'tcx>,
33-
named_region: Region<'tcx>)
34-
-> Option<(&hir::Arg, ty::Ty<'tcx>, ty::BoundRegion)> {
30+
// with 'a, the corresponding bound region and is_first which is true if
31+
// the hir::Arg is the first argument in the function declaration.
32+
fn find_arg_with_anonymous_region
33+
(&self,
34+
anon_region: Region<'tcx>,
35+
named_region: Region<'tcx>)
36+
-> Option<(&hir::Arg, ty::Ty<'tcx>, ty::BoundRegion, bool)> {
3537

3638
match *anon_region {
3739
ty::ReFree(ref free_region) => {
3840

3941
let id = free_region.scope;
4042
let node_id = self.tcx.hir.as_local_node_id(id).unwrap();
4143
let body_id = self.tcx.hir.maybe_body_owned_by(node_id).unwrap();
42-
44+
let mut is_first = false;
4345
let body = self.tcx.hir.body(body_id);
4446
body.arguments
4547
.iter()
@@ -56,7 +58,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
5658
r
5759
});
5860
if found_anon_region {
59-
return Some((arg, new_arg_ty, free_region.bound_region));
61+
if body.arguments.iter().nth(0) == Some(&arg) {
62+
is_first = true;
63+
}
64+
return Some((arg,
65+
new_arg_ty,
66+
free_region.bound_region,
67+
is_first));
6068
} else {
6169
None
6270
}
@@ -86,19 +94,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
8694
// only introduced anonymous regions in parameters) as well as a
8795
// version new_ty of its type where the anonymous region is replaced
8896
// with the named one.
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())
99-
} else {
100-
return false; // inapplicable
101-
};
97+
let (named, (arg, new_ty, br, is_first), scope_def_id) = if
98+
self.is_named_region(sub) && self.is_suitable_anonymous_region(sup).is_some() {
99+
(sub,
100+
self.find_arg_with_anonymous_region(sup, sub).unwrap(),
101+
self.is_suitable_anonymous_region(sup).unwrap())
102+
} else if
103+
self.is_named_region(sup) && self.is_suitable_anonymous_region(sub).is_some() {
104+
(sup,
105+
self.find_arg_with_anonymous_region(sub, sup).unwrap(),
106+
self.is_suitable_anonymous_region(sub).unwrap())
107+
} else {
108+
return false; // inapplicable
109+
};
102110

103111
// Here, we check for the case where the anonymous region
104112
// is in the return type.
@@ -116,6 +124,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
116124
_ => {}
117125
}
118126

127+
// Here we check for the case where anonymous region
128+
// corresponds to self and if yes, we display E0312.
129+
// FIXME(#42700) - Need to format self properly to
130+
// enable E0611 for it.
131+
if is_first &&
132+
self.tcx
133+
.opt_associated_item(scope_def_id)
134+
.map(|i| i.method_has_self_argument)
135+
.unwrap_or(false) {
136+
return false;
137+
}
138+
119139
if let Some(simple_name) = arg.pat.simple_name() {
120140
struct_span_err!(self.tcx.sess,
121141
span,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ error[E0611]: explicit lifetime required in the type of `x`
33
|
44
16 | fn foo<'a>(&'a self, x: &i32) -> &i32 {
55
| - consider changing the type of `x` to `&'a i32`
6-
17 |
6+
17 |
77
18 | if true { &self.field } else { x }
88
| ^ lifetime `'a` required
99

src/test/ui/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ note: ...the reference is valid for the anonymous lifetime #1 defined on the met
88
--> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:16:3
99
|
1010
16 | / fn foo<'a>(&self, x: &'a i32) -> &i32 {
11-
17 | |
11+
17 | |
1212
18 | | x
1313
19 | |
1414
20 | | }
@@ -17,7 +17,7 @@ note: ...but the borrowed content is only valid for the lifetime 'a as defined o
1717
--> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:16:3
1818
|
1919
16 | / fn foo<'a>(&self, x: &'a i32) -> &i32 {
20-
17 | |
20+
17 | |
2121
18 | | x
2222
19 | |
2323
20 | | }
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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 Foo) -> &'a Foo {
17+
18+
if true { x } else { self }
19+
20+
}
21+
}
22+
23+
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-self-is-anon.rs:18:30
3+
|
4+
18 | if true { x } else { self }
5+
| ^^^^
6+
|
7+
note: ...the reference is valid for the lifetime 'a as defined on the method body at 16:5...
8+
--> $DIR/ex1-return-one-existing-name-self-is-anon.rs:16:5
9+
|
10+
16 | / fn foo<'a>(&self, x: &'a Foo) -> &'a Foo {
11+
17 | |
12+
18 | | if true { x } else { self }
13+
19 | |
14+
20 | | }
15+
| |_____^
16+
note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the method body at 16:5
17+
--> $DIR/ex1-return-one-existing-name-self-is-anon.rs:16:5
18+
|
19+
16 | / fn foo<'a>(&self, x: &'a Foo) -> &'a Foo {
20+
17 | |
21+
18 | | if true { x } else { self }
22+
19 | |
23+
20 | | }
24+
| |_____^
25+
26+
error: aborting due to previous error(s)
27+

0 commit comments

Comments
 (0)