Skip to content

Commit b6cbc1e

Browse files
committed
Auto merge of #52648 - davidtwco:issue-52533, r=nikomatsakis
[nll] improve the "fully elaborated type" case in region errors Fixes #52533. r? @nikomatsakis
2 parents 6998b36 + 2e4224a commit b6cbc1e

30 files changed

+328
-149
lines changed

src/librustc/infer/error_reporting/need_type_info.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
7474

7575

7676
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
77-
fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String {
77+
pub fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String {
7878
if let ty::TyInfer(ty::TyVar(ty_vid)) = (*ty).sty {
7979
let ty_vars = self.type_variables.borrow();
8080
if let TypeVariableOrigin::TypeParameterDefinition(_, name) =

src/librustc/util/ppaux.rs

+35-5
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr};
1919
use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple};
2020
use ty::{TyClosure, TyGenerator, TyGeneratorWitness, TyForeign, TyProjection, TyAnon};
2121
use ty::{TyDynamic, TyInt, TyUint, TyInfer};
22-
use ty::{self, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind};
22+
use ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind};
2323
use util::nodemap::FxHashSet;
2424

2525
use std::cell::Cell;
@@ -32,6 +32,12 @@ use syntax::ast::CRATE_NODE_ID;
3232
use syntax::symbol::{Symbol, InternedString};
3333
use hir;
3434

