Skip to content

Commit 02c419c

Browse files
committed
introduce a NiceRegionError type and define methods on that
This is more convenient, and allows us to be more independent from infcx, particularly with respect to `in_progress_tables` field. No functional change.
1 parent 3db8e0d commit 02c419c

File tree

6 files changed

+137
-82
lines changed

6 files changed

+137
-82
lines changed

src/librustc/infer/error_reporting/mod.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,9 +291,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
291291
for error in errors {
292292
debug!("report_region_errors: error = {:?}", error);
293293

294-
if !self.try_report_named_anon_conflict(&error) &&
295-
!self.try_report_anon_anon_conflict(&error)
296-
{
294+
if !self.try_report_nice_region_error(&error) {
297295
match error.clone() {
298296
// These errors could indicate all manner of different
299297
// problems with many different solutions. Rather

src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,10 @@
1010

1111
//! Error Reporting for Anonymous Region Lifetime Errors
1212
//! where both the regions are anonymous.
13-
use infer::InferCtxt;
14-
use infer::lexical_region_resolve::RegionResolutionError::*;
15-
use infer::lexical_region_resolve::RegionResolutionError;
13+
use infer::error_reporting::nice_region_error::NiceRegionError;
1614
use infer::error_reporting::nice_region_error::util::AnonymousArgInfo;
1715

18-
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
16+
impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
1917
/// Print the error message for lifetime errors when both the concerned regions are anonymous.
2018
///
2119
/// Consider a case where we have
@@ -52,12 +50,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
5250
/// ````
5351
///
5452
/// It will later be extended to trait objects.
55-
pub fn try_report_anon_anon_conflict(&self, error: &RegionResolutionError<'tcx>) -> bool {
56-
let (span, sub, sup) = match *error {
57-
ConcreteFailure(ref origin, sub, sup) => (origin.span(), sub, sup),
58-
SubSupConflict(_, ref origin, sub, _, sup) => (origin.span(), sub, sup),
59-
_ => return false, // inapplicable
60-
};
53+
pub(super) fn try_report_anon_anon_conflict(&self) -> bool {
54+
let NiceRegionError { span, sub, sup, .. } = *self;
6155

6256
// Determine whether the sub and sup consist of both anonymous (elided) regions.
6357
let anon_reg_sup = or_false!(self.is_suitable_region(sup));

src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99
// except according to those terms.
1010

1111
use hir;
12-
use infer::InferCtxt;
13-
use ty::{self, Region};
12+
use ty::{self, Region, TyCtxt};
1413
use hir::map as hir_map;
1514
use middle::resolve_lifetime as rl;
1615
use hir::intravisit::{self, NestedVisitorMap, Visitor};
16+
use infer::error_reporting::nice_region_error::NiceRegionError;
1717

18-
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
18+
impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
1919
/// This function calls the `visit_ty` method for the parameters
2020
/// corresponding to the anonymous regions. The `nested_visitor.found_type`
2121
/// contains the anonymous type.
@@ -74,8 +74,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
7474
br: &ty::BoundRegion,
7575
) -> Option<(&'gcx hir::Ty)> {
7676
let mut nested_visitor = FindNestedTypeVisitor {
77-
infcx: &self,
78-
hir_map: &self.tcx.hir,
77+
tcx: self.tcx,
7978
bound_region: *br,
8079
found_type: None,
8180
depth: 1,
@@ -93,8 +92,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
9392
// where that lifetime appears. This allows us to highlight the
9493
// specific part of the type in the error message.
9594
struct FindNestedTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
96-
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
97-
hir_map: &'a hir::map::Map<'gcx>,
95+
tcx: TyCtxt<'a, 'gcx, 'tcx>,
9896
// The bound_region corresponding to the Refree(freeregion)
9997
// associated with the anonymous region we are looking for.
10098
bound_region: ty::BoundRegion,
@@ -106,7 +104,7 @@ struct FindNestedTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
106104

107105
impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
108106
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
109-
NestedVisitorMap::OnlyBodies(&self.hir_map)
107+
NestedVisitorMap::OnlyBodies(&self.tcx.hir)
110108
}
111109

112110
fn visit_ty(&mut self, arg: &'gcx hir::Ty) {
@@ -126,8 +124,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
126124

127125
hir::TyRptr(ref lifetime, _) => {
128126
// the lifetime of the TyRptr
129-
let hir_id = self.infcx.tcx.hir.node_to_hir_id(lifetime.id);
130-
match (self.infcx.tcx.named_region(hir_id), self.bound_region) {
127+
let hir_id = self.tcx.hir.node_to_hir_id(lifetime.id);
128+
match (self.tcx.named_region(hir_id), self.bound_region) {
131129
// Find the index of the anonymous region that was part of the
132130
// error. We will then search the function parameters for a bound
133131
// region at the right depth with the same index
@@ -195,10 +193,9 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
195193
// Checks if it is of type `hir::TyPath` which corresponds to a struct.
196194
hir::TyPath(_) => {
197195
let subvisitor = &mut TyPathVisitor {
198-
infcx: self.infcx,
196+
tcx: self.tcx,
199197
found_it: false,
200198
bound_region: self.bound_region,
201-
hir_map: self.hir_map,
202199
depth: self.depth,
203200
};
204201
intravisit::walk_ty(subvisitor, arg); // call walk_ty; as visit_ty is empty,
@@ -222,21 +219,20 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
222219
// where that lifetime appears. This allows us to highlight the
223220
// specific part of the type in the error message.
224221
struct TyPathVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
225-
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
226-
hir_map: &'a hir::map::Map<'gcx>,
222+
tcx: TyCtxt<'a, 'gcx, 'tcx>,
227223
found_it: bool,
228224
bound_region: ty::BoundRegion,
229225
depth: u32,
230226
}
231227

232228
impl<'a, 'gcx, 'tcx> Visitor<'gcx> for TyPathVisitor<'a, 'gcx, 'tcx> {
233229
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
234-
NestedVisitorMap::OnlyBodies(&self.hir_map)
230+
NestedVisitorMap::OnlyBodies(&self.tcx.hir)
235231
}
236232

237233
fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
238-
let hir_id = self.infcx.tcx.hir.node_to_hir_id(lifetime.id);
239-
match (self.infcx.tcx.named_region(hir_id), self.bound_region) {
234+
let hir_id = self.tcx.hir.node_to_hir_id(lifetime.id);
235+
match (self.tcx.named_region(hir_id), self.bound_region) {
240236
// the lifetime of the TyPath!
241237
(Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)), ty::BrAnon(br_index)) => {
242238
if debruijn_index.depth == self.depth && anon_index == br_index {

src/librustc/infer/error_reporting/nice_region_error/mod.rs

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,56 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#[macro_use] mod util;
11+
use infer::InferCtxt;
12+
use infer::lexical_region_resolve::RegionResolutionError;
13+
use infer::lexical_region_resolve::RegionResolutionError::*;
14+
use syntax::codemap::Span;
15+
use ty::{self, TyCtxt};
16+
17+
#[macro_use]
18+
mod util;
1219

1320
mod find_anon_type;
1421
mod different_lifetimes;
1522
mod named_anon_conflict;
23+
24+
impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
25+
pub fn try_report_nice_region_error(&self, error: &RegionResolutionError<'tcx>) -> bool {
26+
let (span, sub, sup) = match *error {
27+
ConcreteFailure(ref origin, sub, sup) => (origin.span(), sub, sup),
28+
SubSupConflict(_, ref origin, sub, _, sup) => (origin.span(), sub, sup),
29+
_ => return false, // inapplicable
30+
};
31+
32+
if let Some(tables) = self.in_progress_tables {
33+
let tables = tables.borrow();
34+
NiceRegionError::new(self.tcx, span, sub, sup, Some(&tables)).try_report()
35+
} else {
36+
NiceRegionError::new(self.tcx, span, sub, sup, None).try_report()
37+
}
38+
}
39+
}
40+
41+
pub struct NiceRegionError<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
42+
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
43+
span: Span,
44+
sub: ty::Region<'tcx>,
45+
sup: ty::Region<'tcx>,
46+
tables: Option<&'cx ty::TypeckTables<'tcx>>,
47+
}
48+
49+
impl<'cx, 'gcx, 'tcx> NiceRegionError<'cx, 'gcx, 'tcx> {
50+
pub fn new(
51+
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
52+
span: Span,
53+
sub: ty::Region<'tcx>,
54+
sup: ty::Region<'tcx>,
55+
tables: Option<&'cx ty::TypeckTables<'tcx>>,
56+
) -> Self {
57+
Self { tcx, span, sub, sup, tables }
58+
}
59+
60+
pub fn try_report(&self) -> bool {
61+
self.try_report_anon_anon_conflict() || self.try_report_named_anon_conflict()
62+
}
63+
}

src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs

Lines changed: 66 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -10,56 +10,68 @@
1010

1111
//! Error Reporting for Anonymous Region Lifetime Errors
1212
//! where one region is named and the other is anonymous.
13-
use infer::InferCtxt;
14-
use infer::lexical_region_resolve::RegionResolutionError::*;
15-
use infer::lexical_region_resolve::RegionResolutionError;
13+
use infer::error_reporting::nice_region_error::NiceRegionError;
1614
use ty;
1715

18-
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
16+
impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
1917
/// When given a `ConcreteFailure` for a function with arguments containing a named region and
2018
/// an anonymous region, emit an descriptive diagnostic error.
21-
pub fn try_report_named_anon_conflict(&self, error: &RegionResolutionError<'tcx>) -> bool {
22-
let (span, sub, sup) = match *error {
23-
ConcreteFailure(ref origin, sub, sup) => (origin.span(), sub, sup),
24-
SubSupConflict(_, ref origin, sub, _, sup) => (origin.span(), sub, sup),
25-
_ => return false, // inapplicable
26-
};
19+
pub(super) fn try_report_named_anon_conflict(&self) -> bool {
20+
let NiceRegionError { span, sub, sup, .. } = *self;
2721

28-
debug!("try_report_named_anon_conflict(sub={:?}, sup={:?})", sub, sup);
22+
debug!(
23+
"try_report_named_anon_conflict(sub={:?}, sup={:?})",
24+
sub,
25+
sup
26+
);
2927

3028
// Determine whether the sub and sup consist of one named region ('a)
3129
// and one anonymous (elided) region. If so, find the parameter arg
3230
// where the anonymous region appears (there must always be one; we
3331
// only introduced anonymous regions in parameters) as well as a
3432
// version new_ty of its type where the anonymous region is replaced
3533
// with the named one.//scope_def_id
36-
let (named, anon, anon_arg_info, region_info) =
37-
if self.is_named_region(sub) && self.is_suitable_region(sup).is_some() &&
38-
self.find_arg_with_region(sup, sub).is_some() {
39-
(sub,
40-
sup,
41-
self.find_arg_with_region(sup, sub).unwrap(),
42-
self.is_suitable_region(sup).unwrap())
43-
} else if self.is_named_region(sup) && self.is_suitable_region(sub).is_some() &&
44-
self.find_arg_with_region(sub, sup).is_some() {
45-
(sup,
46-
sub,
47-
self.find_arg_with_region(sub, sup).unwrap(),
48-
self.is_suitable_region(sub).unwrap())
49-
} else {
50-
return false; // inapplicable
51-
};
34+
let (named, anon, anon_arg_info, region_info) = if self.is_named_region(sub)
35+
&& self.is_suitable_region(sup).is_some()
36+
&& self.find_arg_with_region(sup, sub).is_some()
37+
{
38+
(
39+
sub,
40+
sup,
41+
self.find_arg_with_region(sup, sub).unwrap(),
42+
self.is_suitable_region(sup).unwrap(),
43+
)
44+
} else if self.is_named_region(sup) && self.is_suitable_region(sub).is_some()
45+
&& self.find_arg_with_region(sub, sup).is_some()
46+
{
47+
(
48+
sup,
49+
sub,
50+
self.find_arg_with_region(sub, sup).unwrap(),
51+
self.is_suitable_region(sub).unwrap(),
52+
)
53+
} else {
54+
return false; // inapplicable
55+
};
5256

5357
debug!("try_report_named_anon_conflict: named = {:?}", named);
54-
debug!("try_report_named_anon_conflict: anon_arg_info = {:?}", anon_arg_info);
55-
debug!("try_report_named_anon_conflict: region_info = {:?}", region_info);
58+
debug!(
59+
"try_report_named_anon_conflict: anon_arg_info = {:?}",
60+
anon_arg_info
61+
);
62+
debug!(
63+
"try_report_named_anon_conflict: region_info = {:?}",
64+
region_info
65+
);
5666

57-
let (arg, new_ty, br, is_first, scope_def_id, is_impl_item) = (anon_arg_info.arg,
58-
anon_arg_info.arg_ty,
59-
anon_arg_info.bound_region,
60-
anon_arg_info.is_first,
61-
region_info.def_id,
62-
region_info.is_impl_item);
67+
let (arg, new_ty, br, is_first, scope_def_id, is_impl_item) = (
68+
anon_arg_info.arg,
69+
anon_arg_info.arg_ty,
70+
anon_arg_info.bound_region,
71+
anon_arg_info.is_first,
72+
region_info.def_id,
73+
region_info.is_impl_item,
74+
);
6375
match br {
6476
ty::BrAnon(_) => {}
6577
_ => {
@@ -75,27 +87,34 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
7587
}
7688

7789
if let Some((_, fndecl)) = self.find_anon_type(anon, &br) {
78-
if self.is_return_type_anon(scope_def_id, br, fndecl).is_some() ||
79-
self.is_self_anon(is_first, scope_def_id) {
90+
if self.is_return_type_anon(scope_def_id, br, fndecl).is_some()
91+
|| self.is_self_anon(is_first, scope_def_id)
92+
{
8093
return false;
8194
}
8295
}
8396

8497
let (error_var, span_label_var) = if let Some(simple_name) = arg.pat.simple_name() {
85-
(format!("the type of `{}`", simple_name), format!("the type of `{}`", simple_name))
98+
(
99+
format!("the type of `{}`", simple_name),
100+
format!("the type of `{}`", simple_name),
101+
)
86102
} else {
87103
("parameter type".to_owned(), "type".to_owned())
88104
};
89105

90-
struct_span_err!(self.tcx.sess,
91-
span,
92-
E0621,
93-
"explicit lifetime required in {}",
94-
error_var)
95-
.span_label(arg.pat.span,
96-
format!("consider changing {} to `{}`", span_label_var, new_ty))
97-
.span_label(span, format!("lifetime `{}` required", named))
98-
.emit();
106+
struct_span_err!(
107+
self.tcx.sess,
108+
span,
109+
E0621,
110+
"explicit lifetime required in {}",
111+
error_var
112+
).span_label(
113+
arg.pat.span,
114+
format!("consider changing {} to `{}`", span_label_var, new_ty),
115+
)
116+
.span_label(span, format!("lifetime `{}` required", named))
117+
.emit();
99118
return true;
100119
}
101120
}

src/librustc/infer/error_reporting/nice_region_error/util.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
//! Helper functions corresponding to lifetime errors due to
1212
//! anonymous regions.
1313
use hir;
14-
use infer::InferCtxt;
14+
use infer::error_reporting::nice_region_error::NiceRegionError;
1515
use ty::{self, Region, Ty};
1616
use hir::def_id::DefId;
1717
use hir::map as hir_map;
@@ -56,7 +56,7 @@ pub(super) struct FreeRegionInfo {
5656
pub is_impl_item: bool,
5757
}
5858

59-
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
59+
impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
6060
// This method walks the Type of the function body arguments using
6161
// `fold_regions()` function and returns the
6262
// &hir::Arg of the function argument corresponding to the anonymous
@@ -86,13 +86,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
8686
if let Some(node_id) = hir.as_local_node_id(id) {
8787
if let Some(body_id) = hir.maybe_body_owned_by(node_id) {
8888
let body = hir.body(body_id);
89-
if let Some(tables) = self.in_progress_tables {
89+
if let Some(tables) = self.tables {
9090
body.arguments
9191
.iter()
9292
.enumerate()
9393
.filter_map(|(index, arg)| {
9494
// May return None; sometimes the tables are not yet populated.
95-
let ty = tables.borrow().node_id_to_type_opt(arg.hir_id)?;
95+
let ty = tables.node_id_to_type_opt(arg.hir_id)?;
9696
let mut found_anon_region = false;
9797
let new_arg_ty = self.tcx.fold_regions(&ty, &mut false, |r, _| {
9898
if *r == *anon_region {

0 commit comments

Comments
 (0)