Skip to content

Commit 078220d

Browse files
committed
extract a best_blame_constraint helper
1 parent 9ba4d33 commit 078220d

File tree

1 file changed

+123
-63
lines changed
  • src/librustc_mir/borrow_check/nll/region_infer/error_reporting

1 file changed

+123
-63
lines changed

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

Lines changed: 123 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ mod var_name;
2828
/// Constraints that are considered interesting can be categorized to
2929
/// determine why they are interesting. Order of variants indicates
3030
/// sort order of the category, thereby influencing diagnostic output.
31-
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord)]
31+
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
3232
enum ConstraintCategory {
3333
Cast,
3434
Assignment,
@@ -43,12 +43,14 @@ enum ConstraintCategory {
4343
impl fmt::Display for ConstraintCategory {
4444
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4545
match self {
46-
ConstraintCategory::Assignment |
47-
ConstraintCategory::AssignmentToUpvar => write!(f, "assignment"),
46+
ConstraintCategory::Assignment | ConstraintCategory::AssignmentToUpvar => {
47+
write!(f, "assignment")
48+
}
4849
ConstraintCategory::Return => write!(f, "return"),
4950
ConstraintCategory::Cast => write!(f, "cast"),
50-
ConstraintCategory::CallArgument |
51-
ConstraintCategory::CallArgumentToUpvar => write!(f, "argument"),
51+
ConstraintCategory::CallArgument | ConstraintCategory::CallArgumentToUpvar => {
52+
write!(f, "argument")
53+
}
5254
_ => write!(f, "free region"),
5355
}
5456
}
@@ -62,6 +64,43 @@ enum Trace {
6264
}
6365

6466
impl<'tcx> RegionInferenceContext<'tcx> {
67+
/// Tries to find the best constraint to blame for the fact that
68+
/// `R: from_region`, where `R` is some region that meets
69+
/// `target_test`. This works by following the constraint graph,
70+
/// creating a constraint path that forces `R` to outlive
71+
/// `from_region`, and then finding the best choices within that
72+
/// path to blame.
73+
fn best_blame_constraint(
74+
&self,
75+
mir: &Mir<'tcx>,
76+
from_region: RegionVid,
77+
target_test: impl Fn(RegionVid) -> bool,
78+
) -> (ConstraintCategory, Span) {
79+
debug!("best_blame_constraint(from_region={:?})", from_region);
80+
81+
// Find all paths
82+
let path = self
83+
.find_constraint_paths_between_regions(from_region, target_test)
84+
.unwrap();
85+
debug!("best_blame_constraint: path={:#?}", path);
86+
87+
// Classify each of the constraints along the path.
88+
let mut categorized_path: Vec<(ConstraintCategory, Span)> = path
89+
.iter()
90+
.map(|&index| self.classify_constraint(index, mir))
91+
.collect();
92+
debug!(
93+
"best_blame_constraint: categorized_path={:?}",
94+
categorized_path
95+
);
96+
97+
// Find what appears to be the most interesting path to report to the user.
98+
categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
99+
debug!("best_blame_constraint: sorted_path={:?}", categorized_path);
100+
101+
*categorized_path.first().unwrap()
102+
}
103+
65104
/// Walks the graph of constraints (where `'a: 'b` is considered
66105
/// an edge `'a -> 'b`) to find all paths from `from_region` to
67106
/// `to_region`. The paths are accumulated into the vector
@@ -89,7 +128,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
89128
let mut p = r;
90129
loop {
91130
match context[p] {
92-
Trace::NotVisited => bug!("found unvisited region {:?} on path to {:?}", p, r),
131+
Trace::NotVisited => {
132+
bug!("found unvisited region {:?} on path to {:?}", p, r)
133+
}
93134
Trace::FromConstraint(c) => {
94135
result.push(c);
95136
p = self.constraints[c].sup;
@@ -139,19 +180,24 @@ impl<'tcx> RegionInferenceContext<'tcx> {
139180
&self,
140181
index: ConstraintIndex,
141182
mir: &Mir<'tcx>,
142-
_infcx: &InferCtxt<'_, '_, 'tcx>,
143183
) -> (ConstraintCategory, Span) {
144184
let constraint = self.constraints[index];
145185
debug!("classify_constraint: constraint={:?}", constraint);
146186
let span = constraint.locations.span(mir);
147-
let location = constraint.locations.from_location().unwrap_or(Location::START);
187+
let location = constraint
188+
.locations
189+
.from_location()
190+
.unwrap_or(Location::START);
148191

149192
if !self.constraint_is_interesting(index) {
150193
return (ConstraintCategory::Boring, span);
151194
}
152195

153196
let data = &mir[location.block];
154-
debug!("classify_constraint: location={:?} data={:?}", location, data);
197+
debug!(
198+
"classify_constraint: location={:?} data={:?}",
199+
location, data
200+
);
155201
let category = if location.statement_index == data.statements.len() {
156202
if let Some(ref terminator) = data.terminator {
157203
debug!("classify_constraint: terminator.kind={:?}", terminator.kind);
@@ -174,8 +220,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
174220
} else {
175221
match rvalue {
176222
Rvalue::Cast(..) => ConstraintCategory::Cast,
177-
Rvalue::Use(..) |
178-
Rvalue::Aggregate(..) => ConstraintCategory::Assignment,
223+
Rvalue::Use(..) | Rvalue::Aggregate(..) => {
224+
ConstraintCategory::Assignment
225+
}
179226
_ => ConstraintCategory::Other,
180227
}
181228
}
@@ -206,27 +253,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
206253
) {
207254
debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
208255

209-
// Find all paths
210-
let path = self.find_constraint_paths_between_regions(fr, |r| r == outlived_fr).unwrap();
211-
debug!("report_error: path={:#?}", path);
212-
213-
// Classify each of the constraints along the path.
214-
let mut categorized_path: Vec<(ConstraintCategory, Span)> = path.iter()
215-
.map(|&index| self.classify_constraint(index, mir, infcx))
216-
.collect();
217-
debug!("report_error: categorized_path={:?}", categorized_path);
218-
219-
// Find what appears to be the most interesting path to report to the user.
220-
categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
221-
debug!("report_error: sorted_path={:?}", categorized_path);
222-
223-
// Get a span
224-
let (category, span) = categorized_path.first().unwrap();
256+
let (category, span) = self.best_blame_constraint(mir, fr, |r| r == outlived_fr);
225257

226258
// Check if we can use one of the "nice region errors".
227259
if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
228260
let tables = infcx.tcx.typeck_tables_of(mir_def_id);
229-
let nice = NiceRegionError::new_from_span(infcx.tcx, *span, o, f, Some(tables));
261+
let nice = NiceRegionError::new_from_span(infcx.tcx, span, o, f, Some(tables));
230262
if let Some(_error_reported) = nice.try_report() {
231263
return;
232264
}
@@ -237,22 +269,36 @@ impl<'tcx> RegionInferenceContext<'tcx> {
237269
self.universal_regions.is_local_free_region(fr),
238270
self.universal_regions.is_local_free_region(outlived_fr),
239271
) {
240-
(ConstraintCategory::Assignment, true, false) =>
241-
&ConstraintCategory::AssignmentToUpvar,
242-
(ConstraintCategory::CallArgument, true, false) =>
243-
&ConstraintCategory::CallArgumentToUpvar,
272+
(ConstraintCategory::Assignment, true, false) => ConstraintCategory::AssignmentToUpvar,
273+
(ConstraintCategory::CallArgument, true, false) => {
274+
ConstraintCategory::CallArgumentToUpvar
275+
}
244276
(category, _, _) => category,
245277
};
246278

247279
debug!("report_error: category={:?}", category);
248280
match category {
249-
ConstraintCategory::AssignmentToUpvar |
250-
ConstraintCategory::CallArgumentToUpvar =>
251-
self.report_closure_error(
252-
mir, infcx, mir_def_id, fr, outlived_fr, category, span, errors_buffer),
253-
_ =>
254-
self.report_general_error(
255-
mir, infcx, mir_def_id, fr, outlived_fr, category, span, errors_buffer),
281+
ConstraintCategory::AssignmentToUpvar | ConstraintCategory::CallArgumentToUpvar => self
282+
.report_closure_error(
283+
mir,
284+
infcx,
285+
mir_def_id,
286+
fr,
287+
outlived_fr,
288+
category,
289+
span,
290+
errors_buffer,
291+
),
292+
_ => self.report_general_error(
293+
mir,
294+
infcx,
295+
mir_def_id,
296+
fr,
297+
outlived_fr,
298+
category,
299+
span,
300+
errors_buffer,
301+
),
256302
}
257303
}
258304

@@ -263,23 +309,31 @@ impl<'tcx> RegionInferenceContext<'tcx> {
263309
mir_def_id: DefId,
264310
fr: RegionVid,
265311
outlived_fr: RegionVid,
266-
category: &ConstraintCategory,
267-
span: &Span,
312+
category: ConstraintCategory,
313+
span: Span,
268314
errors_buffer: &mut Vec<Diagnostic>,
269315
) {
270-
let fr_name_and_span = self.get_var_name_and_span_for_region(
271-
infcx.tcx, mir, fr);
272-
let outlived_fr_name_and_span = self.get_var_name_and_span_for_region(
273-
infcx.tcx, mir,outlived_fr);
316+
let fr_name_and_span = self.get_var_name_and_span_for_region(infcx.tcx, mir, fr);
317+
let outlived_fr_name_and_span =
318+
self.get_var_name_and_span_for_region(infcx.tcx, mir, outlived_fr);
274319

275320
if fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none() {
276321
return self.report_general_error(
277-
mir, infcx, mir_def_id, fr, outlived_fr, category, span, errors_buffer);
322+
mir,
323+
infcx,
324+
mir_def_id,
325+
fr,
326+
outlived_fr,
327+
category,
328+
span,
329+
errors_buffer,
330+
);
278331
}
279332

280-
let mut diag = infcx.tcx.sess.struct_span_err(
281-
*span, &format!("borrowed data escapes outside of closure"),
282-
);
333+
let mut diag = infcx
334+
.tcx
335+
.sess
336+
.struct_span_err(span, &format!("borrowed data escapes outside of closure"));
283337

284338
if let Some((outlived_fr_name, outlived_fr_span)) = outlived_fr_name_and_span {
285339
if let Some(name) = outlived_fr_name {
@@ -294,10 +348,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
294348
if let Some(name) = fr_name {
295349
diag.span_label(
296350
fr_span,
297-
format!("`{}` is a reference that is only valid in the closure body", name),
351+
format!(
352+
"`{}` is a reference that is only valid in the closure body",
353+
name
354+
),
298355
);
299356

300-
diag.span_label(*span, format!("`{}` escapes the closure body here", name));
357+
diag.span_label(span, format!("`{}` escapes the closure body here", name));
301358
}
302359
}
303360

@@ -311,24 +368,27 @@ impl<'tcx> RegionInferenceContext<'tcx> {
311368
mir_def_id: DefId,
312369
fr: RegionVid,
313370
outlived_fr: RegionVid,
314-
category: &ConstraintCategory,
315-
span: &Span,
371+
category: ConstraintCategory,
372+
span: Span,
316373
errors_buffer: &mut Vec<Diagnostic>,
317374
) {
318375
let mut diag = infcx.tcx.sess.struct_span_err(
319-
*span, &format!("unsatisfied lifetime constraints"), // FIXME
376+
span,
377+
&format!("unsatisfied lifetime constraints"), // FIXME
320378
);
321379

322380
let counter = &mut 1;
323-
let fr_name = self.give_region_a_name(
324-
infcx.tcx, mir, mir_def_id, fr, counter, &mut diag);
325-
let outlived_fr_name = self.give_region_a_name(
326-
infcx.tcx, mir, mir_def_id, outlived_fr, counter, &mut diag);
327-
328-
diag.span_label(*span, format!(
329-
"{} requires that `{}` must outlive `{}`",
330-
category, fr_name, outlived_fr_name,
331-
));
381+
let fr_name = self.give_region_a_name(infcx.tcx, mir, mir_def_id, fr, counter, &mut diag);
382+
let outlived_fr_name =
383+
self.give_region_a_name(infcx.tcx, mir, mir_def_id, outlived_fr, counter, &mut diag);
384+
385+
diag.span_label(
386+
span,
387+
format!(
388+
"{} requires that `{}` must outlive `{}`",
389+
category, fr_name, outlived_fr_name,
390+
),
391+
);
332392

333393
diag.buffer(errors_buffer);
334394
}

0 commit comments

Comments
 (0)