35+
thread_local! {
36+
/// Mechanism for highlighting of specific regions for display in NLL region inference errors.
37+
/// Contains region to highlight and counter for number to use when highlighting.
38+
static HIGHLIGHT_REGION: Cell<Option<(RegionVid, usize)>> = Cell::new(None)
39+
}
40+
3541
macro_rules! gen_display_debug_body {
3642
( $with:path ) => {
3743
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -562,6 +568,19 @@ pub fn parameterized<F: fmt::Write>(f: &mut F,
562568
PrintContext::new().parameterized(f, substs, did, projections)
563569
}
564570

571+
fn get_highlight_region() -> Option<(RegionVid, usize)> {
572+
HIGHLIGHT_REGION.with(|hr| hr.get())
573+
}
574+
575+
pub fn with_highlight_region<R>(r: RegionVid, counter: usize, op: impl FnOnce() -> R) -> R {
576+
HIGHLIGHT_REGION.with(|hr| {
577+
assert_eq!(hr.get(), None);
578+
hr.set(Some((r, counter)));
579+
let r = op();
580+
hr.set(None);
581+
r
582+
})
583+
}
565584

566585
impl<'a, T: Print> Print for &'a T {
567586
fn print<F: fmt::Write>(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result {
@@ -733,7 +752,7 @@ define_print! {
733752
define_print! {
734753
() ty::RegionKind, (self, f, cx) {
735754
display {
736-
if cx.is_verbose {
755+
if cx.is_verbose || get_highlight_region().is_some() {
737756
return self.print_debug(f, cx);
738757
}
739758

@@ -905,6 +924,15 @@ impl fmt::Debug for ty::FloatVid {
905924

906925
impl fmt::Debug for ty::RegionVid {
907926
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
927+
if let Some((region, counter)) = get_highlight_region() {
928+
debug!("RegionVid.fmt: region={:?} self={:?} counter={:?}", region, self, counter);
929+
return if *self == region {
930+
write!(f, "'{:?}", counter)
931+
} else {
932+
write!(f, "'_")
933+
}
934+
}
935+
908936
write!(f, "'_#{}r", self.index())
909937
}
910938
}
@@ -1022,9 +1050,11 @@ define_print! {
10221050
TyRef(r, ty, mutbl) => {
10231051
write!(f, "&")?;
10241052
let s = r.print_to_string(cx);
1025-
write!(f, "{}", s)?;
1026-
if !s.is_empty() {
1027-
write!(f, " ")?;
1053+
if s != "'_" {
1054+
write!(f, "{}", s)?;
1055+
if !s.is_empty() {
1056+
write!(f, " ")?;
1057+
}
10281058
}
10291059
ty::TypeAndMut { ty, mutbl }.print(f, cx)
10301060
}

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

+62-80
Original file line numberDiff line numberDiff line change
@@ -31,26 +31,21 @@ mod var_name;
3131
enum ConstraintCategory {
3232
Cast,
3333
Assignment,
34-
AssignmentToUpvar,
3534
Return,
36-
CallArgumentToUpvar,
3735
CallArgument,
3836
Other,
3937
Boring,
4038
}
4139

4240
impl fmt::Display for ConstraintCategory {
4341
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
42+
// Must end with a space. Allows for empty names to be provided.
4443
match self {
45-
ConstraintCategory::Assignment | ConstraintCategory::AssignmentToUpvar => {
46-
write!(f, "assignment")
47-
}
48-
ConstraintCategory::Return => write!(f, "return"),
49-
ConstraintCategory::Cast => write!(f, "cast"),
50-
ConstraintCategory::CallArgument | ConstraintCategory::CallArgumentToUpvar => {
51-
write!(f, "argument")
52-
}
53-
_ => write!(f, "free region"),
44+
ConstraintCategory::Assignment => write!(f, "assignment "),
45+
ConstraintCategory::Return => write!(f, "return "),
46+
ConstraintCategory::Cast => write!(f, "cast "),
47+
ConstraintCategory::CallArgument => write!(f, "argument "),
48+
_ => write!(f, ""),
5449
}
5550
}
5651
}
@@ -224,10 +219,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
224219
"constraint_is_interesting: locations={:?} constraint={:?}",
225220
constraint.locations, constraint
226221
);
227-
if let Locations::Interesting(_) = constraint.locations {
228-
true
229-
} else {
230-
false
222+
223+
match constraint.locations {
224+
Locations::Interesting(_) | Locations::All => true,
225+
_ => false,
231226
}
232227
}
233228

@@ -320,45 +315,26 @@ impl<'tcx> RegionInferenceContext<'tcx> {
320315
}
321316
}
322317

323-
let category = match (
324-
category,
318+
let (fr_is_local, outlived_fr_is_local): (bool, bool) = (
325319
self.universal_regions.is_local_free_region(fr),
326320
self.universal_regions.is_local_free_region(outlived_fr),
327-
) {
328-
(ConstraintCategory::Assignment, true, false) => ConstraintCategory::AssignmentToUpvar,
329-
(ConstraintCategory::CallArgument, true, false) => {
330-
ConstraintCategory::CallArgumentToUpvar
331-
}
332-
(category, _, _) => category,
321+
);
322+
debug!("report_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}",
323+
fr_is_local, outlived_fr_is_local, category);
324+
325+
match (category, fr_is_local, outlived_fr_is_local) {
326+
(ConstraintCategory::Assignment, true, false) |
327+
(ConstraintCategory::CallArgument, true, false) =>
328+
self.report_escaping_data_error(mir, infcx, mir_def_id, fr, outlived_fr,
329+
category, span, errors_buffer),
330+
_ =>
331+
self.report_general_error(mir, infcx, mir_def_id, fr, fr_is_local,
332+
outlived_fr, outlived_fr_is_local,
333+
category, span, errors_buffer),
333334
};
334-
335-
debug!("report_error: category={:?}", category);
336-
match category {
337-
ConstraintCategory::AssignmentToUpvar | ConstraintCategory::CallArgumentToUpvar => self
338-
.report_closure_error(
339-
mir,
340-
infcx,
341-
mir_def_id,
342-
fr,
343-
outlived_fr,
344-
category,
345-
span,
346-
errors_buffer,
347-
),
348-
_ => self.report_general_error(
349-
mir,
350-
infcx,
351-
mir_def_id,
352-
fr,
353-
outlived_fr,
354-
category,
355-
span,
356-
errors_buffer,
357-
),
358-
}
359335
}
360336

361-
fn report_closure_error(
337+
fn report_escaping_data_error(
362338
&self,
363339
mir: &Mir<'tcx>,
364340
infcx: &InferCtxt<'_, '_, 'tcx>,
@@ -373,29 +349,23 @@ impl<'tcx> RegionInferenceContext<'tcx> {
373349
let outlived_fr_name_and_span =
374350
self.get_var_name_and_span_for_region(infcx.tcx, mir, outlived_fr);
375351

352+
let escapes_from = if infcx.tcx.is_closure(mir_def_id) { "closure" } else { "function" };
353+
376354
if fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none() {
377-
return self.report_general_error(
378-
mir,
379-
infcx,
380-
mir_def_id,
381-
fr,
382-
outlived_fr,
383-
category,
384-
span,
385-
errors_buffer,
386-
);
355+
return self.report_general_error(mir, infcx, mir_def_id,
356+
fr, true, outlived_fr, false,
357+
category, span, errors_buffer);
387358
}
388359

389-
let mut diag = infcx
390-
.tcx
391-
.sess
392-
.struct_span_err(span, &format!("borrowed data escapes outside of closure"));
360+
let mut diag = infcx.tcx.sess.struct_span_err(
361+
span, &format!("borrowed data escapes outside of {}", escapes_from),
362+
);
393363

394364
if let Some((outlived_fr_name, outlived_fr_span)) = outlived_fr_name_and_span {
395365
if let Some(name) = outlived_fr_name {
396366
diag.span_label(
397367
outlived_fr_span,
398-
format!("`{}` is declared here, outside of the closure body", name),
368+
format!("`{}` is declared here, outside of the {} body", name, escapes_from),
399369
);
400370
}
401371
}
@@ -404,13 +374,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
404374
if let Some(name) = fr_name {
405375
diag.span_label(
406376
fr_span,
407-
format!(
408-
"`{}` is a reference that is only valid in the closure body",
409-
name
410-
),
377+
format!("`{}` is a reference that is only valid in the {} body",
378+
name, escapes_from),
411379
);
412380

413-
diag.span_label(span, format!("`{}` escapes the closure body here", name));
381+
diag.span_label(span, format!("`{}` escapes the {} body here",
382+
name, escapes_from));
414383
}
415384
}
416385

@@ -423,7 +392,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
423392
infcx: &InferCtxt<'_, '_, 'tcx>,
424393
mir_def_id: DefId,
425394
fr: RegionVid,
395+
fr_is_local: bool,
426396
outlived_fr: RegionVid,
397+
outlived_fr_is_local: bool,
427398
category: ConstraintCategory,
428399
span: Span,
429400
errors_buffer: &mut Vec<Diagnostic>,
@@ -434,17 +405,28 @@ impl<'tcx> RegionInferenceContext<'tcx> {
434405
);
435406

436407
let counter = &mut 1;
437-
let fr_name = self.give_region_a_name(infcx.tcx, mir, mir_def_id, fr, counter, &mut diag);
438-
let outlived_fr_name =
439-
self.give_region_a_name(infcx.tcx, mir, mir_def_id, outlived_fr, counter, &mut diag);
440-
441-
diag.span_label(
442-
span,
443-
format!(
444-
"{} requires that `{}` must outlive `{}`",
445-
category, fr_name, outlived_fr_name,
446-
),
447-
);
408+
let fr_name = self.give_region_a_name(
409+
infcx, mir, mir_def_id, fr, counter, &mut diag);
410+
let outlived_fr_name = self.give_region_a_name(
411+
infcx, mir, mir_def_id, outlived_fr, counter, &mut diag);
412+
413+
let mir_def_name = if infcx.tcx.is_closure(mir_def_id) { "closure" } else { "function" };
414+
415+
match (category, outlived_fr_is_local, fr_is_local) {
416+
(ConstraintCategory::Return, true, _) => {
417+
diag.span_label(span, format!(
418+
"{} was supposed to return data with lifetime `{}` but it is returning \
419+
data with lifetime `{}`",
420+
mir_def_name, fr_name, outlived_fr_name,
421+
));
422+
},
423+
_ => {
424+
diag.span_label(span, format!(
425+
"{}requires that `{}` must outlive `{}`",
426+
category, fr_name, outlived_fr_name,
427+
));
428+
},
429+
}
448430

449431
diag.buffer(errors_buffer);
450432
}

0 commit comments

Comments
 (0)