diff options
| author | David Wood <david@davidtw.co> | 2018-07-26 12:29:58 +0200 |
|---|---|---|
| committer | David Wood <david@davidtw.co> | 2018-07-27 13:00:56 +0200 |
| commit | f44807ae1ec15c983586077b53445bb45f083327 (patch) | |
| tree | 2d31a269b839df0001a8b48baaf0bf9f29538c5e | |
| parent | b377e7bbfbf584de4c1a775fd41b957cbd2e057b (diff) | |
| download | rust-f44807ae1ec15c983586077b53445bb45f083327.tar.gz rust-f44807ae1ec15c983586077b53445bb45f083327.zip | |
Improved mechanism for naming regions in non-annotated types.
9 files changed, 127 insertions, 49 deletions
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index c67453d2b20..15b5edaa3d5 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -19,7 +19,7 @@ use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr}; use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple}; use ty::{TyClosure, TyGenerator, TyGeneratorWitness, TyForeign, TyProjection, TyAnon}; use ty::{TyDynamic, TyInt, TyUint, TyInfer}; -use ty::{self, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind}; +use ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind}; use util::nodemap::FxHashSet; use std::cell::Cell; @@ -32,6 +32,12 @@ use syntax::ast::CRATE_NODE_ID; use syntax::symbol::{Symbol, InternedString}; use hir; +thread_local! { + /// Mechanism for highlighting of specific regions for display in NLL region inference errors. + /// Contains region to highlight and counter for number to use when highlighting. + static HIGHLIGHT_REGION: Cell<Option<(RegionVid, usize)>> = Cell::new(None) +} + macro_rules! gen_display_debug_body { ( $with:path ) => { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -562,6 +568,19 @@ pub fn parameterized<F: fmt::Write>(f: &mut F, PrintContext::new().parameterized(f, substs, did, projections) } +fn get_highlight_region() -> Option<(RegionVid, usize)> { + HIGHLIGHT_REGION.with(|hr| hr.get()) +} + +pub fn with_highlight_region<R>(r: RegionVid, counter: usize, op: impl FnOnce() -> R) -> R { + HIGHLIGHT_REGION.with(|hr| { + assert_eq!(hr.get(), None); + hr.set(Some((r, counter))); + let r = op(); + hr.set(None); + r + }) +} impl<'a, T: Print> Print for &'a T { fn print<F: fmt::Write>(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result { @@ -733,7 +752,7 @@ define_print! { define_print! { () ty::RegionKind, (self, f, cx) { display { - if cx.is_verbose { + if cx.is_verbose || get_highlight_region().is_some() { return self.print_debug(f, cx); } @@ -905,6 +924,15 @@ impl fmt::Debug for ty::FloatVid { impl fmt::Debug for ty::RegionVid { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some((region, counter)) = get_highlight_region() { + debug!("RegionVid.fmt: region={:?} self={:?} counter={:?}", region, self, counter); + return if *self == region { + write!(f, "'{:?}", counter) + } else { + write!(f, "'_") + } + } + write!(f, "'_#{}r", self.index()) } } @@ -1022,9 +1050,11 @@ define_print! { TyRef(r, ty, mutbl) => { write!(f, "&")?; let s = r.print_to_string(cx); - write!(f, "{}", s)?; - if !s.is_empty() { - write!(f, " ")?; + if s != "'_" { + write!(f, "{}", s)?; + if !s.is_empty() { + write!(f, " ")?; + } } ty::TypeAndMut { ty, mutbl }.print(f, cx) } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs index f3b437c38d8..8505d8e1ef3 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs @@ -16,6 +16,7 @@ use rustc::infer::InferCtxt; use rustc::mir::Mir; use rustc::ty::subst::{Substs, UnpackedKind}; use rustc::ty::{self, RegionVid, Ty, TyCtxt}; +use rustc::util::ppaux::with_highlight_region; use rustc_errors::DiagnosticBuilder; use syntax::ast::Name; use syntax::symbol::keywords; @@ -228,40 +229,27 @@ impl<'tcx> RegionInferenceContext<'tcx> { counter: &mut usize, diag: &mut DiagnosticBuilder<'_>, ) -> Option<InternedString> { - let mut type_name = infcx.extract_type_name(&argument_ty); - let argument_index = self.get_argument_index_for_region(infcx.tcx, needle_fr)?; - let mut first_region_name = None; - - debug!("give_name_if_we_cannot_match_hir_ty: type_name={:?}", type_name); - while let Some(start_index) = type_name.find("&'_#") { - if let Some(end_index) = type_name[start_index..].find(' ') { - // Need to make the `end_index` relative to the full string. - let end_index = start_index + end_index; - // `start_index + 1` skips the `&`. - // `end_index + 1` goes to (including) the space after the region. - type_name.replace_range(start_index + 1..end_index + 1, ""); - } - } - debug!("give_name_if_we_cannot_match_hir_ty: type_name={:?}", type_name); - - let mut index = 0; - while let Some(next_index) = type_name[index..].find("&") { - // At this point, next_index is the index of the `&` character (starting from - // the last `&` character). - debug!("give_name_if_we_cannot_match_hir_ty: start-of-loop index={:?} type_name={:?}", - index, type_name); - let region_name = self.synthesize_region_name(counter).as_str(); - if first_region_name.is_none() { first_region_name = Some(region_name); } - - // Compute the index of the character after `&` in the original string. - index = next_index + index + 1; - type_name.insert_str(index, &format!("{} ", region_name)); - } - - let (_, span) = self.get_argument_name_and_span_for_region(mir, argument_index); - diag.span_label(span, format!("has type `{}`", type_name)); - - first_region_name.map(|s| s.as_interned_str()) + let type_name = with_highlight_region(needle_fr, *counter, || { + infcx.extract_type_name(&argument_ty) + }); + + debug!("give_name_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}", + type_name, needle_fr); + let assigned_region_name = if type_name.find(&format!("'{}", counter)).is_some() { + // Only add a label if we can confirm that a region was labelled. + let argument_index = self.get_argument_index_for_region(infcx.tcx, needle_fr)?; + let (_, span) = self.get_argument_name_and_span_for_region(mir, argument_index); + diag.span_label(span, format!("has type `{}`", type_name)); + + // This counter value will already have been used, so this function will increment it + // so the next value will be used next and return the region name that would have been + // used. + Some(self.synthesize_region_name(counter)) + } else { + None + }; + + assigned_region_name } /// Attempts to highlight the specific part of a type annotation diff --git a/src/test/ui/issue-52533-1.nll.stderr b/src/test/ui/issue-52533-1.nll.stderr new file mode 100644 index 00000000000..87fda1dd99c --- /dev/null +++ b/src/test/ui/issue-52533-1.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to nll + --> $DIR/issue-52533-1.rs:19:18 + | +LL | gimme(|x, y| y) + | ^ + +error: unsatisfied lifetime constraints + --> $DIR/issue-52533-1.rs:19:18 + | +LL | gimme(|x, y| y) + | - - ^ closure was supposed to return data with lifetime `'1` but it is returning data with lifetime `'2` + | | | + | | has type `&Foo<'_, '1, u32>` + | has type `&Foo<'_, '2, u32>` + +error: aborting due to previous error + diff --git a/src/test/ui/issue-52533-1.rs b/src/test/ui/issue-52533-1.rs new file mode 100644 index 00000000000..22af5a86702 --- /dev/null +++ b/src/test/ui/issue-52533-1.rs @@ -0,0 +1,21 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(warnings)] + +struct Foo<'a, 'b, T: 'a + 'b> { x: &'a T, y: &'b T } + +fn gimme(_: impl for<'a, 'b, 'c> FnOnce(&'a Foo<'a, 'b, u32>, + &'a Foo<'a, 'c, u32>) -> &'a Foo<'a, 'b, u32>) { } + +fn main() { + gimme(|x, y| y) + //~^ ERROR mismatched types [E0308] +} diff --git a/src/test/ui/issue-52533-1.stderr b/src/test/ui/issue-52533-1.stderr new file mode 100644 index 00000000000..38deb7d66de --- /dev/null +++ b/src/test/ui/issue-52533-1.stderr @@ -0,0 +1,22 @@ +error[E0308]: mismatched types + --> $DIR/issue-52533-1.rs:19:18 + | +LL | gimme(|x, y| y) + | ^ lifetime mismatch + | + = note: expected type `&Foo<'_, '_, u32>` + found type `&Foo<'_, '_, u32>` +note: the anonymous lifetime #4 defined on the body at 19:11... + --> $DIR/issue-52533-1.rs:19:11 + | +LL | gimme(|x, y| y) + | ^^^^^^^^ +note: ...does not necessarily outlive the anonymous lifetime #3 defined on the body at 19:11 + --> $DIR/issue-52533-1.rs:19:11 + | +LL | gimme(|x, y| y) + | ^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr index c7fdbe1685c..99da2141ce9 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr @@ -11,7 +11,7 @@ LL | let mut closure = expect_sig(|p, y| *p = y); | - - ^^^^^^ free region requires that `'1` must outlive `'2` | | | | | has type `&'1 i32` - | has type `&'2 mut &'3 i32` + | has type `&mut &'2 i32` note: No external requirements --> $DIR/escape-argument-callee.rs:36:38 diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr index 6882b08f330..b4508824901 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr @@ -8,12 +8,12 @@ error: unsatisfied lifetime constraints --> $DIR/propagate-approximated-fail-no-postdom.rs:57:13 | LL | |_outlives1, _outlives2, _outlives3, x, y| { - | ---------- ---------- has type `std::cell::Cell<&'3 &'4 u32>` + | ---------- ---------- has type `std::cell::Cell<&'2 &u32>` | | - | has type `std::cell::Cell<&'1 &'2 u32>` + | has type `std::cell::Cell<&&'1 u32>` ... LL | demand_y(x, y, p) //~ ERROR - | ^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'3` + | ^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` note: No external requirements --> $DIR/propagate-approximated-fail-no-postdom.rs:53:9 diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr index 771d1df2df0..40ebda4419b 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr @@ -8,12 +8,12 @@ error: unsatisfied lifetime constraints --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:9 | LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { - | --------- - has type `&'1 std::cell::Cell<&'2 u32>` + | --------- - has type `&std::cell::Cell<&'1 u32>` | | - | has type `&'3 std::cell::Cell<&'4 &'5 u32>` + | has type `&std::cell::Cell<&'2 &u32>` LL | // Only works if 'x: 'y: LL | demand_y(x, y, x.get()) - | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'3` + | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` note: No external requirements --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:45:47 diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr index 1ac52e5e560..37ea6103976 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr @@ -8,12 +8,12 @@ error: unsatisfied lifetime constraints --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:51:9 | LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { - | ---------- ---------- has type `&'4 std::cell::Cell<&'5 &'6 u32>` + | ---------- ---------- has type `&std::cell::Cell<&'2 &u32>` | | - | has type `&'1 std::cell::Cell<&'2 &'3 u32>` + | has type `&std::cell::Cell<&'1 &u32>` LL | // Only works if 'x: 'y: LL | demand_y(x, y, x.get()) - | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'4` + | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` note: No external requirements --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:49:47 |
