about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/traits/mod.rs9
-rw-r--r--src/librustc/traits/util.rs195
-rw-r--r--src/librustc_passes/ast_validation.rs1
-rw-r--r--src/librustc_typeck/astconv.rs155
4 files changed, 208 insertions, 152 deletions
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index a792c439f5b..d950746f6e6 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -60,9 +60,12 @@ pub use self::specialize::specialization_graph::FutureCompatOverlapError;
 pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
 pub use self::engine::{TraitEngine, TraitEngineExt};
 pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs};
-pub use self::util::{supertraits, supertrait_def_ids, transitive_bounds,
-                     Supertraits, SupertraitDefIds};
-pub use self::util::{expand_trait_refs, TraitRefExpander};
+pub use self::util::{
+    supertraits, supertrait_def_ids, transitive_bounds, Supertraits, SupertraitDefIds,
+};
+pub use self::util::{
+    expand_trait_aliases, TraitAliasExpander, TraitAliasExpansionInfoDignosticBuilder,
+};
 
 pub use self::chalk_fulfill::{
     CanonicalGoal as ChalkCanonicalGoal,
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index 4cb3f551123..d765827e3d5 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -1,3 +1,5 @@
+use errors::DiagnosticBuilder;
+use smallvec::SmallVec;
 use syntax_pos::Span;
 
 use crate::hir;
@@ -43,7 +45,7 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
     }
 }
 
-struct PredicateSet<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+struct PredicateSet<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     set: FxHashSet<ty::Predicate<'tcx>>,
 }
@@ -53,6 +55,10 @@ impl<'a, 'gcx, 'tcx> PredicateSet<'a, 'gcx, 'tcx> {
         PredicateSet { tcx: tcx, set: Default::default() }
     }
 
+    fn contains(&mut self, pred: &ty::Predicate<'tcx>) -> bool {
+        self.set.contains(&anonymize_predicate(self.tcx, pred))
+    }
+
     fn insert(&mut self, pred: &ty::Predicate<'tcx>) -> bool {
         // We have to be careful here because we want
         //
@@ -66,6 +72,18 @@ impl<'a, 'gcx, 'tcx> PredicateSet<'a, 'gcx, 'tcx> {
         // regions before we throw things into the underlying set.
         self.set.insert(anonymize_predicate(self.tcx, pred))
     }
+
+    fn remove(&mut self, pred: &ty::Predicate<'tcx>) -> bool {
+        self.set.remove(&anonymize_predicate(self.tcx, pred))
+    }
+}
+
+impl<'a, 'gcx, 'tcx, T: AsRef<ty::Predicate<'tcx>>> Extend<T> for PredicateSet<'a, 'gcx, 'tcx> {
+    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
+        for pred in iter.into_iter() {
+            self.insert(pred.as_ref());
+        }
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -230,10 +248,16 @@ impl<'cx, 'gcx, 'tcx> Iterator for Elaborator<'cx, 'gcx, 'tcx> {
     }
 
     fn next(&mut self) -> Option<ty::Predicate<'tcx>> {
-        self.stack.pop().map(|item| {
-            self.push(&item);
-            item
-        })
+        // Extract next item from top-most stack frame, if any.
+        let next_predicate = match self.stack.pop() {
+            Some(predicate) => predicate,
+            None => {
+                // No more stack frames. Done.
+                return None;
+            }
+        };
+        self.push(&next_predicate);
+        return Some(next_predicate);
     }
 }
 
@@ -256,96 +280,140 @@ pub fn transitive_bounds<'cx, 'gcx, 'tcx>(tcx: TyCtxt<'cx, 'gcx, 'tcx>,
 }
 
 ///////////////////////////////////////////////////////////////////////////
-// `TraitRefExpander` iterator
+// `TraitAliasExpander` iterator
 ///////////////////////////////////////////////////////////////////////////
 
-/// "Trait reference expansion" is the process of expanding a sequence of trait
+/// "Trait alias expansion" is the process of expanding a sequence of trait
 /// references into another sequence by transitively following all trait
 /// aliases. e.g. If you have bounds like `Foo + Send`, a trait alias
 /// `trait Foo = Bar + Sync;`, and another trait alias
 /// `trait Bar = Read + Write`, then the bounds would expand to
 /// `Read + Write + Sync + Send`.
-pub struct TraitRefExpander<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
-    stack: Vec<TraitRefExpansionInfo<'tcx>>,
+pub struct TraitAliasExpander<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
+    stack: Vec<TraitAliasExpansionInfo<'tcx>>,
+    /// The set of predicates visited from the root directly to the current point in the
+    /// expansion tree.
     visited: PredicateSet<'a, 'gcx, 'tcx>,
 }
 
 #[derive(Debug, Clone)]
