Skip to content

Commit

Permalink
Auto merge of #87246 - rust-lang:placeholder-pretty, r=nikomatsakis
Browse files Browse the repository at this point in the history
When pretty printing, name placeholders as bound regions

Split from #85499

When we see a placeholder that we are going to print, treat it as a bound var (and add it to a `for<...>`
  • Loading branch information
bors committed Jul 22, 2021
2 parents 602150f + b9ee2fb commit 8024983
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 46 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -995,7 +995,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let get_lifetimes = |sig| {
use rustc_hir::def::Namespace;
let mut s = String::new();
let (_, (sig, reg)) = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS)
let (_, sig, reg) = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS)
.name_all_regions(sig)
.unwrap();
let lts: Vec<String> = reg.into_iter().map(|(_, kind)| kind.to_string()).collect();
Expand Down
142 changes: 107 additions & 35 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1776,13 +1776,73 @@ impl<F: fmt::Write> FmtPrinter<'_, '_, F> {
}
}

/// Folds through bound vars and placeholders, naming them
struct RegionFolder<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
current_index: ty::DebruijnIndex,
region_map: BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
name: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
}

impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
self.tcx
}

fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
) -> ty::Binder<'tcx, T> {
self.current_index.shift_in(1);
let t = t.super_fold_with(self);
self.current_index.shift_out(1);
t
}

fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
match *t.kind() {
_ if t.has_vars_bound_at_or_above(self.current_index) || t.has_placeholders() => {
return t.super_fold_with(self);
}
_ => {}
}
t
}

fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
let name = &mut self.name;
let region = match *r {
ty::ReLateBound(_, br) => self.region_map.entry(br).or_insert_with(|| name(br)),
ty::RePlaceholder(ty::PlaceholderRegion { name: kind, .. }) => {
// If this is an anonymous placeholder, don't rename. Otherwise, in some
// async fns, we get a `for<'r> Send` bound
match kind {
ty::BrAnon(_) | ty::BrEnv => r,
_ => {
// Index doesn't matter, since this is just for naming and these never get bound
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind };
self.region_map.entry(br).or_insert_with(|| name(br))
}
}
}
_ => return r,
};
if let ty::ReLateBound(debruijn1, br) = *region {
assert_eq!(debruijn1, ty::INNERMOST);
self.tcx.mk_region(ty::ReLateBound(self.current_index, br))
} else {
region
}
}
}

// HACK(eddyb) limited to `FmtPrinter` because of `binder_depth`,
// `region_index` and `used_region_names`.
impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
pub fn name_all_regions<T>(
mut self,
value: &ty::Binder<'tcx, T>,
) -> Result<(Self, (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)), fmt::Error>
) -> Result<(Self, T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>), fmt::Error>
where
T: Print<'tcx, Self, Output = Self, Error = fmt::Error> + TypeFoldable<'tcx>,
{
Expand All @@ -1805,16 +1865,16 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {

let mut empty = true;
let mut start_or_continue = |cx: &mut Self, start: &str, cont: &str| {
write!(
cx,
"{}",
if empty {
empty = false;
start
} else {
cont
}
)
let w = if empty {
empty = false;
start
} else {
cont
};
let _ = write!(cx, "{}", w);
};
let do_continue = |cx: &mut Self, cont: Symbol| {
let _ = write!(cx, "{}", cont);
};

define_scoped_cx!(self);
Expand All @@ -1824,44 +1884,44 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
// aren't named. Eventually, we might just want this as the default, but
// this is not *quite* right and changes the ordering of some output
// anyways.
let new_value = if self.tcx().sess.verbose() {
let (new_value, map) = if self.tcx().sess.verbose() {
// anon index + 1 (BrEnv takes 0) -> name
let mut region_map: BTreeMap<u32, Symbol> = BTreeMap::default();
let bound_vars = value.bound_vars();
for var in bound_vars {
match var {
ty::BoundVariableKind::Region(ty::BrNamed(_, name)) => {
let _ = start_or_continue(&mut self, "for<", ", ");
let _ = write!(self, "{}", name);
start_or_continue(&mut self, "for<", ", ");
do_continue(&mut self, name);
}
ty::BoundVariableKind::Region(ty::BrAnon(i)) => {
let _ = start_or_continue(&mut self, "for<", ", ");
start_or_continue(&mut self, "for<", ", ");
let name = loop {
let name = name_by_region_index(region_index);
region_index += 1;
if !self.used_region_names.contains(&name) {
break name;
}
};
let _ = write!(self, "{}", name);
do_continue(&mut self, name);
region_map.insert(i + 1, name);
}
ty::BoundVariableKind::Region(ty::BrEnv) => {
let _ = start_or_continue(&mut self, "for<", ", ");
start_or_continue(&mut self, "for<", ", ");
let name = loop {
let name = name_by_region_index(region_index);
region_index += 1;
if !self.used_region_names.contains(&name) {
break name;
}
};
let _ = write!(self, "{}", name);
do_continue(&mut self, name);
region_map.insert(0, name);
}
_ => continue,
}
}
start_or_continue(&mut self, "", "> ")?;
start_or_continue(&mut self, "", "> ");

self.tcx.replace_late_bound_regions(value.clone(), |br| {
let kind = match br.kind {
Expand All @@ -1881,11 +1941,12 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
))
})
} else {
let new_value = self.tcx.replace_late_bound_regions(value.clone(), |br| {
let _ = start_or_continue(&mut self, "for<", ", ");
let tcx = self.tcx;
let mut name = |br: ty::BoundRegion| {
start_or_continue(&mut self, "for<", ", ");
let kind = match br.kind {
ty::BrNamed(_, name) => {
let _ = write!(self, "{}", name);
do_continue(&mut self, name);
br.kind
}
ty::BrAnon(_) | ty::BrEnv => {
Expand All @@ -1896,31 +1957,36 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
break name;
}
};
let _ = write!(self, "{}", name);
do_continue(&mut self, name);
ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
}
};
self.tcx.mk_region(ty::ReLateBound(
ty::INNERMOST,
ty::BoundRegion { var: br.var, kind },
))
});
start_or_continue(&mut self, "", "> ")?;
new_value
tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind }))
};
let mut folder = RegionFolder {
tcx,
current_index: ty::INNERMOST,
name: &mut name,
region_map: BTreeMap::new(),
};
let new_value = value.clone().skip_binder().fold_with(&mut folder);
let region_map = folder.region_map;
start_or_continue(&mut self, "", "> ");
(new_value, region_map)
};

