Skip to content

Commit 68b1a87

Browse files
committed
Various refactorings to clean up nll diagnostics
- Create ErrorReportingCtx and ErrorConstraintInfo, vasting reducing the number of arguments passed around everywhere in the error reporting code - Create RegionErrorNamingCtx, making a given lifetime have consistent numbering thoughout all error messages for that MIR def. - Make the error reporting code return the DiagnosticBuilder rather than directly buffer the Diagnostic. This makes it easier to modify the diagnostic later, e.g. to add suggestions.
1 parent eb48d6b commit 68b1a87

File tree

3 files changed

+303
-207
lines changed

3 files changed

+303
-207
lines changed

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

Lines changed: 126 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc::infer::NLLRegionVariableOrigin;
1313
use rustc::mir::{ConstraintCategory, Location, Body};
1414
use rustc::ty::{self, RegionVid};
1515
use rustc_data_structures::indexed_vec::IndexVec;
16-
use rustc_errors::{Diagnostic, DiagnosticBuilder};
16+
use rustc_errors::DiagnosticBuilder;
1717
use std::collections::VecDeque;
1818
use syntax::errors::Applicability;
1919
use syntax::symbol::kw;
@@ -22,7 +22,7 @@ use syntax_pos::Span;
2222
mod region_name;
2323
mod var_name;
2424

25-
crate use self::region_name::{RegionName, RegionNameSource};
25+
crate use self::region_name::{RegionName, RegionNameSource, RegionErrorNamingCtx};
2626

