Skip to content

Commit 69e93e8

Browse files
authored
Rollup merge of rust-lang#64416 - mark-i-m:region-naming-ctx, r=estebank
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. r? @estebank Split out from rust-lang#58281
2 parents aeb32f0 + 2a774b1 commit 69e93e8

File tree

5 files changed

+316
-214
lines changed

5 files changed

+316
-214
lines changed

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

+128-115
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,39 @@ 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+
/// The region inference context used for borrow chekcing this MIR body.
60+
#[allow(dead_code)] // FIXME(mark-i-m): used by outlives suggestions
61+
region_infcx: &'b RegionInferenceContext<'tcx>,
62+
63+
/// The inference context used for type checking.
64+
infcx: &'b InferCtxt<'a, 'tcx>,
65+
66+
/// The MIR def we are reporting errors on.
67+
mir_def_id: DefId,
68+
69+
/// The MIR body we are reporting errors on (for convenience).
70+
body: &'b Body<'tcx>,
71+
72+
/// Any upvars for the MIR body we have kept track of during borrow checking.
73+
upvars: &'b [Upvar],
74+
}
75+
76+
/// Information about the various region constraints involved in a borrow checker error.
77+
#[derive(Clone, Debug)]
78+
pub struct ErrorConstraintInfo {
79+
// fr: outlived_fr
80+
fr: RegionVid,
81+
fr_is_local: bool,
82+
outlived_fr: RegionVid,
83+
outlived_fr_is_local: bool,
84+
85+
// Category and span for best blame constraint
86+
category: ConstraintCategory,
87+
span: Span,
88+
}
89+
5790
impl<'tcx> RegionInferenceContext<'tcx> {
5891
/// Tries to find the best constraint to blame for the fact that
5992
/// `R: from_region`, where `R` is some region that meets
@@ -257,16 +290,16 @@ impl<'tcx> RegionInferenceContext<'tcx> {
257290
/// ```
258291
///
259292
/// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
260-
pub(super) fn report_error(
261-
&self,
293+
pub(super) fn report_error<'a>(
294+
&'a self,
262295
body: &Body<'tcx>,
263296
upvars: &[Upvar],
264-
infcx: &InferCtxt<'_, 'tcx>,
297+
infcx: &'a InferCtxt<'a, 'tcx>,
265298
mir_def_id: DefId,
266299
fr: RegionVid,
267300
outlived_fr: RegionVid,
268-
errors_buffer: &mut Vec<Diagnostic>,
269-
) {
301+
renctx: &mut RegionErrorNamingCtx,
302+
) -> DiagnosticBuilder<'a> {
270303
debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
271304

272305
let (category, _, span) = self.best_blame_constraint(body, fr, |r| {
@@ -279,8 +312,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
279312
let tables = infcx.tcx.typeck_tables_of(mir_def_id);
280313
let nice = NiceRegionError::new_from_span(infcx, span, o, f, Some(tables));
281314
if let Some(diag) = nice.try_report_from_nll() {
282-
diag.buffer(errors_buffer);
283-
return;
315+
return diag;
284316
}
285317
}
286318

@@ -293,45 +325,28 @@ impl<'tcx> RegionInferenceContext<'tcx> {
293325
"report_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}",
294326
fr_is_local, outlived_fr_is_local, category
295327
);
328+
329+
let errctx = ErrorReportingCtx {
330+
region_infcx: self,
331+
infcx,
332+
mir_def_id,
333+
body,
334+
upvars,
335+
};
336+
337+
let errci = ErrorConstraintInfo {
338+
fr, outlived_fr, fr_is_local, outlived_fr_is_local, category, span
339+
};
340+
296341
match (category, fr_is_local, outlived_fr_is_local) {
297342
(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-
)
343+
self.report_fnmut_error(&errctx, &errci, renctx)
308344
}
309345
(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-
};
346+
| (ConstraintCategory::CallArgument, true, false) =>
347+
self.report_escaping_data_error(&errctx, &errci, renctx),
348+
_ => self.report_general_error(&errctx, &errci, renctx),
349+
}
335350
}
336351

337352
/// We have a constraint `fr1: fr2` that is not satisfied, where
@@ -379,19 +394,19 @@ impl<'tcx> RegionInferenceContext<'tcx> {
379394
/// ```
380395
fn report_fnmut_error(
381396
&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
397+
errctx: &ErrorReportingCtx<'_, '_, 'tcx>,
398+
errci: &ErrorConstraintInfo,
399+
renctx: &mut RegionErrorNamingCtx,
400+
) -> DiagnosticBuilder<'_> {
401+
let ErrorConstraintInfo {
402+
outlived_fr, span, ..
403+
} = errci;
404+
405+
let mut diag = errctx
406+
.infcx
392407
.tcx
393408
.sess
394-
.struct_span_err(span, "captured variable cannot escape `FnMut` closure body");
409+
.struct_span_err(*span, "captured variable cannot escape `FnMut` closure body");
395410

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

406-
diag.span_label(span, message);
421+
diag.span_label(*span, message);
407422

408-
match self.give_region_a_name(infcx, body, upvars, mir_def_id, outlived_fr, &mut 1)
409-
.unwrap().source
410-
{
423+
match self.give_region_a_name(errctx, renctx, *outlived_fr).unwrap().source {
411424
RegionNameSource::NamedEarlyBoundRegion(fr_span)
412425
| RegionNameSource::NamedFreeRegion(fr_span)
413426
| RegionNameSource::SynthesizedFreeEnvRegion(fr_span, _)
@@ -427,7 +440,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
427440
);
428441
diag.note("...therefore, they cannot allow references to captured variables to escape");
429442

430-
diag.buffer(errors_buffer);
443+
diag
431444
}
432445

433446
/// Reports a error specifically for when data is escaping a closure.
@@ -444,20 +457,22 @@ impl<'tcx> RegionInferenceContext<'tcx> {
444457
/// ```
445458
fn report_escaping_data_error(
446459
&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-
) {
460+
errctx: &ErrorReportingCtx<'_, '_, 'tcx>,
461+
errci: &ErrorConstraintInfo,
462+
renctx: &mut RegionErrorNamingCtx,
463+
) -> DiagnosticBuilder<'_> {
464+
let ErrorReportingCtx {
465+
infcx, body, upvars, ..
466+
} = errctx;
467+
468+
let ErrorConstraintInfo {
469+
span, category, ..
470+
} = errci;
471+
457472
let fr_name_and_span =
458-
self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, fr);
473+
self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, errci.fr);
459474
let outlived_fr_name_and_span =
460-
self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, outlived_fr);
475+
self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, errci.outlived_fr);
461476