self.binder_depth += 1;
self.region_index = region_index;
Ok((self, new_value))
Ok((self, new_value, map))
}

pub fn pretty_in_binder<T>(self, value: &ty::Binder<'tcx, T>) -> Result<Self, fmt::Error>
where
T: Print<'tcx, Self, Output = Self, Error = fmt::Error> + TypeFoldable<'tcx>,
{
let old_region_index = self.region_index;
let (new, new_value) = self.name_all_regions(value)?;
let mut inner = new_value.0.print(new)?;
let (new, new_value, _) = self.name_all_regions(value)?;
let mut inner = new_value.print(new)?;
inner.region_index = old_region_index;
inner.binder_depth -= 1;
Ok(inner)
Expand All @@ -1935,8 +2001,8 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
T: Print<'tcx, Self, Output = Self, Error = fmt::Error> + TypeFoldable<'tcx>,
{
let old_region_index = self.region_index;
let (new, new_value) = self.name_all_regions(value)?;
let mut inner = f(&new_value.0, new)?;
let (new, new_value, _) = self.name_all_regions(value)?;
let mut inner = f(&new_value, new)?;
inner.region_index = old_region_index;
inner.binder_depth -= 1;
Ok(inner)
Expand All @@ -1960,6 +2026,12 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
debug!("LateBoundRegionNameCollector::visit_region(r: {:?}, address: {:p})", r, &r);
if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r {
self.used_region_names.insert(name);
} else if let ty::RePlaceholder(ty::PlaceholderRegion {
name: ty::BrNamed(_, name),
..
}) = *r
{
self.used_region_names.insert(name);
}
r.super_visit_with(self)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ where
}

impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T {
//~^ ERROR the trait bound `<T as UnsafeCopy<'b, T>>::Item: Deref` is not satisfied
//~^ ERROR the trait bound `for<'b> <T as UnsafeCopy<'b, T>>::Item: Deref` is not satisfied
type Item = T;
//~^ ERROR the trait bound `for<'b> <T as UnsafeCopy<'b, T>>::Item: Deref
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ LL | type Item = T;
<&T as Deref>
<&mut T as Deref>

error[E0277]: the trait bound `<T as UnsafeCopy<'b, T>>::Item: Deref` is not satisfied
error[E0277]: the trait bound `for<'b> <T as UnsafeCopy<'b, T>>::Item: Deref` is not satisfied
--> $DIR/hr-associated-type-projection-1.rs:13:33
|
LL | impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T {
| ^^^^^^^^^^^^^^^^^ the trait `Deref` is not implemented for `<T as UnsafeCopy<'b, T>>::Item`
| ^^^^^^^^^^^^^^^^^ the trait `for<'b> Deref` is not implemented for `<T as UnsafeCopy<'b, T>>::Item`
|
help: consider further restricting the associated type
|
LL | impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T where <T as UnsafeCopy<'b, T>>::Item: Deref {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T where for<'b> <T as UnsafeCopy<'b, T>>::Item: Deref {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/closures/issue-41366.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ LL | (&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
| ^^------^
| | |
| | found signature of `fn(u16) -> _`
| expected signature of `fn(<u32 as T<'x>>::V) -> _`
| expected signature of `for<'x> fn(<u32 as T<'x>>::V) -> _`
|
= note: required for the cast to the object type `dyn for<'x> Fn(<u32 as T<'x>>::V)`

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
error[E0119]: conflicting implementations of trait `Trait` for type `for<'r> fn(fn(&'r ()))`
error[E0119]: conflicting implementations of trait `Trait` for type `for<'r> fn(for<'r> fn(&'r ()))`
--> $DIR/coherence-fn-covariant-bound-vs-static.rs:17:1
|
LL | impl Trait for for<'r> fn(fn(&'r ())) {}
| ------------------------------------- first implementation here
LL | impl<'a> Trait for fn(fn(&'a ())) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'r> fn(fn(&'r ()))`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'r> fn(for<'r> fn(&'r ()))`
|
= note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-43623.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ LL | {
LL | break_me::<Type, fn(_)>;
| ^^^^^^^^^^^^^^^^^^^^^^^
| |
| expected signature of `fn(<Type as Trait<'b>>::Assoc) -> _`
| expected signature of `for<'b> fn(<Type as Trait<'b>>::Assoc) -> _`
| found signature of `fn(()) -> _`

error: aborting due to previous error
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-60283.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ LL | F: for<'a> FnMut(<T as Trait<'a>>::Item),
LL | foo((), drop)
| ^^^^
| |
| expected signature of `fn(<() as Trait<'a>>::Item) -> _`
| expected signature of `for<'a> fn(<() as Trait<'a>>::Item) -> _`
| found signature of `fn(()) -> _`

error[E0277]: the size for values of type `<() as Trait<'_>>::Item` cannot be known at compilation time
Expand Down

0 comments on commit 8024983

Please sign in to comment.