-pub struct TraitRefExpansionInfo<'tcx> {
-    pub top_level_trait_ref: ty::PolyTraitRef<'tcx>,
-    pub top_level_span: Span,
-    pub trait_ref: ty::PolyTraitRef<'tcx>,
-    pub span: Span,
+pub struct TraitAliasExpansionInfo<'tcx> {
+    pub items: SmallVec<[(ty::PolyTraitRef<'tcx>, Span); 4]>,
 }
 
-pub fn expand_trait_refs<'cx, 'gcx, 'tcx>(
+impl<'tcx> TraitAliasExpansionInfo<'tcx> {
+    fn new(trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> TraitAliasExpansionInfo<'tcx> {
+        TraitAliasExpansionInfo {
+            items: smallvec![(trait_ref, span)]
+        }
+    }
+
+    fn push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> TraitAliasExpansionInfo<'tcx> {
+        let mut items = self.items.clone();
+        items.push((trait_ref, span));
+
+        TraitAliasExpansionInfo {
+            items
+        }
+    }
+
+    pub fn trait_ref(&self) -> &ty::PolyTraitRef<'tcx> {
+        &self.top().0
+    }
+
+    pub fn top(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
+        self.items.last().unwrap()
+    }
+
+    pub fn bottom(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
+        self.items.first().unwrap()
+    }
+}
+
+pub trait TraitAliasExpansionInfoDignosticBuilder {
+    fn label_with_exp_info<'tcx>(&mut self,
+        info: &TraitAliasExpansionInfo<'tcx>,
+        top_label: &str
+    ) -> &mut Self;
+}
+
+impl<'a> TraitAliasExpansionInfoDignosticBuilder for DiagnosticBuilder<'a> {
+    fn label_with_exp_info<'tcx>(&mut self,
+        info: &TraitAliasExpansionInfo<'tcx>,
+        top_label: &str
+    ) -> &mut Self {
+        self.span_label(info.top().1, top_label);
+        if info.items.len() > 1 {
+            for (_, sp) in info.items[1..(info.items.len() - 1)].iter().rev() {
+                self.span_label(*sp, "referenced here");
+            }
+        }
+        self
+    }
+}
+
+pub fn expand_trait_aliases<'cx, 'gcx, 'tcx>(
     tcx: TyCtxt<'cx, 'gcx, 'tcx>,
     trait_refs: impl IntoIterator<Item = (ty::PolyTraitRef<'tcx>, Span)>
-) -> TraitRefExpander<'cx, 'gcx, 'tcx> {
-    let mut visited = PredicateSet::new(tcx);
-    let mut items: Vec<_> =
-        trait_refs
-            .into_iter()
-            .map(|(trait_ref, span)| TraitRefExpansionInfo {
-                top_level_trait_ref: trait_ref.clone(),
-                top_level_span: span,
-                trait_ref,
-                span,
-            })
-            .collect();
-    items.retain(|item| visited.insert(&item.trait_ref.to_predicate()));
-    TraitRefExpander { stack: items, visited }
+) -> TraitAliasExpander<'cx, 'gcx, 'tcx> {
+    let items: Vec<_> = trait_refs
+        .into_iter()
+        .map(|(trait_ref, span)| TraitAliasExpansionInfo::new(trait_ref, span))
+        .collect();
+    TraitAliasExpander { stack: items, visited: PredicateSet::new(tcx) }
 }
 
