Skip to content

Commit f44807a

Browse files
committed
Improved mechanism for naming regions in non-annotated types.
1 parent b377e7b commit f44807a

File tree

9 files changed

+127
-49
lines changed

9 files changed

+127
-49
lines changed

src/librustc/util/ppaux.rs

Lines changed: 35 additions & 5 deletions
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/region_name.rs

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use rustc::infer::InferCtxt;
1616
use rustc::mir::Mir;
1717
use rustc::ty::subst::{Substs, UnpackedKind};
1818
use rustc::ty::{self, RegionVid, Ty, TyCtxt};
19+
use rustc::util::ppaux::with_highlight_region;
1920
use rustc_errors::DiagnosticBuilder;
2021
use syntax::ast::Name;
2122
use syntax::symbol::keywords;
@@ -228,40 +229,27 @@ impl<'tcx> RegionInferenceContext<'tcx> {
228229
counter: &mut usize,
229230
diag: &mut DiagnosticBuilder<'_>,
230231
) -> Option<InternedString> {
231-
let mut type_name = infcx.extract_type_name(&argument_ty);
232-
let argument_index = self.get_argument_index_for_region(infcx.tcx, needle_fr)?;
233-
let mut first_region_name = None;
234-
235-
debug!("give_name_if_we_cannot_match_hir_ty: type_name={:?}", type_name);
236-
while let Some(start_index) = type_name.find("&'_#") {
237-
if let Some(end_index) = type_name[start_index..].find(' ') {
238-
// Need to make the `end_index` relative to the full string.
239-
let end_index = start_index + end_index;
240-
// `start_index + 1` skips the `&`.
241-
// `end_index + 1` goes to (including) the space after the region.
242-
type_name.replace_range(start_index + 1..end_index + 1, "");
243-
}
244-
}
245-
debug!("give_name_if_we_cannot_match_hir_ty: type_name={:?}", type_name);
246-
247-
let mut index = 0;
248-
while let Some(next_index) = type_name[index..].find("&") {
249-
// At this point, next_index is the index of the `&` character (starting from
250-
// the last `&` character).
251-
debug!("give_name_if_we_cannot_match_hir_ty: start-of-loop index={:?} type_name={:?}",
252-
index, type_name);
253-
let region_name = self.synthesize_region_name(counter).as_str();
254-
if first_region_name.is_none() { first_region_name = Some(region_name); }
255-
256-
// Compute the index of the character after `&` in the original string.
257-
index = next_index + index + 1;
258-
type_name.insert_str(index, &format!("{} ", region_name));
259-
}
260-
261-
let (_, span) = self.get_argument_name_and_span_for_region(mir, argument_index);
262-
diag.span_label(span, format!("has type `{}`", type_name));
263-
264-
first_region_name.map(|s| s.as_interned_str())
232+
let type_name = with_highlight_region(needle_fr, *counter, || {
233+
infcx.extract_type_name(&argument_ty)
234+
});
235+
236+
debug!("give_name_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}",
237+
type_name, needle_fr);
238+
let assigned_region_name = if type_name.find(&format!("'{}", counter)).is_some() {
239+
// Only add a label if we can confirm that a region was labelled.
240+
let argument_index = self.get_argument_index_for_region(infcx.tcx, needle_fr)?;
241+
let (_, span) = self.get_argument_name_and_span_for_region(mir, argument_index);
242+
diag.span_label(span, format!("has type `{}`", type_name));
243+
244+
// This counter value will already have been used, so this function will increment it
245+
// so the next value will be used next and return the region name that would have been
246+
// used.
247+
Some(self.synthesize_region_name(counter))
248+
} else {
249+
None
250+
};
251+
252+
assigned_region_name
265253
}
266254

267255
/// Attempts to highlight the specific part of a type annotation

src/test/ui/issue-52533-1.nll.stderr

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
warning: not reporting region error due to nll
2+
--> $DIR/issue-52533-1.rs:19:18
3+
|
4+
LL | gimme(|x, y| y)
5+
| ^
6+
7+
error: unsatisfied lifetime constraints
8+
--> $DIR/issue-52533-1.rs:19:18
9+
|
10+
LL | gimme(|x, y| y)
11+
| - - ^ closure was supposed to return data with lifetime `'1` but it is returning data with lifetime `'2`
12+
| | |
13+
| | has type `&Foo<'_, '1, u32>`
14+
| has type `&Foo<'_, '2, u32>`
15+
16+
error: aborting due to previous error
17+