2727
impl ConstraintDescription for ConstraintCategory {
2828
fn description(&self) -> &'static str {
@@ -54,6 +54,30 @@ enum Trace {
5454
NotVisited,
5555
}
5656

57+
/// Various pieces of state used when reporting borrow checker errors.
58+
pub struct ErrorReportingCtx<'a, 'b, 'tcx> {
59+
rinfcx: &'b RegionInferenceContext<'tcx>,
60+
infcx: &'b InferCtxt<'a, 'tcx>,
61+
62+
mir_def_id: DefId,
63+
body: &'b Body<'tcx>,
64+
upvars: &'b [Upvar],
65+
}
66+
67+
/// Information about the various region constraints involved in a borrow checker error.
68+
#[derive(Clone, Debug)]
69+
pub struct ErrorConstraintInfo {
70+
// fr: outlived_fr
71+
fr: RegionVid,
72+
fr_is_local: bool,
73+
outlived_fr: RegionVid,
74+
outlived_fr_is_local: bool,
75+
76+
// Category and span for best blame constraint
77+
category: ConstraintCategory,
78+
span: Span,
79+
}
80+
5781
impl<'tcx> RegionInferenceContext<'tcx> {
5882
/// Tries to find the best constraint to blame for the fact that
5983
/// `R: from_region`, where `R` is some region that meets
@@ -257,16 +281,16 @@ impl<'tcx> RegionInferenceContext<'tcx> {
257281
/// ```
258282
///
259283
/// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
260-
pub(super) fn report_error(
261-
&self,
284+
pub(super) fn report_error<'a>(
285+
&'a self,
262286
body: &Body<'tcx>,
263287
upvars: &[Upvar],
264-
infcx: &InferCtxt<'_, 'tcx>,
288+
infcx: &'a InferCtxt<'a, 'tcx>,
265289
mir_def_id: DefId,
266290
fr: RegionVid,
267291
outlived_fr: RegionVid,
268-
errors_buffer: &mut Vec<Diagnostic>,
269-
) {
292+
renctx: &mut RegionErrorNamingCtx,
293+
) -> DiagnosticBuilder<'a> {
270294
debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
271295

272296
let (category, _, span) = self.best_blame_constraint(body, fr, |r| {
@@ -279,8 +303,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
279303
let tables = infcx.tcx.typeck_tables_of(mir_def_id);
280304
let nice = NiceRegionError::new_from_span(infcx, span, o, f, Some(tables));
281305
if let Some(diag) = nice.try_report_from_nll() {
282-
diag.buffer(errors_buffer);
283-
return;
306+
return diag;
284307
}
285308
}
286309

@@ -293,45 +316,35 @@ impl<'tcx> RegionInferenceContext<'tcx> {
293316
"report_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}",
294317
fr_is_local, outlived_fr_is_local, category
295318
);
319+
320+
let errctx = ErrorReportingCtx {
321+
rinfcx: self,
322+
infcx,
323+
mir_def_id,
324+
body,
325+
upvars,
326+
};
327+
328+
let errci = ErrorConstraintInfo {
329+
fr, outlived_fr, fr_is_local, outlived_fr_is_local, category, span
330+
};
331+
296332
match (category, fr_is_local, outlived_fr_is_local) {
297333
(ConstraintCategory::Return, true, false) if self.is_closure_fn_mut(infcx, fr) => {
298-
self.report_fnmut_error(
299-
body,
300-
upvars,
301-
infcx,
302-
mir_def_id,
303-
fr,
304-
outlived_fr,
305-
span,
306-
errors_buffer,
307-
)
334+
self.report_fnmut_error(&errctx, &errci, renctx)
308335
}
309336
(ConstraintCategory::Assignment, true, false)
310-
| (ConstraintCategory::CallArgument, true, false) => self.report_escaping_data_error(
311-
body,
312-
upvars,
313-
infcx,
314-
mir_def_id,
315-
fr,
316-
outlived_fr,
317-
category,
318-
span,
319-
errors_buffer,
320-
),
321-
_ => self.report_general_error(
322-
body,
323-
upvars,
324-
infcx,
325-
mir_def_id,
326-
fr,
327-
fr_is_local,
328-
outlived_fr,
329-
outlived_fr_is_local,
330-
category,
331-
span,
332-
errors_buffer,
333-
),
334-
};
337+
| (ConstraintCategory::CallArgument, true, false) => {
338+
let mut db = self.report_escaping_data_error(&errctx, &errci, renctx);
339+
340+
db
341+
}
342+
_ => {
343+
let mut db = self.report_general_error(&errctx, &errci, renctx);
344+
345+
db
346+
}
347+
}
335348
}
336349

337350
/// We have a constraint `fr1: fr2` that is not satisfied, where
@@ -379,19 +392,19 @@ impl<'tcx> RegionInferenceContext<'tcx> {
379392
/// ```
380393
fn report_fnmut_error(
381394
&self,
382-
body: &Body<'tcx>,
383-
upvars: &[Upvar],
384-
infcx: &InferCtxt<'_, 'tcx>,
385-
mir_def_id: DefId,
386-
_fr: RegionVid,
387-
outlived_fr: RegionVid,
388-
span: Span,
389-
errors_buffer: &mut Vec<Diagnostic>,
390-
) {
391-
let mut diag = infcx
395+
errctx: &ErrorReportingCtx<'_, '_, 'tcx>,
396+
errci: &ErrorConstraintInfo,
397+
renctx: &mut RegionErrorNamingCtx,
398+
) -> DiagnosticBuilder<'_> {
399+
let ErrorConstraintInfo {
400+
outlived_fr, span, ..
401+
} = errci;
402+
403+
let mut diag = errctx
404+
.infcx
392405
.tcx
393406
.sess
394-
.struct_span_err(span, "captured variable cannot escape `FnMut` closure body");
407+
.struct_span_err(*span, "captured variable cannot escape `FnMut` closure body");
395408

396409
// We should check if the return type of this closure is in fact a closure - in that
397410
// case, we can special case the error further.
@@ -403,11 +416,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
403416
"returns a reference to a captured variable which escapes the closure body"
404417
};
405418

406-
diag.span_label(span, message);
419+
diag.span_label(*span, message);
407420

408-
match self.give_region_a_name(infcx, body, upvars, mir_def_id, outlived_fr, &mut 1)
409-
.unwrap().source
410-
{
421+
match self.give_region_a_name(errctx, renctx, *outlived_fr).unwrap().source {
411422
RegionNameSource::NamedEarlyBoundRegion(fr_span)
412423
| RegionNameSource::NamedFreeRegion(fr_span)
413424
| RegionNameSource::SynthesizedFreeEnvRegion(fr_span, _)
@@ -427,7 +438,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
427438
);
428439
diag.note("...therefore, they cannot allow references to captured variables to escape");
429440

430-
diag.buffer(errors_buffer);
441+
diag
431442
}
432443

433444
/// Reports a error specifically for when data is escaping a closure.
@@ -444,20 +455,22 @@ impl<'tcx> RegionInferenceContext<'tcx> {
444455
/// ```
445456
fn report_escaping_data_error(
446457
&self,
447-
body: &Body<'tcx>,
448-
upvars: &[Upvar],
449-
infcx: &InferCtxt<'_, 'tcx>,
450-
mir_def_id: DefId,
451-
fr: RegionVid,
452-
outlived_fr: RegionVid,
453-
category: ConstraintCategory,
454-
span: Span,
455-
errors_buffer: &mut Vec<Diagnostic>,
456-
) {
458+
errctx: &ErrorReportingCtx<'_, '_, 'tcx>,
459+
errci: &ErrorConstraintInfo,
460+
renctx: &mut RegionErrorNamingCtx,
461+
) -> DiagnosticBuilder<'_> {
462+
let ErrorReportingCtx {
463+
infcx, body, upvars, ..
464+
} = errctx;
465+
466+
let ErrorConstraintInfo {
467+
span, category, ..
468+
} = errci;
469+
457470
let fr_name_and_span =
458-
self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, fr);
471+
self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, errci.fr);
459472
let outlived_fr_name_and_span =
460-
self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, outlived_fr);
473+
self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, errci.outlived_fr);
461474

