@@ -14,9 +14,11 @@ use traits;
1414use traits:: project:: Normalized ;
1515use ty:: fold:: { TypeFoldable , TypeFolder , TypeVisitor } ;
1616use ty:: { self , Lift , TyCtxt } ;
17+ use syntax:: symbol:: InternedString ;
1718
1819use std:: fmt;
1920use 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+
498609impl < ' 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 }
0 commit comments