src/test/ui/issue-52533-1.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![allow(warnings)]
12+
13+
struct Foo<'a, 'b, T: 'a + 'b> { x: &'a T, y: &'b T }
14+
15+
fn gimme(_: impl for<'a, 'b, 'c> FnOnce(&'a Foo<'a, 'b, u32>,
16+
&'a Foo<'a, 'c, u32>) -> &'a Foo<'a, 'b, u32>) { }
17+
18+
fn main() {
19+
gimme(|x, y| y)
20+
//~^ ERROR mismatched types [E0308]
21+
}

src/test/ui/issue-52533-1.stderr

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-52533-1.rs:19:18
3+
|
4+
LL | gimme(|x, y| y)
5+
| ^ lifetime mismatch
6+
|
7+
= note: expected type `&Foo<'_, '_, u32>`
8+
found type `&Foo<'_, '_, u32>`
9+
note: the anonymous lifetime #4 defined on the body at 19:11...
10+
--> $DIR/issue-52533-1.rs:19:11
11+
|
12+
LL | gimme(|x, y| y)
13+
| ^^^^^^^^
14+
note: ...does not necessarily outlive the anonymous lifetime #3 defined on the body at 19:11
15+
--> $DIR/issue-52533-1.rs:19:11
16+
|
17+
LL | gimme(|x, y| y)
18+
| ^^^^^^^^
19+
20+
error: aborting due to previous error
21+
22+
For more information about this error, try `rustc --explain E0308`.

src/test/ui/nll/closure-requirements/escape-argument-callee.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ LL | let mut closure = expect_sig(|p, y| *p = y);
1111
| - - ^^^^^^ free region requires that `'1` must outlive `'2`
1212
| | |
1313
| | has type `&'1 i32`
14-
| has type `&'2 mut &'3 i32`
14+
| has type `&mut &'2 i32`
1515

1616
note: No external requirements
1717
--> $DIR/escape-argument-callee.rs:36:38

src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ error: unsatisfied lifetime constraints
88
--> $DIR/propagate-approximated-fail-no-postdom.rs:57:13
99
|
1010
LL | |_outlives1, _outlives2, _outlives3, x, y| {
11-
| ---------- ---------- has type `std::cell::Cell<&'3 &'4 u32>`
11+
| ---------- ---------- has type `std::cell::Cell<&'2 &u32>`
1212
| |
13-
| has type `std::cell::Cell<&'1 &'2 u32>`
13+
| has type `std::cell::Cell<&&'1 u32>`
1414
...
1515
LL | demand_y(x, y, p) //~ ERROR
16-
| ^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'3`
16+
| ^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
1717

1818
note: No external requirements
1919
--> $DIR/propagate-approximated-fail-no-postdom.rs:53:9

src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ error: unsatisfied lifetime constraints
88
--> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:9
99
|
1010
LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
11-
| --------- - has type `&'1 std::cell::Cell<&'2 u32>`
11+
| --------- - has type `&std::cell::Cell<&'1 u32>`
1212
| |
13-
| has type `&'3 std::cell::Cell<&'4 &'5 u32>`
13+
| has type `&std::cell::Cell<&'2 &u32>`
1414
LL | // Only works if 'x: 'y:
1515
LL | demand_y(x, y, x.get())
16-
| ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'3`
16+
| ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
1717

1818
note: No external requirements
1919
--> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:45:47

src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ error: unsatisfied lifetime constraints
88
--> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:51:9
99
|
1010
LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
11-
| ---------- ---------- has type `&'4 std::cell::Cell<&'5 &'6 u32>`
11+
| ---------- ---------- has type `&std::cell::Cell<&'2 &u32>`
1212
| |
13-
| has type `&'1 std::cell::Cell<&'2 &'3 u32>`
13+
| has type `&std::cell::Cell<&'1 &u32>`
1414
LL | // Only works if 'x: 'y:
1515
LL | demand_y(x, y, x.get())
16-
| ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'4`
16+
| ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
1717

1818
note: No external requirements
1919
--> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:49:47

0 commit comments

Comments
 (0)