Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit eacebf2

Browse files
committed
Pretty print quantified goals and clauses
1 parent 64aac8d commit eacebf2

16 files changed

+198
-79
lines changed

src/librustc/traits/structural_impls.rs

Lines changed: 144 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ use traits;
1414
use traits::project::Normalized;
1515
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
1616
use ty::{self, Lift, TyCtxt};
17+
use syntax::symbol::InternedString;
1718

1819
use std::fmt;
1920
use std::rc::Rc;
21+
use std::collections::{BTreeSet, BTreeMap};
2022

2123
// structural impls for the structs in traits
2224

@@ -479,7 +481,12 @@ impl<'tcx> fmt::Display for traits::DomainGoal<'tcx> {
479481
Holds(wc) => write!(fmt, "{}", wc),
480482
WellFormed(wf) => write!(fmt, "{}", wf),
481483
FromEnv(from_env) => write!(fmt, "{}", from_env),
482-
Normalize(projection) => write!(fmt, "Normalize({})", projection),
484+
Normalize(projection) => write!(
485+
fmt,
486+
"Normalize({} -> {})",
487+
projection.projection_ty,
488+
projection.ty
489+
),
483490
}
484491
}
485492
}
@@ -495,6 +502,110 @@ impl fmt::Display for traits::QuantifierKind {
495502
}
496503
}
497504

