Skip to content

Commit e01e883

Browse files
committed
Introduce new categories and show a reasonable error message.
1 parent 27ce0cc commit e01e883

File tree

1 file changed

+58
-42
lines changed

1 file changed

+58
-42
lines changed

src/librustc_mir/borrow_check/nll/region_infer/error_reporting.rs

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

11+
use std::fmt;
1112
use borrow_check::nll::region_infer::{Cause, ConstraintIndex, RegionInferenceContext};
1213
use borrow_check::nll::region_infer::values::ToElementIndex;
1314
use borrow_check::nll::type_check::Locations;
1415
use rustc::hir::def_id::DefId;
1516
use rustc::infer::InferCtxt;
1617
use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
17-
use rustc::mir::{Location, Mir, StatementKind, TerminatorKind, Rvalue};
18+
use rustc::mir::{self, Location, Mir, Place, StatementKind, TerminatorKind, Rvalue};
1819
use rustc::ty::RegionVid;
1920
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
2021
use rustc_data_structures::indexed_vec::IndexVec;
2122
use syntax_pos::Span;
2223

2324
/// Constraints that are considered interesting can be categorized to
24-
/// determine why they are interesting.
25+
/// determine why they are interesting. Order of variants indicates
26+
/// sort order of the category, thereby influencing diagnostic output.
2527
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord)]
2628
enum ConstraintCategory {
27-
Assignment,
2829
Cast,
30+
Assignment,
31+
Return,
2932
CallArgument,
3033
Other,
34+
Boring,
35+
}
36+
37+
impl fmt::Display for ConstraintCategory {
38+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39+
match self {
40+
ConstraintCategory::Assignment => write!(f, "Assignment"),
41+
ConstraintCategory::Return => write!(f, "Return"),
42+
ConstraintCategory::Cast => write!(f, "Cast"),
43+
ConstraintCategory::CallArgument => write!(f, "Argument"),
44+
_ => write!(f, "Free region"),
45+
}
46+
}
3147
}
3248

3349
impl<'tcx> RegionInferenceContext<'tcx> {
@@ -132,9 +148,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
132148
}
133149

134150
/// This function classifies a constraint from a location.
135-
fn classify_constraint(&self, location: Location, mir: &Mir<'tcx>) -> ConstraintCategory {
151+
fn classify_constraint(&self, index: &ConstraintIndex,
152+
mir: &Mir<'tcx>) -> Option<(ConstraintCategory, Span)> {
153+
let constraint = self.constraints.get(*index)?;
154+
let span = constraint.locations.span(mir);
155+
let location = constraint.locations.from_location()?;
156+
157+
if !self.constraint_is_interesting(index) {
158+
return Some((ConstraintCategory::Boring, span));
159+
}
160+
136161
let data = &mir[location.block];
137-
if location.statement_index == data.statements.len() {
162+
let category = if location.statement_index == data.statements.len() {
138163
if let Some(ref terminator) = data.terminator {
139164
match terminator.kind {
140165
TerminatorKind::DropAndReplace { .. } => ConstraintCategory::Assignment,
@@ -147,14 +172,22 @@ impl<'tcx> RegionInferenceContext<'tcx> {
147172
} else {
148173
let statement = &data.statements[location.statement_index];
149174
match statement.kind {
150-
StatementKind::Assign(_, ref rvalue) => match rvalue {
151-
Rvalue::Cast(..) => ConstraintCategory::Cast,
152-
Rvalue::Use(..) => ConstraintCategory::Assignment,
153-
_ => ConstraintCategory::Other,
175+
StatementKind::Assign(ref place, ref rvalue) => {
176+
if *place == Place::Local(mir::RETURN_PLACE) {
177+
ConstraintCategory::Return
178+
} else {
179+
match rvalue {
180+
Rvalue::Cast(..) => ConstraintCategory::Cast,
181+
Rvalue::Use(..) => ConstraintCategory::Assignment,
182+
_ => ConstraintCategory::Other,
183+
}
184+
}
154185
},
155186
_ => ConstraintCategory::Other,
156187
}
157-
}
188+
};
189+
190+
Some((category, span))
158191
}
159192

160193
/// Report an error because the universal region `fr` was required to outlive
@@ -187,53 +220,36 @@ impl<'tcx> RegionInferenceContext<'tcx> {
187220
}
188221
}
189222

223+
let fr_string = match fr_name {
224+
Some(r) => format!("free region `{}`", r),
225+
None => format!("free region `{:?}`", fr),
226+
};
227+
228+
let outlived_fr_string = match outlived_fr_name {
229+
Some(r) => format!("free region `{}`", r),
230+
None => format!("free region `{:?}`", outlived_fr),
231+
};
232+
190233
let constraints = self.find_constraint_paths_from_region(fr.clone());
191234
let path = constraints.iter().min_by_key(|p| p.len()).unwrap();
192-
debug!("report_error: path={:?}", path);
193-
194-
let path = path.iter()
195-
.filter(|index| self.constraint_is_interesting(index))
196-
.collect::<Vec<&ConstraintIndex>>();
197-
debug!("report_error: path={:?}", path);
235+
debug!("report_error: shortest_path={:?}", path);
198236

199237
let mut categorized_path = path.iter().filter_map(|index| {
200-
self.constraints.get(**index).iter().filter_map(|constraint| {
201-
let span = constraint.locations.span(mir);
202-
constraint.locations.from_location().iter().filter_map(|location| {
203-
let classification = self.classify_constraint(*location, mir);
204-
Some((classification, span))
205-
}).next()
206-
}).next()
238+
self.classify_constraint(index, mir)
207239
}).collect::<Vec<(ConstraintCategory, Span)>>();
208240
debug!("report_error: categorized_path={:?}", categorized_path);
209241

210242
categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
211243
debug!("report_error: sorted_path={:?}", categorized_path);
212244

213-
if categorized_path.len() > 0 {
214-
let blame_constraint = &categorized_path[0];
215-
245+
if let Some((category, span)) = &categorized_path.first() {
216246
let mut diag = infcx.tcx.sess.struct_span_err(
217-
blame_constraint.1,
218-
&format!("{:?}", blame_constraint.0),
247+
*span, &format!("{} requires that data must outlive {}",
248+
category, outlived_fr_string),
219249
);
220250

221-
for secondary in categorized_path.iter().skip(1) {
222-
diag.span_label(secondary.1, format!("{:?}", secondary.0));
223-
}
224-
225251
diag.emit();
226252
} else {
227-
let fr_string = match fr_name {
228-
Some(r) => format!("free region `{}`", r),
229-
None => format!("free region `{:?}`", fr),
230-
};
231-
232-
let outlived_fr_string = match outlived_fr_name {
233-
Some(r) => format!("free region `{}`", r),
234-
None => format!("free region `{:?}`", outlived_fr),
235-
};
236-
237253
let mut diag = infcx.tcx.sess.struct_span_err(
238254
blame_span,
239255
&format!("{} does not outlive {}", fr_string, outlived_fr_string,),

0 commit comments

Comments
 (0)