462475
let escapes_from = match self.universal_regions.defining_ty {
463476
DefiningTy::Closure(..) => "closure",
@@ -469,27 +482,23 @@ impl<'tcx> RegionInferenceContext<'tcx> {
469482
// Revert to the normal error in these cases.
470483
// Assignments aren't "escapes" in function items.
471484
if (fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none())
472-
|| (category == ConstraintCategory::Assignment && escapes_from == "function")
485+
|| (*category == ConstraintCategory::Assignment && escapes_from == "function")
473486
|| escapes_from == "const"
474487
{
475488
return self.report_general_error(
476-
body,
477-
upvars,
478-
infcx,
479-
mir_def_id,
480-
fr,
481-
true,
482-
outlived_fr,
483-
false,
484-
category,
485-
span,
486-
errors_buffer,
489+
errctx,
490+
&ErrorConstraintInfo {
491+
fr_is_local: true,
492+
outlived_fr_is_local: false,
493+
.. *errci
494+
},
495+
renctx,
487496
);
488497
}
489498

490499
let mut diag = borrowck_errors::borrowed_data_escapes_closure(
491500
infcx.tcx,
492-
span,
501+
*span,
493502
escapes_from,
494503
);
495504

@@ -513,12 +522,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
513522
);
514523

515524
diag.span_label(
516-
span,
525+
*span,
517526
format!("`{}` escapes the {} body here", fr_name, escapes_from),
518527
);
519528
}
520529

521-
diag.buffer(errors_buffer);
530+
diag
522531
}
523532