505+
/// Collect names for regions / types bound by a quantified goal / clause.
506+
/// This collector does not try to do anything clever like in ppaux, it's just used
507+
/// for debug output in tests anyway.
508+
struct BoundNamesCollector {
509+
// Just sort by name because `BoundRegion::BrNamed` does not have a `BoundVar` index anyway.
510+
regions: BTreeSet<InternedString>,
511+
512+
// Sort by `BoundVar` index, so usually this should be equivalent to the order given
513+
// by the list of type parameters.
514+
types: BTreeMap<u32, InternedString>,
515+
516+
binder_index: ty::DebruijnIndex,
517+
}
518+
519+
impl BoundNamesCollector {
520+
fn new() -> Self {
521+
BoundNamesCollector {
522+
regions: BTreeSet::new(),
523+
types: BTreeMap::new(),
524+
binder_index: ty::INNERMOST,
525+
}
526+
}
527+
528+
fn is_empty(&self) -> bool {
529+
self.regions.is_empty() && self.types.is_empty()
530+
}
531+
532+
fn write_names(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
533+
let mut start = true;
534+
for r in &self.regions {
535+
if !start {
536+
write!(fmt, ", ")?;
537+
}
538+
start = false;
539+
write!(fmt, "{}", r)?;
540+
}
541+
for (_, t) in &self.types {
542+
if !start {
543+
write!(fmt, ", ")?;
544+
}
545+
start = false;
546+
write!(fmt, "{}", t)?;
547+
}
548+
Ok(())
549+
}
550+
}
551+
552+
impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector {
553+
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {
554+
self.binder_index.shift_in(1);
555+
let result = t.super_visit_with(self);
556+
self.binder_index.shift_out(1);
557+
result
558+
}
559+
560+
fn visit_ty(&mut self, t: ty::Ty<'tcx>) -> bool {
561+
use syntax::symbol::Symbol;
562+
563+
match t.sty {
564+
ty::Bound(bound_ty) if bound_ty.index == self.binder_index => {
565+
self.types.insert(
566+
bound_ty.var.as_u32(),
567+
match bound_ty.kind {
568+
ty::BoundTyKind::Param(name) => name,
569+
ty::BoundTyKind::Anon => Symbol::intern(
570+
&format!("?{}", bound_ty.var.as_u32())
571+
).as_interned_str(),
572+
}
573+
);
574+
}
575+
576+
_ => (),
577+
};
578+
579+
t.super_visit_with(self)
580+
}
581+
582+
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
583+
use syntax::symbol::Symbol;
584+
585+
match r {
586+
ty::ReLateBound(index, br) if *index == self.binder_index => {
587+
match br {
588+
ty::BoundRegion::BrNamed(_, name) => {
589+
self.regions.insert(*name);
590+
}
591+
592+
ty::BoundRegion::BrAnon(var) => {
593+
self.regions.insert(Symbol::intern(
594+
&format!("?'{}", var)
595+
).as_interned_str());
596+
}
597+
598+
_ => (),
599+
}
600+
}
601+
602+
_ => (),
603+
};
604+
605+
r.super_visit_with(self)
606+
}
607+
}
608+
498609
impl<'tcx> fmt::Display for traits::Goal<'tcx> {
499610
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
500611
use traits::GoalKind::*;
@@ -514,8 +625,22 @@ impl<'tcx> fmt::Display for traits::Goal<'tcx> {
514625
Not(goal) => write!(fmt, "not {{ {} }}", goal),
515626
DomainGoal(goal) => write!(fmt, "{}", goal),
516627
Quantified(qkind, goal) => {
517-
// FIXME: appropriate binder names
518-
write!(fmt, "{}<> {{ {} }}", qkind, goal.skip_binder())
628+
let mut collector = BoundNamesCollector::new();
629+
goal.skip_binder().visit_with(&mut collector);
630+
631+
if !collector.is_empty() {
632+
write!(fmt, "{}<", qkind)?;
633+
collector.write_names(fmt)?;
634+
write!(fmt, "> {{ ")?;
635+
}
636+
637+
write!(fmt, "{}", goal.skip_binder())?;
638+
639+
if !collector.is_empty() {
640+
write!(fmt, " }}")?;
641+
}
642+
643+
Ok(())
519644
}
520645
CannotProve => write!(fmt, "CannotProve"),
521646
}
@@ -546,8 +671,22 @@ impl<'tcx> fmt::Display for traits::Clause<'tcx> {
546671
match self {
547672
Implies(clause) => write!(fmt, "{}", clause),
548673
ForAll(clause) => {
549-
// FIXME: appropriate binder names
550-
write!(fmt, "forall<> {{ {} }}", clause.skip_binder())
674+
let mut collector = BoundNamesCollector::new();
675+
clause.skip_binder().visit_with(&mut collector);
676+
677+
if !collector.is_empty() {
678+
write!(fmt, "forall<")?;
679+
collector.write_names(fmt)?;
680+
write!(fmt, "> {{ ")?;
681+
}
682+
683+
write!(fmt, "{}", clause.skip_binder())?;
684+
685+
if !collector.is_empty() {
686+
write!(fmt, " }}")?;
687+
}
688+
689+
Ok(())
551690
}
552691
}
553692
}

src/librustc_traits/lowering/environment.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,8 @@ crate fn environment<'a, 'tcx>(
250250
// In an fn, we assume that the arguments and all their constituents are
251251
// well-formed.
252252
if is_fn {
253-
// `skip_binder` because we move late bound regions to the root binder,
254-
// restored in the return type
253+
// `skip_binder` because we move region parameters to the root binder,
254+
// restored in the return type of this query
255255
let fn_sig = tcx.fn_sig(def_id).skip_binder().subst(tcx, bound_vars);
256256

257257
input_tys.extend(

src/librustc_traits/lowering/mod.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -600,14 +600,7 @@ impl<'a, 'tcx> ClauseDumper<'a, 'tcx> {
600600

601601
let mut strings: Vec<_> = clauses
602602
.iter()
603-
.map(|clause| {
604-
// Skip the top-level binder for a less verbose output
605-
let program_clause = match clause {
606-
Clause::Implies(program_clause) => program_clause,
607-
Clause::ForAll(program_clause) => program_clause.skip_binder(),
608-
};
609-
program_clause.to_string()
610-
})
603+
.map(|clause| clause.to_string())
611604
.collect();
612605

613606
strings.sort();

src/test/ui/chalkify/lower_env1.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ trait Foo { }
1717
trait Bar where Self: Foo { }
1818

1919
#[rustc_dump_env_program_clauses] //~ ERROR program clause dump
20-
fn bar<T: Bar>() {
20+
fn bar<T: Bar + ?Sized>() {
2121
}
2222

2323
fn main() {

src/test/ui/chalkify/lower_env1.stderr

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,19 @@ error: program clause dump
44
LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7-
= note: FromEnv(Self: Foo) :- FromEnv(Self: Bar).
8-
= note: Implemented(Self: Bar) :- FromEnv(Self: Bar).
9-
= note: WellFormed(Self: Bar) :- Implemented(Self: Bar), WellFormed(Self: Foo).
7+
= note: forall<Self> { FromEnv(Self: Foo) :- FromEnv(Self: Bar). }
8+
= note: forall<Self> { Implemented(Self: Bar) :- FromEnv(Self: Bar). }
9+
= note: forall<Self> { WellFormed(Self: Bar) :- Implemented(Self: Bar), WellFormed(Self: Foo). }
1010

1111
error: program clause dump
1212
--> $DIR/lower_env1.rs:19:1
1313
|
1414
LL | #[rustc_dump_env_program_clauses] //~ ERROR program clause dump
1515
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1616
|
17-
= note: FromEnv(Self: Foo) :- FromEnv(Self: Bar).
18-
= note: Implemented(Self: Bar) :- FromEnv(Self: Bar).
19-
= note: Implemented(Self: Foo) :- FromEnv(Self: Foo).
20-
= note: Implemented(Self: std::marker::Sized) :- FromEnv(Self: std::marker::Sized).
17+
= note: forall<Self> { FromEnv(Self: Foo) :- FromEnv(Self: Bar). }
18+
= note: forall<Self> { Implemented(Self: Bar) :- FromEnv(Self: Bar). }
19+
= note: forall<Self> { Implemented(Self: Foo) :- FromEnv(Self: Foo). }
2120

2221
error: aborting due to 2 previous errors
2322

src/test/ui/chalkify/lower_env2.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@
1414
trait Foo { }
1515

1616
#[rustc_dump_program_clauses] //~ ERROR program clause dump
17-
struct S<'a, T> where T: Foo {
17+
struct S<'a, T: ?Sized> where T: Foo {
1818
data: &'a T,
1919
}
2020

2121
#[rustc_dump_env_program_clauses] //~ ERROR program clause dump
22-
fn bar<'a, T: Foo>(x: S<T>) {
22+
fn bar<T: Foo>(_x: S<'_, T>) { // note that we have an implicit `T: Sized` bound
2323
}
2424

2525
fn main() {

src/test/ui/chalkify/lower_env2.stderr

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,20 @@ error: program clause dump
44
LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7-
= note: FromEnv(T: Foo) :- FromEnv(S<'a, T>).
8-
= note: FromEnv(T: std::marker::Sized) :- FromEnv(S<'a, T>).
9-
= note: TypeOutlives(T : 'a) :- FromEnv(S<'a, T>).
10-
= note: WellFormed(S<'a, T>) :- Implemented(T: std::marker::Sized), Implemented(T: Foo), TypeOutlives(T : 'a).
7+
= note: forall<'a, T> { FromEnv(T: Foo) :- FromEnv(S<'a, T>). }
8+
= note: forall<'a, T> { TypeOutlives(T : 'a) :- FromEnv(S<'a, T>). }
9+
= note: forall<'a, T> { WellFormed(S<'a, T>) :- Implemented(T: Foo), TypeOutlives(T : 'a). }
1110

1211
error: program clause dump
1312
--> $DIR/lower_env2.rs:21:1
1413
|
1514
LL | #[rustc_dump_env_program_clauses] //~ ERROR program clause dump
1615
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1716
|
18-
= note: FromEnv(T: Foo) :- FromEnv(S<'a, T>).
19-
= note: FromEnv(T: std::marker::Sized) :- FromEnv(S<'a, T>).
20-
= note: Implemented(Self: Foo) :- FromEnv(Self: Foo).
21-
= note: Implemented(Self: std::marker::Sized) :- FromEnv(Self: std::marker::Sized).
22-
= note: TypeOutlives(T : 'a) :- FromEnv(S<'a, T>).
17+
= note: forall<'a, T> { FromEnv(T: Foo) :- FromEnv(S<'a, T>). }
18+
= note: forall<'a, T> { TypeOutlives(T : 'a) :- FromEnv(S<'a, T>). }
19+
= note: forall<Self> { Implemented(Self: Foo) :- FromEnv(Self: Foo). }
20+
= note: forall<Self> { Implemented(Self: std::marker::Sized) :- FromEnv(Self: std::marker::Sized). }
2321

2422
error: aborting due to 2 previous errors
2523

src/test/ui/chalkify/lower_env3.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ error: program clause dump
44
LL | #[rustc_dump_env_program_clauses] //~ ERROR program clause dump
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7-
= note: Implemented(Self: Foo) :- FromEnv(Self: Foo).
7+
= note: forall<Self> { Implemented(Self: Foo) :- FromEnv(Self: Foo). }
88

99
error: program clause dump
1010
--> $DIR/lower_env3.rs:20:5
1111
|
1212
LL | #[rustc_dump_env_program_clauses] //~ ERROR program clause dump
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1414
|
15-
= note: FromEnv(Self: std::marker::Sized) :- FromEnv(Self: std::clone::Clone).
16-
= note: Implemented(Self: std::clone::Clone) :- FromEnv(Self: std::clone::Clone).
17-
= note: Implemented(Self: std::marker::Sized) :- FromEnv(Self: std::marker::Sized).
15+
= note: forall<Self> { FromEnv(Self: std::marker::Sized) :- FromEnv(Self: std::clone::Clone). }
16+
= note: forall<Self> { Implemented(Self: std::clone::Clone) :- FromEnv(Self: std::clone::Clone). }
17+
= note: forall<Self> { Implemented(Self: std::marker::Sized) :- FromEnv(Self: std::marker::Sized). }
1818

1919
error: aborting due to 2 previous errors
2020

src/test/ui/chalkify/lower_impl.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ error: program clause dump
44
LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7-
= note: Implemented(T: Foo) :- ProjectionEq(<T as std::iter::Iterator>::Item == i32), TypeOutlives(T : 'static), Implemented(T: std::iter::Iterator), Implemented(T: std::marker::Sized).
7+
= note: forall<T> { Implemented(T: Foo) :- ProjectionEq(<T as std::iter::Iterator>::Item == i32), TypeOutlives(T : 'static), Implemented(T: std::iter::Iterator), Implemented(T: std::marker::Sized). }
88

99
error: program clause dump
1010
--> $DIR/lower_impl.rs:23:5
1111
|
1212
LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1414
|
15-
= note: Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :- Implemented(T: Bar).
15+
= note: forall<T> { Normalize(<T as Bar>::Assoc -> std::vec::Vec<T>) :- Implemented(T: Bar). }
1616

1717
error: aborting due to 2 previous errors
1818

src/test/ui/chalkify/lower_struct.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
#![feature(rustc_attrs)]
1212

1313
#[rustc_dump_program_clauses] //~ ERROR program clause dump
14-
struct Foo<T> where Box<T>: Clone {
15-
_x: std::marker::PhantomData<T>,
14+
struct Foo<'a, T> where Box<T>: Clone {
15+
_x: std::marker::PhantomData<&'a T>,
1616
}
1717

1818
fn main() { }

src/test/ui/chalkify/lower_struct.stderr

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ error: program clause dump
44
LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7-
= note: FromEnv(T: std::marker::Sized) :- FromEnv(Foo<T>).
8-
= note: FromEnv(std::boxed::Box<T>: std::clone::Clone) :- FromEnv(Foo<T>).
9-
= note: WellFormed(Foo<T>) :- Implemented(T: std::marker::Sized), Implemented(std::boxed::Box<T>: std::clone::Clone).
7+
= note: forall<'a, T> { FromEnv(T: std::marker::Sized) :- FromEnv(Foo<'a, T>). }
8+
= note: forall<'a, T> { FromEnv(std::boxed::Box<T>: std::clone::Clone) :- FromEnv(Foo<'a, T>). }
9+
= note: forall<'a, T> { TypeOutlives(T : 'a) :- FromEnv(Foo<'a, T>). }
10+
= note: forall<'a, T> { WellFormed(Foo<'a, T>) :- Implemented(T: std::marker::Sized), Implemented(std::boxed::Box<T>: std::clone::Clone), TypeOutlives(T : 'a). }
1011

1112
error: aborting due to previous error
1213

src/test/ui/chalkify/lower_trait.stderr

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,20 @@ error: program clause dump
44
LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7-
= note: FromEnv(<Self as Foo<S, T>>::Assoc: Bar) :- FromEnv(Self: Foo<S, T>).
8-
= note: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<S, T>).
9-
= note: Implemented(Self: Foo<S, T>) :- FromEnv(Self: Foo<S, T>).
10-
= note: WellFormed(Self: Foo<S, T>) :- Implemented(Self: Foo<S, T>), WellFormed(S: std::marker::Sized), WellFormed(<Self as Foo<S, T>>::Assoc: Bar).
7+
= note: forall<Self, S, T> { FromEnv(<Self as Foo<S, T>>::Assoc: Bar) :- FromEnv(Self: Foo<S, T>). }
8+
= note: forall<Self, S, T> { FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<S, T>). }
9+
= note: forall<Self, S, T> { Implemented(Self: Foo<S, T>) :- FromEnv(Self: Foo<S, T>). }
10+
= note: forall<Self, S, T> { WellFormed(Self: Foo<S, T>) :- Implemented(Self: Foo<S, T>), WellFormed(S: std::marker::Sized), WellFormed(<Self as Foo<S, T>>::Assoc: Bar). }
1111

1212
error: program clause dump
1313
--> $DIR/lower_trait.rs:17:5
1414
|
1515
LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
1616
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1717
|
18-
= note: FromEnv(Self: Foo<S, T>) :- FromEnv(Unnormalized(<Self as Foo<S, T>>::Assoc)).
19-
= note: ProjectionEq(<Self as Foo<S, T>>::Assoc == Unnormalized(<Self as Foo<S, T>>::Assoc)).
20-
= note: WellFormed(Unnormalized(<Self as Foo<S, T>>::Assoc)) :- Implemented(Self: Foo<S, T>).
18+
= note: forall<Self, S, T> { FromEnv(Self: Foo<S, T>) :- FromEnv(Unnormalized(<Self as Foo<S, T>>::Assoc)). }
19+
= note: forall<Self, S, T> { ProjectionEq(<Self as Foo<S, T>>::Assoc == Unnormalized(<Self as Foo<S, T>>::Assoc)). }
20+
= note: forall<Self, S, T> { WellFormed(Unnormalized(<Self as Foo<S, T>>::Assoc)) :- Implemented(Self: Foo<S, T>). }
2121

2222
error: aborting due to 2 previous errors
2323

src/test/ui/chalkify/lower_trait_higher_rank.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@
1111
#![feature(rustc_attrs)]
1212

1313
#[rustc_dump_program_clauses] //~ ERROR program clause dump
14-
trait Foo<F> where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8
14+
trait Foo<F: ?Sized> where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8
1515
{
16-
fn s(_: F) -> F;
1716
}
1817

1918
fn main() {

0 commit comments

Comments
 (0)