Skip to content

When pretty printing, name placeholders as bound regions #87246

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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