524533
/// Reports a region inference error for the general case with named/synthesized lifetimes to
@@ -538,41 +547,37 @@ impl<'tcx> RegionInferenceContext<'tcx> {
538547
/// ```
539548
fn report_general_error(
540549
&self,
541-
body: &Body<'tcx>,
542-
upvars: &[Upvar],
543-
infcx: &InferCtxt<'_, 'tcx>,
544-
mir_def_id: DefId,
545-
fr: RegionVid,
546-
fr_is_local: bool,
547-
outlived_fr: RegionVid,
548-
outlived_fr_is_local: bool,
549-
category: ConstraintCategory,
550-
span: Span,
551-
errors_buffer: &mut Vec<Diagnostic>,
552-
) {
550+
errctx: &ErrorReportingCtx<'_, '_, 'tcx>,
551+
errci: &ErrorConstraintInfo,
552+
renctx: &mut RegionErrorNamingCtx,
553+
) -> DiagnosticBuilder<'_> {
554+
let ErrorReportingCtx {
555+
infcx, mir_def_id, ..
556+
} = errctx;
557+
let ErrorConstraintInfo {
558+
fr, fr_is_local, outlived_fr, outlived_fr_is_local, span, category, ..
559+
} = errci;
560+
553561
let mut diag = infcx.tcx.sess.struct_span_err(
554-
span,
562+
*span,
555563
"lifetime may not live long enough"
556564
);
557565

558-
let counter = &mut 1;
559-
let fr_name = self.give_region_a_name(
560-
infcx, body, upvars, mir_def_id, fr, counter).unwrap();
561-
fr_name.highlight_region_name(&mut diag);
562-
let outlived_fr_name =
563-
self.give_region_a_name(infcx, body, upvars, mir_def_id, outlived_fr, counter).unwrap();
564-
outlived_fr_name.highlight_region_name(&mut diag);
565-
566-
let mir_def_name = if infcx.tcx.is_closure(mir_def_id) {
566+
let mir_def_name = if infcx.tcx.is_closure(*mir_def_id) {
567567
"closure"
568568
} else {
569569
"function"
570570
};
571571

572+
let fr_name = self.give_region_a_name(errctx, renctx, *fr).unwrap();
573+
fr_name.highlight_region_name(&mut diag);
574+
let outlived_fr_name = self.give_region_a_name(errctx, renctx, *outlived_fr).unwrap();
575+
outlived_fr_name.highlight_region_name(&mut diag);
576+
572577
match (category, outlived_fr_is_local, fr_is_local) {
573578
(ConstraintCategory::Return, true, _) => {
574579
diag.span_label(
575-
span,
580+
*span,
576581
format!(
577582
"{} was supposed to return data with lifetime `{}` but it is returning \
578583
data with lifetime `{}`",
@@ -582,7 +587,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
582587
}
583588
_ => {
584589
diag.span_label(
585-
span,
590+
*span,
586591
format!(
587592
"{}requires that `{}` must outlive `{}`",
588593
category.description(),
@@ -593,9 +598,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
593598
}
594599
}
595600

596-
self.add_static_impl_trait_suggestion(infcx, &mut diag, fr, fr_name, outlived_fr);
601+
self.add_static_impl_trait_suggestion(infcx, &mut diag, *fr, fr_name, *outlived_fr);
597602

598-
diag.buffer(errors_buffer);
603+
diag
599604
}
600605

601606
/// Adds a suggestion to errors where a `impl Trait` is returned.
@@ -704,8 +709,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
704709
borrow_region,
705710
|r| self.provides_universal_region(r, borrow_region, outlived_region)
706711
);
707-
let outlived_fr_name =
708-
self.give_region_a_name(infcx, body, upvars, mir_def_id, outlived_region, &mut 1);
712+
713+
let mut renctx = RegionErrorNamingCtx::new();
714+
let errctx = ErrorReportingCtx {
715+
infcx, body, upvars, mir_def_id,
716+
rinfcx: self,
717+
};
718+
let outlived_fr_name = self.give_region_a_name(&errctx, &mut renctx, outlived_region);
719+
709720
(category, from_closure, span, outlived_fr_name)
710721
}
711722

0 commit comments

Comments
 (0)