about summary refs log tree commit diff
path: root/src/librustc/traits/structural_impls.rs
diff options
context:
space:
mode:
authorscalexm <alexandre@scalexm.fr>2018-10-31 18:55:40 +0100
committerscalexm <alexandre@scalexm.fr>2018-11-13 12:28:43 +0100
commiteacebf24b0e42df1cc8161d8a5023c83d24ddced (patch)
tree824530b0c6e98b7d059b6c1f59cda726a7815cb7 /src/librustc/traits/structural_impls.rs
parent64aac8d4c1ff1dddd31a0aed9fbf9f619b8b808e (diff)
Pretty print quantified goals and clauses
Diffstat (limited to 'src/librustc/traits/structural_impls.rs')
-rw-r--r--src/librustc/traits/structural_impls.rs149
1 files changed, 144 insertions, 5 deletions
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index e83d085971c..66d9c6711bb 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -14,9 +14,11 @@ use traits;
 use traits::project::Normalized;
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use ty::{self, Lift, TyCtxt};
+use syntax::symbol::InternedString;
 
 use std::fmt;
 use std::rc::Rc;
+use std::collections::{BTreeSet, BTreeMap};
 
 // structural impls for the structs in traits
 
@@ -479,7 +481,12 @@ impl<'tcx> fmt::Display for traits::DomainGoal<'tcx> {
             Holds(wc) => write!(fmt, "{}", wc),
             WellFormed(wf) => write!(fmt, "{}", wf),
             FromEnv(from_env) => write!(fmt, "{}", from_env),
-            Normalize(projection) => write!(fmt, "Normalize({})", projection),
+            Normalize(projection) => write!(
+                fmt,
+                "Normalize({} -> {})",
+                projection.projection_ty,
+                projection.ty
+            ),
         }
     }
 }
@@ -495,6 +502,110 @@ impl fmt::Display for traits::QuantifierKind {
     }
 }
 
+/// Collect names for regions / types bound by a quantified goal / clause.
+/// This collector does not try to do anything clever like in ppaux, it's just used
+/// for debug output in tests anyway.
+struct BoundNamesCollector {
+    // Just sort by name because `BoundRegion::BrNamed` does not have a `BoundVar` index anyway.
+    regions: BTreeSet<InternedString>,
+
+    // Sort by `BoundVar` index, so usually this should be equivalent to the order given
+    // by the list of type parameters.
+    types: BTreeMap<u32, InternedString>,
+
+    binder_index: ty::DebruijnIndex,
+}
+
+impl BoundNamesCollector {
+    fn new() -> Self {
+        BoundNamesCollector {
+            regions: BTreeSet::new(),
+            types: BTreeMap::new(),
+            binder_index: ty::INNERMOST,
+        }
+    }
+
+    fn is_empty(&self) -> bool {
+        self.regions.is_empty() && self.types.is_empty()
+    }
+
+    fn write_names(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut start = true;
+        for r in &self.regions {
+            if !start {
+                write!(fmt, ", ")?;
+            }
+            start = false;
+            write!(fmt, "{}", r)?;
+        }
+        for (_, t) in &self.types {
+            if !start {
+                write!(fmt, ", ")?;
+            }
+            start = false;
+            write!(fmt, "{}", t)?;
+        }
+        Ok(())
+    }
+}
+
+impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector {
+    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {
+        self.binder_index.shift_in(1);
+        let result = t.super_visit_with(self);
+        self.binder_index.shift_out(1);
+        result
+    }
+
+    fn visit_ty(&mut self, t: ty::Ty<'tcx>) -> bool {
+        use syntax::symbol::Symbol;
+
+        match t.sty {
+            ty::Bound(bound_ty) if bound_ty.index == self.binder_index => {
+                self.types.insert(
+                    bound_ty.var.as_u32(),
+                    match bound_ty.kind {
+                        ty::BoundTyKind::Param(name) => name,
+                        ty::BoundTyKind::Anon => Symbol::intern(
+                            &format!("?{}", bound_ty.var.as_u32())
+                        ).as_interned_str(),
+                    }
+                );
+            }
+
+            _ => (),
+        };
+
+        t.super_visit_with(self)
+    }
+
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
+        use syntax::symbol::Symbol;
+
+        match r {
+            ty::ReLateBound(index, br) if *index == self.binder_index => {
+                match br {
+                    ty::BoundRegion::BrNamed(_, name) => {
+                        self.regions.insert(*name);
+                    }
+
+                    ty::BoundRegion::BrAnon(var) => {
+                        self.regions.insert(Symbol::intern(
+                            &format!("?'{}", var)
+                        ).as_interned_str());
+                    }
+
+                    _ => (),
+                }
+            }
+
+            _ => (),
+        };
+
+        r.super_visit_with(self)
+    }
+}
+
 impl<'tcx> fmt::Display for traits::Goal<'tcx> {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         use traits::GoalKind::*;
@@ -514,8 +625,22 @@ impl<'tcx> fmt::Display for traits::Goal<'tcx> {
             Not(goal) => write!(fmt, "not {{ {} }}", goal),
             DomainGoal(goal) => write!(fmt, "{}", goal),
             Quantified(qkind, goal) => {
-                // FIXME: appropriate binder names
-                write!(fmt, "{}<> {{ {} }}", qkind, goal.skip_binder())
+                let mut collector = BoundNamesCollector::new();
+                goal.skip_binder().visit_with(&mut collector);
+
+                if !collector.is_empty() {
+                    write!(fmt, "{}<", qkind)?;
+                    collector.write_names(fmt)?;
+                    write!(fmt, "> {{ ")?;
+                }
+
+                write!(fmt, "{}", goal.skip_binder())?;
+
+                if !collector.is_empty() {
+                    write!(fmt, " }}")?;
+                }
+
+                Ok(())
             }
             CannotProve => write!(fmt, "CannotProve"),
         }
@@ -546,8 +671,22 @@ impl<'tcx> fmt::Display for traits::Clause<'tcx> {
         match self {
             Implies(clause) => write!(fmt, "{}", clause),
             ForAll(clause) => {
-                // FIXME: appropriate binder names
-                write!(fmt, "forall<> {{ {} }}", clause.skip_binder())
+                let mut collector = BoundNamesCollector::new();
+                clause.skip_binder().visit_with(&mut collector);
+
+                if !collector.is_empty() {
+                    write!(fmt, "forall<")?;
+                    collector.write_names(fmt)?;
+                    write!(fmt, "> {{ ")?;
+                }
+
+                write!(fmt, "{}", clause.skip_binder())?;
+
+                if !collector.is_empty() {
+                    write!(fmt, " }}")?;
+                }
+
+                Ok(())
             }
         }
     }