@@ -334,7 +334,12 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
334334 continue ;
335335 }
336336
337- let result = select. select ( & Obligation :: new ( dummy_cause. clone ( ) , new_env, pred) ) ;
337+ // Call infcx.resolve_type_vars_if_possible to see if we can
338+ // get rid of any inference variables.
339+ let obligation = infcx. resolve_type_vars_if_possible (
340+ & Obligation :: new ( dummy_cause. clone ( ) , new_env, pred)
341+ ) ;
342+ let result = select. select ( & obligation) ;
338343
339344 match & result {
340345 & Ok ( Some ( ref vtable) ) => {
@@ -369,7 +374,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
369374 }
370375 & Ok ( None ) => { }
371376 & Err ( SelectionError :: Unimplemented ) => {
372- if self . is_of_param ( pred. skip_binder ( ) . trait_ref . substs ) {
377+ if self . is_param_no_infer ( pred. skip_binder ( ) . trait_ref . substs ) {
373378 already_visited. remove ( & pred) ;
374379 self . add_user_pred (
375380 & mut user_computed_preds,
@@ -631,18 +636,28 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
631636 finished_map
632637 }
633638
634- pub fn is_of_param ( & self , substs : & Substs < ' _ > ) -> bool {
635- if substs. is_noop ( ) {
636- return false ;
637- }
639+ fn is_param_no_infer ( & self , substs : & Substs < ' _ > ) -> bool {
640+ return self . is_of_param ( substs. type_at ( 0 ) ) &&
641+ !substs . types ( ) . any ( |t| t . has_infer_types ( ) ) ;
642+ }
638643
639- return match substs. type_at ( 0 ) . sty {
644+ pub fn is_of_param ( & self , ty : Ty < ' _ > ) -> bool {
645+ return match ty. sty {
640646 ty:: Param ( _) => true ,
641- ty:: Projection ( p) => self . is_of_param ( p. substs ) ,
647+ ty:: Projection ( p) => self . is_of_param ( p. self_ty ( ) ) ,
642648 _ => false ,
643649 } ;
644650 }
645651
652+ fn is_self_referential_projection ( & self , p : ty:: PolyProjectionPredicate < ' _ > ) -> bool {
653+ match p. ty ( ) . skip_binder ( ) . sty {
654+ ty:: Projection ( proj) if proj == p. skip_binder ( ) . projection_ty => {
655+ true
656+ } ,
657+ _ => false
658+ }
659+ }
660+
646661 pub fn evaluate_nested_obligations <
647662 ' b ,
648663 ' c ,
@@ -661,28 +676,77 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
661676 ) -> bool {
662677 let dummy_cause = ObligationCause :: misc ( DUMMY_SP , ast:: DUMMY_NODE_ID ) ;
663678
664- for ( obligation, predicate) in nested
665- . filter ( |o| o. recursion_depth == 1 )
679+ for ( obligation, mut predicate) in nested
666680 . map ( |o| ( o. clone ( ) , o. predicate . clone ( ) ) )
667681 {
668682 let is_new_pred =
669683 fresh_preds. insert ( self . clean_pred ( select. infcx ( ) , predicate. clone ( ) ) ) ;
670684
685+ // Resolve any inference variables that we can, to help selection succeed
686+ predicate = select. infcx ( ) . resolve_type_vars_if_possible ( & predicate) ;
687+
688+ // We only add a predicate as a user-displayable bound if
689+ // it involves a generic parameter, and doesn't contain
690+ // any inference variables.
691+ //
692+ // Displaying a bound involving a concrete type (instead of a generic
693+ // parameter) would be pointless, since it's always true
694+ // (e.g. u8: Copy)
695+ // Displaying an inference variable is impossible, since they're
696+ // an internal compiler detail without a defined visual representation
697+ //
698+ // We check this by calling is_of_param on the relevant types
699+ // from the various possible predicates
671700 match & predicate {
672701 & ty:: Predicate :: Trait ( ref p) => {
673- let substs = & p. skip_binder ( ) . trait_ref . substs ;
702+ if self . is_param_no_infer ( p. skip_binder ( ) . trait_ref . substs )
703+ && !only_projections
704+ && is_new_pred {
674705
675- if self . is_of_param ( substs) && !only_projections && is_new_pred {
676706 self . add_user_pred ( computed_preds, predicate) ;
677707 }
678708 predicates. push_back ( p. clone ( ) ) ;
679709 }
680710 & ty:: Predicate :: Projection ( p) => {
681- // If the projection isn't all type vars, then
682- // we don't want to add it as a bound
683- if self . is_of_param ( p. skip_binder ( ) . projection_ty . substs ) && is_new_pred {
684- self . add_user_pred ( computed_preds, predicate) ;
685- } else {
711+ debug ! ( "evaluate_nested_obligations: examining projection predicate {:?}" ,
712+ predicate) ;
713+
714+ // As described above, we only want to display
715+ // bounds which include a generic parameter but don't include
716+ // an inference variable.
717+ // Additionally, we check if we've seen this predicate before,
718+ // to avoid rendering duplicate bounds to the user.
719+ if self . is_param_no_infer ( p. skip_binder ( ) . projection_ty . substs )
720+ && !p. ty ( ) . skip_binder ( ) . is_ty_infer ( )
721+ && is_new_pred {
722+ debug ! ( "evaluate_nested_obligations: adding projection predicate\
723+ to computed_preds: {:?}", predicate) ;
724+
725+ // Under unusual circumstances, we can end up with a self-refeential
726+ // projection predicate. For example:
727+ // <T as MyType>::Value == <T as MyType>::Value
728+ // Not only is displaying this to the user pointless,
729+ // having it in the ParamEnv will cause an issue if we try to call
730+ // poly_project_and_unify_type on the predicate, since this kind of
731+ // predicate will normally never end up in a ParamEnv.
732+ //
733+ // For these reasons, we ignore these weird predicates,
734+ // ensuring that we're able to properly synthesize an auto trait impl
735+ if self . is_self_referential_projection ( p) {
736+ debug ! ( "evaluate_nested_obligations: encountered a projection
737+ predicate equating a type with itself! Skipping" ) ;
738+
739+ } else {
740+ self . add_user_pred ( computed_preds, predicate) ;
741+ }
742+ }
743+
744+ // We can only call poly_project_and_unify_type when our predicate's
745+ // Ty contains an inference variable - otherwise, there won't be anything to
746+ // unify
747+ if p. ty ( ) . skip_binder ( ) . has_infer_types ( ) {
748+ debug ! ( "Projecting and unifying projection predicate {:?}" ,
749+ predicate) ;
686750 match poly_project_and_unify_type ( select, & obligation. with ( p. clone ( ) ) ) {
687751 Err ( e) => {
688752 debug ! (
0 commit comments