462477
let escapes_from = match self.universal_regions.defining_ty {
463478
DefiningTy::Closure(..) => "closure",
@@ -469,27 +484,23 @@ impl<'tcx> RegionInferenceContext<'tcx> {
469484
// Revert to the normal error in these cases.
470485
// Assignments aren't "escapes" in function items.
471486
if (fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none())
472-
|| (category == ConstraintCategory::Assignment && escapes_from == "function")
487+
|| (*category == ConstraintCategory::Assignment && escapes_from == "function")
473488
|| escapes_from == "const"
474489
{
475490
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,
491+
errctx,
492+
&ErrorConstraintInfo {
493+
fr_is_local: true,
494+
outlived_fr_is_local: false,
495+
.. *errci
496+
},
497+
renctx,
487498
);
488499
}
489500

490501
let mut diag = borrowck_errors::borrowed_data_escapes_closure(
491502
infcx.tcx,
492-
span,
503+
*span,
493504
escapes_from,
494505
);
495506

@@ -513,12 +524,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
513524
);
514525

515526
diag.span_label(
516-
span,
527+
*span,
517528
format!("`{}` escapes the {} body here", fr_name, escapes_from),
518529
);
519530
}
520531

521-
diag.buffer(errors_buffer);
532+
diag
522533
}
523534

524535
/// Reports a region inference error for the general case with named/synthesized lifetimes to
@@ -538,41 +549,37 @@ impl<'tcx> RegionInferenceContext<'tcx> {
538549
/// ```
539550
fn report_general_error(
540551
&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-
) {
552+
errctx: &ErrorReportingCtx<'_, '_, 'tcx>,
553+
errci: &ErrorConstraintInfo,
554+
renctx: &mut RegionErrorNamingCtx,
555+
) -> DiagnosticBuilder<'_> {
556+
let ErrorReportingCtx {
557+
infcx, mir_def_id, ..
558+
} = errctx;
559+
let ErrorConstraintInfo {
560+
fr, fr_is_local, outlived_fr, outlived_fr_is_local, span, category, ..
561+
} = errci;
562+
553563
let mut diag = infcx.tcx.sess.struct_span_err(
554-
span,
564+
*span,
555565
"lifetime may not live long enough"
556566
);
557567

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) {
568+
let mir_def_name = if infcx.tcx.is_closure(*mir_def_id) {
567569
"closure"
568570
} else {
569571
"function"
570572
};
571573

574+
let fr_name = self.give_region_a_name(errctx, renctx, *fr).unwrap();
575+
fr_name.highlight_region_name(&mut diag);
576+
let outlived_fr_name = self.give_region_a_name(errctx, renctx, *outlived_fr).unwrap();
577+
outlived_fr_name.highlight_region_name(&mut diag);
578+
572579
match (category, outlived_fr_is_local, fr_is_local) {
573580
(ConstraintCategory::Return, true, _) => {
574581
diag.span_label(
575-
span,
582+
*span,
576583
format!(
577584
"{} was supposed to return data with lifetime `{}` but it is returning \
578585
data with lifetime `{}`",
@@ -582,7 +589,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
582589
}
583590
_ => {
584591
diag.span_label(
585-
span,
592+
*span,
586593
format!(
587594
"{}requires that `{}` must outlive `{}`",
588595
category.description(),
@@ -593,9 +600,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
593600
}
594601
}
595602

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

598-
diag.buffer(errors_buffer);
605+
diag
599606
}
600607

601608
/// Adds a suggestion to errors where a `impl Trait` is returned.
@@ -704,8 +711,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
704711
borrow_region,
705712
|r| self.provides_universal_region(r, borrow_region, outlived_region)
706713
);
707-
let outlived_fr_name =
708-
self.give_region_a_name(infcx, body, upvars, mir_def_id, outlived_region, &mut 1);
714+
715+
let mut renctx = RegionErrorNamingCtx::new();
716+
let errctx = ErrorReportingCtx {
717+
infcx, body, upvars, mir_def_id,
718+
region_infcx: self,
719+
};
720+
let outlived_fr_name = self.give_region_a_name(&errctx, &mut renctx, outlived_region);
721+
709722
(category, from_closure, span, outlived_fr_name)
710723
}
711724

0 commit comments

Comments
 (0)