Skip to content

Commit 8fb6f74

Browse files
committed
Enabling E0611 for inherent functions
1 parent ae92bd0 commit 8fb6f74

7 files changed

+137
-42
lines changed

src/librustc/infer/error_reporting/mod.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ use hir::def_id::DefId;
6767
use middle::region;
6868
use traits::{ObligationCause, ObligationCauseCode};
6969
use ty::{self, TyCtxt, TypeFoldable};
70-
use ty::{Region, Issue32330 };
70+
use ty::{Region, Issue32330};
7171
use ty::error::TypeError;
7272
use syntax::ast::DUMMY_NODE_ID;
7373
use syntax_pos::{Pos, Span};
@@ -272,11 +272,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
272272
for error in errors {
273273

274274
debug!("report_region_errors: error = {:?}", error);
275-
// If ConcreteFailure does not have an anonymous region
276-
if !self.report_named_anon_conflict(&error){
275+
276+
if !self.try_report_named_anon_conflict(&error){
277277

278278
match error.clone() {
279-
279+
// These errors could indicate all manner of different
280+
// problems with many different solutions. Rather
281+
// than generate a "one size fits all" error, what we
282+
// attempt to do is go through a number of specific
283+
// scenarios and try to find the best way to present
284+
// the error. If all of these fails, we fall back to a rather
285+
// general bit of code that displays the error information
280286
ConcreteFailure(origin, sub, sup) => {
281287

282288
self.report_concrete_failure(origin, sub, sup).emit();

src/librustc/infer/error_reporting/named_anon_conflict.rs

Lines changed: 64 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use infer::InferCtxt;
1414
use ty::{self, Region};
1515
use infer::region_inference::RegionResolutionError::*;
1616
use infer::region_inference::RegionResolutionError;
17+
use hir::map as hir_map;
1718

1819
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
1920
// This method walks the Type of the function body arguments using
@@ -23,12 +24,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
2324
// Currently only the case where the function declaration consists of
2425
// one named region and one anonymous region is handled.
2526
// Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32`
26-
// Here, the `y` and the `Ty` of `y` is returned after being substituted
27-
// by that of the named region.
28-
pub fn find_arg_with_anonymous_region(&self,
29-
anon_region: Region<'tcx>,
30-
named_region: Region<'tcx>)
31-
-> Option<(&hir::Arg, ty::Ty<'tcx>)> {
27+
// Here, we would return the hir::Arg for y, and we return the type &'a
28+
// i32, which is the type of y but with the anonymous region replaced
29+
// with 'a.
30+
fn find_arg_with_anonymous_region(&self,
31+
anon_region: Region<'tcx>,
32+
named_region: Region<'tcx>)
33+
-> Option<(&hir::Arg, ty::Ty<'tcx>)> {
3234

3335
match *anon_region {
3436
ty::ReFree(ref free_region) => {
@@ -70,29 +72,35 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
7072
// This method generates the error message for the case when
7173
// the function arguments consist of a named region and an anonymous
7274
// region and corresponds to `ConcreteFailure(..)`
73-
pub fn report_named_anon_conflict(&self, error: &RegionResolutionError<'tcx>) -> bool {
75+
pub fn try_report_named_anon_conflict(&self, error: &RegionResolutionError<'tcx>) -> bool {
7476

7577
let (span, sub, sup) = match *error {
7678
ConcreteFailure(ref origin, sub, sup) => (origin.span(), sub, sup),
7779
_ => return false, // inapplicable
7880
};
7981

80-
let (named, (var, new_ty)) =
81-
if self.is_named_region(sub) && self.is_anonymous_region(sup) {
82+
// Determine whether the sub and sup consist of one named region ('a)
83+
// and one anonymous (elided) region. If so, find the parameter arg
84+
// where the anonymous region appears (there must always be one; we
85+
// only introduced anonymous regions in parameters) as well as a
86+
// version new_ty of its type where the anonymous region is replaced
87+
// with the named one.
88+
let (named, (arg, new_ty)) =
89+
if self.is_named_region(sub) && self.is_suitable_anonymous_region(sup) {
8290
(sub, self.find_arg_with_anonymous_region(sup, sub).unwrap())
83-
} else if self.is_named_region(sup) && self.is_anonymous_region(sub) {
91+
} else if self.is_named_region(sup) && self.is_suitable_anonymous_region(sub) {
8492
(sup, self.find_arg_with_anonymous_region(sub, sup).unwrap())
8593
} else {
8694
return false; // inapplicable
8795
};
8896

89-
if let Some(simple_name) = var.pat.simple_name() {
97+
if let Some(simple_name) = arg.pat.simple_name() {
9098
struct_span_err!(self.tcx.sess,
9199
span,
92100
E0611,
93101
"explicit lifetime required in the type of `{}`",
94102
simple_name)
95-
.span_label(var.pat.span,
103+
.span_label(arg.pat.span,
96104
format!("consider changing the type of `{}` to `{}`",
97105
simple_name,
98106
new_ty))
@@ -104,12 +112,55 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
104112
span,
105113
E0611,
106114
"explicit lifetime required in parameter type")
107-
.span_label(var.pat.span,
115+
.span_label(arg.pat.span,
108116
format!("consider changing type to `{}`", new_ty))
109117
.span_label(span, format!("lifetime `{}` required", named))
110118
.emit();
111119
}
112120
return true;
113121

114122
}
123+
124+
// This method returns whether the given Region is Anonymous
125+
pub fn is_suitable_anonymous_region(&self, region: Region<'tcx>) -> bool {
126+
127+
match *region {
128+
ty::ReFree(ref free_region) => {
129+
match free_region.bound_region {
130+
ty::BrAnon(..) => {
131+
let anonymous_region_binding_scope = free_region.scope;
132+
let node_id = self.tcx
133+
.hir
134+
.as_local_node_id(anonymous_region_binding_scope)
135+
.unwrap();
136+
match self.tcx.hir.find(node_id) {
137+
Some(hir_map::NodeItem(..)) |
138+
Some(hir_map::NodeTraitItem(..)) => {
139+
// proceed ahead //
140+
}
141+
Some(hir_map::NodeImplItem(..)) => {
142+
if self.tcx.impl_trait_ref(self.tcx.
143+
associated_item(anonymous_region_binding_scope).container.id()).is_some() {
144+
// For now, we do not try to target impls of traits. This is
145+
// because this message is going to suggest that the user
146+
// change the fn signature, but they may not be free to do so,
147+
// since the signature must match the trait.
148+
//
149+
// FIXME(#42706) -- in some cases, we could do better here.
150+
return false;//None;
151+
}
152+
else{ }
153+
154+
}
155+
_ => return false, // inapplicable
156+
// we target only top-level functions
157+
}
158+
return true;
159+
}
160+
_ => false,
161+
}
162+
}
163+
_ => false,
164+
}
165+
}
115166
}

src/librustc/infer/error_reporting/util.rs

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
1313
use ty::{self, Region};
1414
use infer::InferCtxt;
15-
use hir::map as hir_map;
1615

1716
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
1817
// This method returns whether the given Region is Named
@@ -28,28 +27,4 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
2827
_ => false,
2928
}
3029
}
31-
32-
// This method returns whether the given Region is Anonymous
33-
pub fn is_anonymous_region(&self, region: Region<'tcx>) -> bool {
34-
35-
match *region {
36-
ty::ReFree(ref free_region) => {
37-
match free_region.bound_region {
38-
ty::BrAnon(..) => {
39-
let id = free_region.scope;
40-
let node_id = self.tcx.hir.as_local_node_id(id).unwrap();
41-
match self.tcx.hir.find(node_id) {
42-
Some(hir_map::NodeItem(..)) |
43-
Some(hir_map::NodeTraitItem(..)) => { /* proceed ahead */ }
44-
_ => return false, // inapplicable
45-
// we target only top-level functions
46-
}
47-
return true;
48-
}
49-
_ => false,
50-
}
51-
}
52-
_ => false,
53-
}
54-
}
5530
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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+
trait Foo {
12+
13+
fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 {
14+
if x > y { x } else { y }
15+
}
16+
}
17+
18+
fn main() { }
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error[E0611]: explicit lifetime required in the type of `x`
2+
--> $DIR/ex1-return-one-existing-name-if-else-using-impl-2.rs:14:15
3+
|
4+
13 | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 {
5+
| - consider changing the type of `x` to `&'a i32`
6+
14 | if x > y { x } else { y }
7+
| ^ lifetime `'a` required
8+
9+
error: aborting due to previous error(s)
10+
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>(&'a self, x: &i32) -> &i32 {
17+
18+
if true { &self.field } else { x }
19+
20+
}
21+
22+
}
23+
24+
fn main() { }
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0611]: explicit lifetime required in the type of `x`
2+
--> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:18:36
3+
|
4+
16 | fn foo<'a>(&'a self, x: &i32) -> &i32 {
5+
| - consider changing the type of `x` to `&'a i32`
6+
17 |
7+
18 | if true { &self.field } else { x }
8+
| ^ lifetime `'a` required
9+
10+
error: aborting due to previous error(s)
11+

0 commit comments

Comments
 (0)