From 9b0480bec63fb1d096fd9017604a861f80ea7df1 Mon Sep 17 00:00:00 2001 From: Wonwoo Choi Date: Tue, 26 Sep 2017 00:36:08 +0900 Subject: [PATCH] Name higher-ranked lifetimes properly while displaying Now they don't shadow other lifetimes. --- src/librustc/ty/context.rs | 6 + src/librustc/util/ppaux.rs | 90 ++++++++++---- .../ui/anonymous-higher-ranked-lifetime.rs | 40 +++++++ .../anonymous-higher-ranked-lifetime.stderr | 112 ++++++++++++++++++ .../regions-fn-subtyping-return-static.stderr | 2 +- 5 files changed, 229 insertions(+), 21 deletions(-) create mode 100644 src/test/ui/anonymous-higher-ranked-lifetime.rs create mode 100644 src/test/ui/anonymous-higher-ranked-lifetime.stderr diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 740299b91f1..a7eacc3744d 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -915,6 +915,10 @@ pub struct GlobalCtxt<'tcx> { /// Maps Expr NodeId's to `true` iff `&expr` can have 'static lifetime. pub rvalue_promotable_to_static: RefCell>, + pub display_used_late_bound_region_names: RefCell>>, + + pub display_late_bound_region_index: Cell, + /// The definite name of the current crate after taking into account /// attributes, commandline parameters, etc. pub crate_name: Symbol, @@ -1189,6 +1193,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { selection_cache: traits::SelectionCache::new(), evaluation_cache: traits::EvaluationCache::new(), rvalue_promotable_to_static: RefCell::new(NodeMap()), + display_used_late_bound_region_names: RefCell::new(None), + display_late_bound_region_index: Cell::new(0), crate_name: Symbol::intern(crate_name), data_layout, layout_interner: RefCell::new(FxHashSet()), diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 214973e3085..a6fb7a0f25c 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -20,6 +20,7 @@ use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple}; use ty::{TyClosure, TyGenerator, TyProjection, TyAnon}; use ty::{TyDynamic, TyInt, TyUint, TyInfer}; use ty::{self, Ty, TyCtxt, TypeFoldable}; +use util::nodemap::FxHashSet; use std::cell::Cell; use std::fmt; @@ -259,12 +260,34 @@ pub fn parameterized(f: &mut fmt::Formatter, Ok(()) } +struct LateBoundRegionNameCollector(FxHashSet); + +impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + match *r { + ty::ReLateBound(_, ty::BrNamed(_, name)) => { + self.0.insert(name); + }, + _ => {}, + } + r.super_visit_with(self) + } +} + fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter, tcx: TyCtxt<'a, 'gcx, 'tcx>, original: &ty::Binder, lifted: Option>) -> fmt::Result where T: fmt::Display, U: fmt::Display + TypeFoldable<'tcx> { + fn name_by_region_index(index: usize) -> Symbol { + match index { + 0 => Symbol::intern("'r"), + 1 => Symbol::intern("'s"), + i => Symbol::intern(&format!("'t{}", i-2)), + } + } + // Replace any anonymous late-bound regions with named // variants, using gensym'd identifiers, so that we can // clearly differentiate between named and unnamed regions in @@ -286,27 +309,54 @@ fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter, } }; - let new_value = tcx.replace_late_bound_regions(&value, |br| { - let _ = start_or_continue(f, "for<", ", "); - let br = match br { - ty::BrNamed(_, name) => { - let _ = write!(f, "{}", name); - br - } - ty::BrAnon(_) | - ty::BrFresh(_) | - ty::BrEnv => { - let name = Symbol::intern("'r"); - let _ = write!(f, "{}", name); - ty::BrNamed(tcx.hir.local_def_id(CRATE_NODE_ID), - name) - } - }; - tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), br)) - }).0; + // If displaying is just started, collect named late-bound regions. + let display_just_started = tcx.display_used_late_bound_region_names.borrow().is_none(); + if display_just_started { + let mut collector = LateBoundRegionNameCollector(FxHashSet()); + value.visit_with(&mut collector); + *tcx.display_used_late_bound_region_names.borrow_mut() = Some(collector.0); + } + let old_region_index = tcx.display_late_bound_region_index.get(); + let mut region_index = old_region_index; + let new_value = { + let used_region_names = tcx.display_used_late_bound_region_names.borrow(); + let used_region_names = used_region_names.as_ref().unwrap(); + tcx.replace_late_bound_regions(&value, |br| { + let _ = start_or_continue(f, "for<", ", "); + let br = match br { + ty::BrNamed(_, name) => { + let _ = write!(f, "{}", name); + br + } + ty::BrAnon(_) | + ty::BrFresh(_) | + ty::BrEnv => { + let name = loop { + let name = name_by_region_index(region_index); + region_index += 1; + if !used_region_names.contains(&name) { + break name; + } + }; + let _ = write!(f, "{}", name); + ty::BrNamed(tcx.hir.local_def_id(CRATE_NODE_ID), + name) + } + }; + tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), br)) + }).0 + }; start_or_continue(f, "", "> ")?; - write!(f, "{}", new_value) + + // Push current state to gcx, and restore after writing new_value. + tcx.display_late_bound_region_index.set(region_index); + write!(f, "{}", new_value)?; + tcx.display_late_bound_region_index.set(old_region_index); + if display_just_started { + *tcx.display_used_late_bound_region_names.borrow_mut() = None; + } + Ok(()) } impl<'tcx> fmt::Display for &'tcx ty::Slice> { @@ -782,7 +832,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { write!(f, "}}") } TyFnPtr(ref bare_fn) => { - write!(f, "{}", bare_fn.0) + write!(f, "{}", bare_fn) } TyInfer(infer_ty) => write!(f, "{}", infer_ty), TyError => write!(f, "[type error]"), diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.rs b/src/test/ui/anonymous-higher-ranked-lifetime.rs new file mode 100644 index 00000000000..f2d04c16d99 --- /dev/null +++ b/src/test/ui/anonymous-higher-ranked-lifetime.rs @@ -0,0 +1,40 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + f1(|_: (), _: ()| {}); + f2(|_: (), _: ()| {}); + f3(|_: (), _: ()| {}); + f4(|_: (), _: ()| {}); + f5(|_: (), _: ()| {}); + g1(|_: (), _: ()| {}); + g2(|_: (), _: ()| {}); + g3(|_: (), _: ()| {}); + g4(|_: (), _: ()| {}); + h1(|_: (), _: (), _: (), _: ()| {}); + h2(|_: (), _: (), _: (), _: ()| {}); +} + +// Basic +fn f1(_: F) where F: Fn(&(), &()) {} +fn f2(_: F) where F: for<'a> Fn(&'a (), &()) {} +fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {} +fn f4(_: F) where F: for<'r> Fn(&(), &'r ()) {} +fn f5(_: F) where F: for<'r> Fn(&'r (), &'r ()) {} + +// Nested +fn g1(_: F) where F: Fn(&(), Box) {} +fn g2(_: F) where F: Fn(&(), fn(&())) {} +fn g3(_: F) where F: for<'s> Fn(&'s (), Box) {} +fn g4(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {} + +// Mixed +fn h1(_: F) where F: Fn(&(), Box, &(), fn(&(), &())) {} +fn h2(_: F) where F: for<'t0> Fn(&(), Box, &'t0 (), fn(&(), &())) {} diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.stderr b/src/test/ui/anonymous-higher-ranked-lifetime.stderr new file mode 100644 index 00000000000..f962b772203 --- /dev/null +++ b/src/test/ui/anonymous-higher-ranked-lifetime.stderr @@ -0,0 +1,112 @@ +error[E0631]: type mismatch in closure arguments + --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5 + | +12 | f1(|_: (), _: ()| {}); + | ^^ ----------------- found signature of `fn((), ()) -> _` + | | + | expected signature of `for<'r, 's> fn(&'r (), &'s ()) -> _` + | + = note: required by `f1` + +error[E0631]: type mismatch in closure arguments + --> $DIR/anonymous-higher-ranked-lifetime.rs:13:5 + | +13 | f2(|_: (), _: ()| {}); + | ^^ ----------------- found signature of `fn((), ()) -> _` + | | + | expected signature of `for<'a, 'r> fn(&'a (), &'r ()) -> _` + | + = note: required by `f2` + +error[E0631]: type mismatch in closure arguments + --> $DIR/anonymous-higher-ranked-lifetime.rs:14:5 + | +14 | f3(|_: (), _: ()| {}); + | ^^ ----------------- found signature of `fn((), ()) -> _` + | | + | expected signature of `for<'r> fn(&(), &'r ()) -> _` + | + = note: required by `f3` + +error[E0631]: type mismatch in closure arguments + --> $DIR/anonymous-higher-ranked-lifetime.rs:15:5 + | +15 | f4(|_: (), _: ()| {}); + | ^^ ----------------- found signature of `fn((), ()) -> _` + | | + | expected signature of `for<'s, 'r> fn(&'s (), &'r ()) -> _` + | + = note: required by `f4` + +error[E0631]: type mismatch in closure arguments + --> $DIR/anonymous-higher-ranked-lifetime.rs:16:5 + | +16 | f5(|_: (), _: ()| {}); + | ^^ ----------------- found signature of `fn((), ()) -> _` + | | + | expected signature of `for<'r> fn(&'r (), &'r ()) -> _` + | + = note: required by `f5` + +error[E0631]: type mismatch in closure arguments + --> $DIR/anonymous-higher-ranked-lifetime.rs:17:5 + | +17 | g1(|_: (), _: ()| {}); + | ^^ ----------------- found signature of `fn((), ()) -> _` + | | + | expected signature of `for<'r> fn(&'r (), std::boxed::Box std::ops::Fn(&'s ()) + 'static>) -> _` + | + = note: required by `g1` + +error[E0631]: type mismatch in closure arguments + --> $DIR/anonymous-higher-ranked-lifetime.rs:18:5 + | +18 | g2(|_: (), _: ()| {}); + | ^^ ----------------- found signature of `fn((), ()) -> _` + | | + | expected signature of `for<'r> fn(&'r (), for<'s> fn(&'s ())) -> _` + | + = note: required by `g2` + +error[E0631]: type mismatch in closure arguments + --> $DIR/anonymous-higher-ranked-lifetime.rs:19:5 + | +19 | g3(|_: (), _: ()| {}); + | ^^ ----------------- found signature of `fn((), ()) -> _` + | | + | expected signature of `for<'s> fn(&'s (), std::boxed::Box std::ops::Fn(&'r ()) + 'static>) -> _` + | + = note: required by `g3` + +error[E0631]: type mismatch in closure arguments + --> $DIR/anonymous-higher-ranked-lifetime.rs:20:5 + | +20 | g4(|_: (), _: ()| {}); + | ^^ ----------------- found signature of `fn((), ()) -> _` + | | + | expected signature of `for<'s> fn(&'s (), for<'r> fn(&'r ())) -> _` + | + = note: required by `g4` + +error[E0631]: type mismatch in closure arguments + --> $DIR/anonymous-higher-ranked-lifetime.rs:21:5 + | +21 | h1(|_: (), _: (), _: (), _: ()| {}); + | ^^ ------------------------------- found signature of `fn((), (), (), ()) -> _` + | | + | expected signature of `for<'r, 's> fn(&'r (), std::boxed::Box std::ops::Fn(&'t0 ()) + 'static>, &'s (), for<'t0, 't1> fn(&'t0 (), &'t1 ())) -> _` + | + = note: required by `h1` + +error[E0631]: type mismatch in closure arguments + --> $DIR/anonymous-higher-ranked-lifetime.rs:22:5 + | +22 | h2(|_: (), _: (), _: (), _: ()| {}); + | ^^ ------------------------------- found signature of `fn((), (), (), ()) -> _` + | | + | expected signature of `for<'r, 't0> fn(&'r (), std::boxed::Box std::ops::Fn(&'s ()) + 'static>, &'t0 (), for<'s, 't1> fn(&'s (), &'t1 ())) -> _` + | + = note: required by `h2` + +error: aborting due to 11 previous errors + diff --git a/src/test/ui/regions-fn-subtyping-return-static.stderr b/src/test/ui/regions-fn-subtyping-return-static.stderr index 1598a8a40d2..0c88c63edeb 100644 --- a/src/test/ui/regions-fn-subtyping-return-static.stderr +++ b/src/test/ui/regions-fn-subtyping-return-static.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types 51 | want_F(bar); //~ ERROR E0308 | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx | - = note: expected type `fn(&'cx S) -> &'cx S` + = note: expected type `for<'cx> fn(&'cx S) -> &'cx S` found type `fn(&'a S) -> &S {bar::<'_>}` error: aborting due to previous error