-impl<'cx, 'gcx, 'tcx> TraitRefExpander<'cx, 'gcx, 'tcx> {
-    /// If `item` refers to a trait alias, adds the components of the trait alias to the stack,
-    /// and returns `false`.
-    /// If `item` refers to an ordinary trait, simply returns `true`.
-    fn push(&mut self, item: &TraitRefExpansionInfo<'tcx>) -> bool {
+impl<'cx, 'gcx, 'tcx> TraitAliasExpander<'cx, 'gcx, 'tcx> {
+    /// If `item` is a trait alias and its predicate has not yet been visited, then expands `item`
+    /// to the definition and pushes the resulting expansion onto `self.stack`, and returns `false`.
+    /// Otherwise, immediately returns `true` if `item` is a regular trait and `false` if it is a
+    /// trait alias.
+    /// The return value indicates whether `item` should not be yielded to the user.
+    fn push(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool {
         let tcx = self.visited.tcx;
+        let trait_ref = item.trait_ref();
+        let pred = trait_ref.to_predicate();
+
+        debug!("expand_trait_aliases: trait_ref={:?}", trait_ref);
+
+        self.visited.remove(&pred);
 
-        if !tcx.is_trait_alias(item.trait_ref.def_id()) {
-            return true;
+        let is_alias = tcx.is_trait_alias(trait_ref.def_id());
+        if !is_alias || self.visited.contains(&pred) {
+            return !is_alias;
         }
 
-        // Get components of the trait alias.
-        let predicates = tcx.super_predicates_of(item.trait_ref.def_id());
+        // Get components of trait alias.
+        let predicates = tcx.super_predicates_of(trait_ref.def_id());
 
-        let mut items: Vec<_> = predicates.predicates
+        let items: Vec<_> = predicates.predicates
             .iter()
             .rev()
             .filter_map(|(pred, span)| {
-                pred.subst_supertrait(tcx, &item.trait_ref)
+                pred.subst_supertrait(tcx, &trait_ref)
                     .to_opt_poly_trait_ref()
-                    .map(|trait_ref|
-                        TraitRefExpansionInfo {
-                            trait_ref,
-                            span: *span,
-                            ..*item
-                        }
-                    )
+                    .map(|trait_ref| item.push(trait_ref, *span))
             })
             .collect();
+        debug!("expand_trait_aliases: items={:?}", items);
 
-        debug!("trait_ref_expander: trait_ref={:?} items={:?}",
-               item.trait_ref, items);
+        self.stack.extend(items);
 
-        // Only keep those items that we haven't already seen.
-        items.retain(|i| self.visited.insert(&i.trait_ref.to_predicate()));
+        // Record predicate into set of already-visited.
+        self.visited.insert(&pred);
 
-        self.stack.extend(items);
         false
     }
 }
 
-impl<'cx, 'gcx, 'tcx> Iterator for TraitRefExpander<'cx, 'gcx, 'tcx> {
-    type Item = TraitRefExpansionInfo<'tcx>;
+impl<'cx, 'gcx, 'tcx> Iterator for TraitAliasExpander<'cx, 'gcx, 'tcx> {
+    type Item = TraitAliasExpansionInfo<'tcx>;
 
     fn size_hint(&self) -> (usize, Option<usize>) {
         (self.stack.len(), None)
     }
 
-    fn next(&mut self) -> Option<TraitRefExpansionInfo<'tcx>> {
+    fn next(&mut self) -> Option<TraitAliasExpansionInfo<'tcx>> {
         while let Some(item) = self.stack.pop() {
             if self.push(&item) {
                 return Some(item);
@@ -386,8 +454,8 @@ impl<'cx, 'gcx, 'tcx> Iterator for SupertraitDefIds<'cx, 'gcx, 'tcx> {
         self.stack.extend(
             predicates.predicates
                       .iter()
-                      .filter_map(|(p, _)| p.to_opt_poly_trait_ref())
-                      .map(|t| t.def_id())
+                      .filter_map(|(pred, _)| pred.to_opt_poly_trait_ref())
+                      .map(|trait_ref| trait_ref.def_id())
                       .filter(|&super_def_id| visited.insert(super_def_id)));
         Some(def_id)
     }
@@ -413,17 +481,12 @@ impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<
     type Item = ty::PolyTraitRef<'tcx>;
 
     fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
-        loop {
-            match self.base_iterator.next() {
-                None => {
-                    return None;
-                }
-                Some(ty::Predicate::Trait(data)) => {
-                    return Some(data.to_poly_trait_ref());
-                }
-                Some(_) => {}
+        while let Some(pred) = self.base_iterator.next() {
+            if let ty::Predicate::Trait(data) = pred {
+                return Some(data.to_poly_trait_ref());
             }
         }
+        None
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 2bea1db841a..d70c8185495 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -504,7 +504,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                         any_lifetime_bounds = true;
                     }
                 }
-                self.no_questions_in_bounds(bounds, "trait object types", false);
             }
             TyKind::ImplTrait(_, ref bounds) => {
                 if self.is_impl_trait_banned {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index e1dc0b10c9f..428fa66101a 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -11,7 +11,7 @@ use crate::lint;
 use crate::middle::resolve_lifetime as rl;
 use crate::namespace::Namespace;
 use rustc::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
-use rustc::traits;
+use rustc::traits::{self, TraitAliasExpansionInfoDignosticBuilder};
 use rustc::ty::{self, DefIdTree, Ty, TyCtxt, ToPredicate, TypeFoldable};
 use rustc::ty::{GenericParamDef, GenericParamDefKind};
 use rustc::ty::subst::{Kind, Subst, InternalSubsts, SubstsRef};
@@ -965,84 +965,77 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         ty::ExistentialTraitRef::erase_self_ty(self.tcx(), trait_ref)
     }
 
-    fn expand_trait_refs(&self,
-        trait_refs: impl IntoIterator<Item = (ty::PolyTraitRef<'tcx>, Span)>
-    ) -> Vec<DefId> {
+    fn conv_object_ty_poly_trait_ref(&self,
+        span: Span,
+        trait_bounds: &[hir::PolyTraitRef],
+        lifetime: &hir::Lifetime)
+        -> Ty<'tcx>
+    {
         let tcx = self.tcx();
 
+        let mut projection_bounds = Vec::new();
+        let mut potential_assoc_types = Vec::new();
+        let dummy_self = self.tcx().types.trait_object_dummy_self;
+        let bound_trait_refs: Vec<_> = trait_bounds
+            .iter()
+            .rev()
+            .map(|trait_bound| {
+                let (trait_ref, cur_potential_assoc_types) = self.instantiate_poly_trait_ref(
+                    trait_bound,
+                    dummy_self,
+                    &mut projection_bounds
+                );
+                potential_assoc_types.extend(cur_potential_assoc_types.into_iter().flatten());
+                (trait_ref, trait_bound.span)
+            }).collect();
+
         // Expand trait aliases recursively and check that only one regular (non-auto) trait
-        // is used.
-        let expanded_traits = traits::expand_trait_refs(tcx, trait_refs);
-        let (auto_traits, regular_traits): (Vec<_>, Vec<_>) =
-            expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref.def_id()));
+        // is used and no 'maybe' bounds are used.
+        let expanded_traits = traits::expand_trait_aliases(tcx, bound_trait_refs.clone());
+        let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
+            expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
         if regular_traits.len() > 1 {
             let extra_trait = &regular_traits[1];
-            let mut err = struct_span_err!(tcx.sess, extra_trait.top_level_span, E0225,
+            let mut err = struct_span_err!(tcx.sess, extra_trait.bottom().1, E0225,
                 "only auto traits can be used as additional traits in a trait object");
-            err.span_label(extra_trait.span, "non-auto additional trait");
-            if extra_trait.span != extra_trait.top_level_span {
-                err.span_label(extra_trait.top_level_span, "expanded from this trait alias");
-            }
+            err.label_with_exp_info(extra_trait, "additional non-auto trait");
+            err.span_label(regular_traits[0].top().1, "first non-auto trait");
             err.emit();
         }
 
-        auto_traits.into_iter().map(|i| i.trait_ref.def_id()).collect()
-    }
-
-    fn conv_object_ty_poly_trait_ref(&self,
-        span: Span,
-        trait_bounds: &[hir::PolyTraitRef],
-        lifetime: &hir::Lifetime)
-        -> Ty<'tcx>
-    {
-        let tcx = self.tcx();
-
-        if trait_bounds.is_empty() {
+        if regular_traits.is_empty() && auto_traits.is_empty() {
             span_err!(tcx.sess, span, E0224,
                 "at least one non-builtin trait is required for an object type");
             return tcx.types.err;
         }
 
-        let mut projection_bounds = Vec::new();
-        let dummy_self = self.tcx().types.trait_object_dummy_self;
-        let (principal, potential_assoc_types) = self.instantiate_poly_trait_ref(
-            &trait_bounds[0],
-            dummy_self,
-            &mut projection_bounds,
-        );
-        debug!("principal: {:?}", principal);
-
-        let mut bound_trait_refs = Vec::with_capacity(trait_bounds.len());
-        for trait_bound in trait_bounds[1..].iter().rev() {
-            // Sanity check for non-principal trait bounds.
-            let (tr, _) = self.instantiate_poly_trait_ref(
-                trait_bound,
-                dummy_self,
-                &mut Vec::new()
-            );
-            bound_trait_refs.push((tr, trait_bound.span));
-        }
-        bound_trait_refs.push((principal, trait_bounds[0].span));
-
-        let mut auto_traits = self.expand_trait_refs(bound_trait_refs);
-
         // Check that there are no gross object safety violations;
         // most importantly, that the supertraits don't contain `Self`,
         // to avoid ICEs.
-        let object_safety_violations =
-            tcx.global_tcx().astconv_object_safety_violations(principal.def_id());
-        if !object_safety_violations.is_empty() {
-            tcx.report_object_safety_error(span, principal.def_id(), object_safety_violations)
-                .map(|mut err| err.emit());
-            return tcx.types.err;
+        for item in &regular_traits {
+            let object_safety_violations =
+                tcx.global_tcx().astconv_object_safety_violations(item.trait_ref().def_id());
+            if !object_safety_violations.is_empty() {
+                tcx.report_object_safety_error(
+                    span,
+                    item.trait_ref().def_id(),
+                    object_safety_violations
+                )
+                    .map(|mut err| err.emit());
+                return tcx.types.err;
+            }
         }
 
         // Use a `BTreeSet` to keep output in a more consistent order.
         let mut associated_types = BTreeSet::default();
 
-        for tr in traits::elaborate_trait_ref(tcx, principal) {
-            debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", tr);
-            match tr {
+        let regular_traits_refs = bound_trait_refs
+            .into_iter()
+            .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()))
+            .map(|(trait_ref, _)| trait_ref);
+        for trait_ref in traits::elaborate_trait_refs(tcx, regular_traits_refs) {
+            debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", trait_ref);
+            match trait_ref {
                 ty::Predicate::Trait(pred) => {
                     associated_types
                         .extend(tcx.associated_items(pred.def_id())
@@ -1102,20 +1095,18 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 if associated_types.len() == 1 { "" } else { "s" },
                 names,
             );
-            let mut suggest = false;
-            let mut potential_assoc_types_spans = vec![];
-            if let Some(potential_assoc_types) = potential_assoc_types {
+            let (suggest, potential_assoc_types_spans) =
                 if potential_assoc_types.len() == associated_types.len() {
-                    // Only suggest when the amount of missing associated types is equals to the
+                    // Only suggest when the amount of missing associated types equals the number of
                     // extra type arguments present, as that gives us a relatively high confidence
                     // that the user forgot to give the associtated type's name. The canonical
                     // example would be trying to use `Iterator<isize>` instead of
-                    // `Iterator<Item=isize>`.
-                    suggest = true;
-                    potential_assoc_types_spans = potential_assoc_types;
-                }
-            }
-            let mut suggestions = vec![];
+                    // `Iterator<Item = isize>`.
+                    (true, potential_assoc_types)
+                } else {
+                    (false, Vec::new())
+                };
+            let mut suggestions = Vec::new();
             for (i, item_def_id) in associated_types.iter().enumerate() {
                 let assoc_item = tcx.associated_item(*item_def_id);
                 err.span_label(
@@ -1151,9 +1142,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             err.emit();
         }
 
+        // De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as
+        // `dyn Trait + Send`.
+        auto_traits.sort_by_key(|i| i.trait_ref().def_id());
+        auto_traits.dedup_by_key(|i| i.trait_ref().def_id());
+        debug!("regular_traits: {:?}", regular_traits);
+        debug!("auto_traits: {:?}", auto_traits);
+
         // Erase the `dummy_self` (`trait_object_dummy_self`) used above.
-        let existential_principal = principal.map_bound(|trait_ref| {
-            self.trait_ref_to_existential(trait_ref)
+        let existential_trait_refs = regular_traits.iter().map(|i| {
+            i.trait_ref().map_bound(|trait_ref| self.trait_ref_to_existential(trait_ref))
         });
         let existential_projections = projection_bounds.iter().map(|(bound, _)| {
             bound.map_bound(|b| {
@@ -1166,21 +1164,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             })
         });
 
-        // De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as
-        // `dyn Trait + Send`.
-        auto_traits.sort();
-        auto_traits.dedup();
-        debug!("auto_traits: {:?}", auto_traits);
-
         // Calling `skip_binder` is okay because the predicates are re-bound.
-        let principal = if tcx.trait_is_auto(existential_principal.def_id()) {
-            ty::ExistentialPredicate::AutoTrait(existential_principal.def_id())
-        } else {
-            ty::ExistentialPredicate::Trait(*existential_principal.skip_binder())
-        };
+        let regular_trait_predicates = existential_trait_refs.map(
+            |trait_ref| ty::ExistentialPredicate::Trait(*trait_ref.skip_binder()));
+        let auto_trait_predicates = auto_traits.into_iter().map(
+            |trait_ref| ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id()));
         let mut v =
-            iter::once(principal)
-            .chain(auto_traits.into_iter().map(ty::ExistentialPredicate::AutoTrait))
+            regular_trait_predicates
+            .chain(auto_trait_predicates)
             .chain(existential_projections
                 .map(|x| ty::ExistentialPredicate::Projection(*x.skip_binder())))
             .collect::<SmallVec<[_; 8]>>();