about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-08-07 09:33:34 +0000
committerbors <bors@rust-lang.org>2019-08-07 09:33:34 +0000
commitd4abb08be6c3a06a14e285396f5e3ef367584f77 (patch)
treead10c5c02dbcc73bd78f0c16dfcb60c3118acaec
parent5421d94960018235654c7fb39aa1c502a3564621 (diff)
parent0410e320e28d0d2dfcc99d4d5ffcf7a6e5559b89 (diff)
downloadrust-d4abb08be6c3a06a14e285396f5e3ef367584f77.tar.gz
rust-d4abb08be6c3a06a14e285396f5e3ef367584f77.zip
Auto merge of #61919 - alexreg:fix-atb-1, r=nikomatsakis
Fix for "ambiguous associated type" issue with ATBs

Fixes #61752.

r? @nikomatsakis

CC @Centril
-rw-r--r--src/librustc/hir/mod.rs2
-rw-r--r--src/librustc/ty/mod.rs12
-rw-r--r--src/librustc/ty/sty.rs13
-rw-r--r--src/librustc_codegen_llvm/debuginfo/metadata.rs14
-rw-r--r--src/librustc_privacy/lib.rs15
-rw-r--r--src/librustc_typeck/astconv.rs95
-rw-r--r--src/librustc_typeck/check/mod.rs2
-rw-r--r--src/librustc_typeck/collect.rs49
-rw-r--r--src/librustc_typeck/lib.rs10
-rw-r--r--src/test/ui/associated-type-bounds/ambiguous-associated-type.rs12
-rw-r--r--src/test/ui/associated-type-bounds/issue-61752.rs24
11 files changed, 157 insertions, 91 deletions
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index b8d8394a02c..3d049fe4ccd 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -2234,7 +2234,7 @@ pub enum UseKind {
 #[derive(RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub struct TraitRef {
     pub path: P<Path>,
-    // Don't hash the ref_id. It is tracked via the thing it is used to access
+    // Don't hash the `ref_id`. It is tracked via the thing it is used to access.
     #[stable_hasher(ignore)]
     pub hir_ref_id: HirId,
 }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 5fec95e2a3b..a10578b0a43 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -904,7 +904,7 @@ pub struct Generics {
     pub parent_count: usize,
     pub params: Vec<GenericParamDef>,
 
-    /// Reverse map to the `index` field of each `GenericParamDef`
+    /// Reverse map to the `index` field of each `GenericParamDef`.
     #[stable_hasher(ignore)]
     pub param_def_id_to_index: FxHashMap<DefId, u32>,
 
@@ -1252,7 +1252,7 @@ impl<'tcx> TraitPredicate<'tcx> {
 
 impl<'tcx> PolyTraitPredicate<'tcx> {
     pub fn def_id(&self) -> DefId {
-        // Ok to skip binder since trait def-ID does not care about regions.
+        // Ok to skip binder since trait `DefId` does not care about regions.
         self.skip_binder().def_id()
     }
 }
@@ -1319,7 +1319,7 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
     /// Note that this is not the `DefId` of the `TraitRef` containing this
     /// associated type, which is in `tcx.associated_item(projection_def_id()).container`.
     pub fn projection_def_id(&self) -> DefId {
-        // Ok to skip binder since trait def-ID does not care about regions.
+        // Ok to skip binder since trait `DefId` does not care about regions.
         self.skip_binder().projection_ty.item_def_id
     }
 }
@@ -1646,9 +1646,9 @@ pub type PlaceholderConst = Placeholder<BoundVar>;
 /// particular point.
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
 pub struct ParamEnv<'tcx> {
-    /// Obligations that the caller must satisfy. This is basically
+    /// `Obligation`s that the caller must satisfy. This is basically
     /// the set of bounds on the in-scope type parameters, translated
-    /// into Obligations, and elaborated and normalized.
+    /// into `Obligation`s, and elaborated and normalized.
     pub caller_bounds: &'tcx List<ty::Predicate<'tcx>>,
 
     /// Typically, this is `Reveal::UserFacing`, but during codegen we
@@ -2796,7 +2796,7 @@ impl<'tcx> TyCtxt<'tcx> {
                 _ => false,
             }
         } else {
-            match self.def_kind(def_id).expect("no def for def-id") {
+            match self.def_kind(def_id).expect("no def for `DefId`") {
                 DefKind::AssocConst
                 | DefKind::Method
                 | DefKind::AssocTy => true,
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 769b6592b6f..064c374de2b 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -646,7 +646,7 @@ impl<'tcx> List<ExistentialPredicate<'tcx>> {
     ///
     /// A Rust trait object type consists (in addition to a lifetime bound)
     /// of a set of trait bounds, which are separated into any number
-    /// of auto-trait bounds, and at most 1 non-auto-trait bound. The
+    /// of auto-trait bounds, and at most one non-auto-trait bound. The
     /// non-auto-trait bound is called the "principal" of the trait
     /// object.
     ///
@@ -680,7 +680,8 @@ impl<'tcx> List<ExistentialPredicate<'tcx>> {
 
     #[inline]
     pub fn projection_bounds<'a>(&'a self) ->
-        impl Iterator<Item=ExistentialProjection<'tcx>> + 'a {
+        impl Iterator<Item = ExistentialProjection<'tcx>> + 'a
+    {
         self.iter().filter_map(|predicate| {
             match *predicate {
                 ExistentialPredicate::Projection(p) => Some(p),
@@ -690,7 +691,7 @@ impl<'tcx> List<ExistentialPredicate<'tcx>> {
     }
 
     #[inline]
-    pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item=DefId> + 'a {
+    pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item = DefId> + 'a {
         self.iter().filter_map(|predicate| {
             match *predicate {
                 ExistentialPredicate::AutoTrait(d) => Some(d),
@@ -711,17 +712,17 @@ impl<'tcx> Binder<&'tcx List<ExistentialPredicate<'tcx>>> {
 
     #[inline]
     pub fn projection_bounds<'a>(&'a self) ->
-        impl Iterator<Item=PolyExistentialProjection<'tcx>> + 'a {
+        impl Iterator<Item = PolyExistentialProjection<'tcx>> + 'a {
         self.skip_binder().projection_bounds().map(Binder::bind)
     }
 
     #[inline]
-    pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item=DefId> + 'a {
+    pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item = DefId> + 'a {
         self.skip_binder().auto_traits()
     }
 
     pub fn iter<'a>(&'a self)
-        -> impl DoubleEndedIterator<Item=Binder<ExistentialPredicate<'tcx>>> + 'tcx {
+        -> impl DoubleEndedIterator<Item = Binder<ExistentialPredicate<'tcx>>> + 'tcx {
         self.skip_binder().iter().cloned().map(Binder::bind)
     }
 }
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index 3b7aee84862..51e789b1788 100644
--- a/src/librustc_codegen_llvm/debuginfo/metadata.rs
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -450,11 +450,11 @@ fn subroutine_type_metadata(
         false);
 }
 
-// FIXME(1563) This is all a bit of a hack because 'trait pointer' is an ill-
-// defined concept. For the case of an actual trait pointer (i.e., Box<Trait>,
-// &Trait), trait_object_type should be the whole thing (e.g, Box<Trait>) and
-// trait_type should be the actual trait (e.g., Trait). Where the trait is part
-// of a DST struct, there is no trait_object_type and the results of this
+// FIXME(1563): This is all a bit of a hack because 'trait pointer' is an ill-
+// defined concept. For the case of an actual trait pointer (i.e., `Box<Trait>`,
+// `&Trait`), `trait_object_type` should be the whole thing (e.g, `Box<Trait>`) and
+// `trait_type` should be the actual trait (e.g., `Trait`). Where the trait is part
+// of a DST struct, there is no `trait_object_type` and the results of this
 // function will be a little bit weird.
 fn trait_pointer_metadata(
     cx: &CodegenCx<'ll, 'tcx>,
@@ -464,13 +464,13 @@ fn trait_pointer_metadata(
 ) -> &'ll DIType {
     // The implementation provided here is a stub. It makes sure that the trait
     // type is assigned the correct name, size, namespace, and source location.
-    // But it does not describe the trait's methods.
+    // However, it does not describe the trait's methods.
 
     let containing_scope = match trait_type.sty {
         ty::Dynamic(ref data, ..) =>
             data.principal_def_id().map(|did| get_namespace_for_item(cx, did)),
         _ => {
-            bug!("debuginfo: Unexpected trait-object type in \
+            bug!("debuginfo: unexpected trait-object type in \
                   trait_pointer_metadata(): {:?}",
                  trait_type);
         }
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 4800bb9365c..4040c0166d8 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -1050,14 +1050,19 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
         if !self.in_body {
             // Avoid calling `hir_trait_to_predicates` in bodies, it will ICE.
             // The traits' privacy in bodies is already checked as a part of trait object types.
-            let (principal, bounds) = rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref);
-            if self.visit_trait(*principal.skip_binder()) {
-                return;
+            let bounds = rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref);
+
+            for (trait_predicate, _) in bounds.trait_bounds {
+                if self.visit_trait(*trait_predicate.skip_binder()) {
+                    return;
+                }
             }
+
             for (poly_predicate, _) in bounds.projection_bounds {
                 let tcx = self.tcx;
-                if self.visit(poly_predicate.skip_binder().ty) ||
-                   self.visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx)) {
+                if self.visit(poly_predicate.skip_binder().ty)
+                    || self.visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx))
+                {
                     return;
                 }
             }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index e8e0dd8425b..25e9355161b 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -42,8 +42,17 @@ pub struct PathSeg(pub DefId, pub usize);
 pub trait AstConv<'tcx> {
     fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
 
-    /// Returns the set of bounds in scope for the type parameter with
-    /// the given id.
+    /// Returns predicates in scope of the form `X: Foo`, where `X` is
+    /// a type parameter `X` with the given id `def_id`. This is a
+    /// subset of the full set of predicates.
+    ///
+    /// This is used for one specific purpose: resolving "short-hand"
+    /// associated type references like `T::Item`. In principle, we
+    /// would do that by first getting the full set of predicates in
+    /// scope and then filtering down to find those that apply to `T`,
+    /// but this can lead to cycle errors. The problem is that we have
+    /// to do this resolution *in order to create the predicates in
+    /// the first place*. Hence, we have this "special pass".
     fn get_type_parameter_bounds(&self, span: Span, def_id: DefId)
                                  -> &'tcx ty::GenericPredicates<'tcx>;
 
@@ -775,11 +784,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     /// The given trait-ref must actually be a trait.
     pub(super) fn instantiate_poly_trait_ref_inner(&self,
         trait_ref: &hir::TraitRef,
+        span: Span,
         self_ty: Ty<'tcx>,
         bounds: &mut Bounds<'tcx>,
         speculative: bool,
-    ) -> (ty::PolyTraitRef<'tcx>, Option<Vec<Span>>)
-    {
+    ) -> Option<Vec<Span>> {
         let trait_def_id = trait_ref.trait_def_id();
 
         debug!("instantiate_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id);
@@ -794,6 +803,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         );
         let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs));
 
+        bounds.trait_bounds.push((poly_trait_ref, span));
+
         let mut dup_bindings = FxHashMap::default();
         for binding in &assoc_bindings {
             // Specify type to assert that error was already reported in `Err` case.
@@ -804,14 +815,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     binding,
                     bounds,
                     speculative,
-                    &mut dup_bindings
+                    &mut dup_bindings,
                 );
             // Okay to ignore `Err` because of `ErrorReported` (see above).
         }
 
         debug!("instantiate_poly_trait_ref({:?}, bounds={:?}) -> {:?}",
                trait_ref, bounds, poly_trait_ref);
-        (poly_trait_ref, potential_assoc_types)
+        potential_assoc_types
     }
 
     /// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct
@@ -836,10 +847,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     pub fn instantiate_poly_trait_ref(&self,
         poly_trait_ref: &hir::PolyTraitRef,
         self_ty: Ty<'tcx>,
-        bounds: &mut Bounds<'tcx>
-    ) -> (ty::PolyTraitRef<'tcx>, Option<Vec<Span>>)
-    {
-        self.instantiate_poly_trait_ref_inner(&poly_trait_ref.trait_ref, self_ty, bounds, false)
+        bounds: &mut Bounds<'tcx>,
+    ) -> Option<Vec<Span>> {
+        self.instantiate_poly_trait_ref_inner(
+            &poly_trait_ref.trait_ref,
+            poly_trait_ref.span,
+            self_ty,
+            bounds,
+            false,
+        )
     }
 
     fn ast_path_to_mono_trait_ref(&self,
@@ -983,12 +999,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         }
 
         for bound in trait_bounds {
-            let (poly_trait_ref, _) = self.instantiate_poly_trait_ref(
+            let _ = self.instantiate_poly_trait_ref(
                 bound,
                 param_ty,
                 bounds,
             );
-            bounds.trait_bounds.push((poly_trait_ref, bound.span))
         }
 
         bounds.region_bounds.extend(region_bounds
@@ -1172,11 +1187,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
                 // parameter to have a skipped binder.
                 let param_ty = tcx.mk_projection(assoc_ty.def_id, candidate.skip_binder().substs);
-                self.add_bounds(
-                    param_ty,
-                    ast_bounds,
-                    bounds,
-                );
+                self.add_bounds(param_ty, ast_bounds, bounds);
             }
         }
         Ok(())
@@ -1216,25 +1227,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let mut bounds = Bounds::default();
         let mut potential_assoc_types = Vec::new();
         let dummy_self = self.tcx().types.trait_object_dummy_self;
-        // FIXME: we want to avoid collecting into a `Vec` here, but simply cloning the iterator is
-        // not straightforward due to the borrow checker.
-        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 bounds,
-                );
-                potential_assoc_types.extend(cur_potential_assoc_types.into_iter().flatten());
-                (trait_ref, trait_bound.span)
-            })
-            .collect();
+        for trait_bound in trait_bounds.iter().rev() {
+            let cur_potential_assoc_types = self.instantiate_poly_trait_ref(
+                trait_bound,
+                dummy_self,
+                &mut bounds,
+            );
+            potential_assoc_types.extend(cur_potential_assoc_types.into_iter().flatten());
+        }
 
         // Expand trait aliases recursively and check that only one regular (non-auto) trait
         // is used and no 'maybe' bounds are used.
-        let expanded_traits = traits::expand_trait_aliases(tcx, bound_trait_refs.iter().cloned());
+        let expanded_traits =
+            traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().cloned());
         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 {
@@ -1276,7 +1281,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         // Use a `BTreeSet` to keep output in a more consistent order.
         let mut associated_types = BTreeSet::default();
 
-        let regular_traits_refs = bound_trait_refs
+        let regular_traits_refs = bounds.trait_bounds
             .into_iter()
             .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()))
             .map(|(trait_ref, _)| trait_ref);
@@ -1491,7 +1496,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     {
         let tcx = self.tcx();
 
+        debug!(
+            "find_bound_for_assoc_item(ty_param_def_id={:?}, assoc_name={:?}, span={:?})",
+            ty_param_def_id,
+            assoc_name,
+            span,
+        );
+
         let predicates = &self.get_type_parameter_bounds(span, ty_param_def_id).predicates;
+
+        debug!("find_bound_for_assoc_item: predicates={:#?}", predicates);
+
         let bounds = predicates.iter().filter_map(|(p, _)| p.to_opt_poly_trait_ref());
 
         // Check that there is exactly one way to find an associated type with the
@@ -1515,7 +1530,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                                    assoc_name: ast::Ident,
                                    span: Span)
         -> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
-        where I: Iterator<Item=ty::PolyTraitRef<'tcx>>
+        where I: Iterator<Item = ty::PolyTraitRef<'tcx>>
     {
         let bound = match bounds.next() {
             Some(bound) => bound,
@@ -1524,13 +1539,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                                  "associated type `{}` not found for `{}`",
                                  assoc_name,
                                  ty_param_name)
-                  .span_label(span, format!("associated type `{}` not found", assoc_name))
-                  .emit();
+                    .span_label(span, format!("associated type `{}` not found", assoc_name))
+                    .emit();
                 return Err(ErrorReported);
             }
         };
 
+        debug!("one_bound_for_assoc_type: bound = {:?}", bound);
+
         if let Some(bound2) = bounds.next() {
+            debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2);
+
             let bounds = iter::once(bound).chain(iter::once(bound2)).chain(bounds);
             let mut err = struct_span_err!(
                 self.tcx().sess, span, E0221,
@@ -1544,7 +1563,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     item.kind == ty::AssocKind::Type &&
                         self.tcx().hygienic_eq(assoc_name, item.ident, bound.def_id())
                 })
-                .and_then(|item| self.tcx().hir().span_if_local(item.def_id));
+                    .and_then(|item| self.tcx().hir().span_if_local(item.def_id));
 
                 if let Some(span) = bound_span {
                     err.span_label(span, format!("ambiguous `{}` from `{}`",
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index e8ff83e7d2b..08033b46b80 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2030,7 +2030,7 @@ fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span, qpath: &
 impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
     fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
         self.tcx
-        }
+    }
 
     fn get_type_parameter_bounds(&self, _: Span, def_id: DefId)
                                  -> &'tcx ty::GenericPredicates<'tcx>
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index a14040fe59a..0f0568907c6 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -49,8 +49,6 @@ use rustc::hir::{self, CodegenFnAttrFlags, CodegenFnAttrs, Unsafety};
 
 use errors::{Applicability, DiagnosticId};
 
-use std::iter;
-
 struct OnlySelfBounds(bool);
 
 ///////////////////////////////////////////////////////////////////////////
@@ -226,7 +224,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
         if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
             self.tcx().mk_projection(item_def_id, trait_ref.substs)
         } else {
-            // no late-bound regions, we can just ignore the binder
+            // There are no late-bound regions; we can just ignore the binder.
             span_err!(
                 self.tcx().sess,
                 span,
@@ -239,20 +237,21 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
     }
 
     fn normalize_ty(&self, _span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
-        // types in item signatures are not normalized, to avoid undue
-        // dependencies.
+        // Types in item signatures are not normalized to avoid undue dependencies.
         ty
     }
 
     fn set_tainted_by_errors(&self) {
-        // no obvious place to track this, so just let it go
+        // There's no obvious place to track this, so just let it go.
     }
 
     fn record_ty(&self, _hir_id: hir::HirId, _ty: Ty<'tcx>, _span: Span) {
-        // no place to record types from signatures?
+        // There's no place to record types from signatures?
     }
 }
 
+/// Returns the predicates defined on `item_def_id` of the form
+/// `X: Foo` where `X` is the type parameter `def_id`.
 fn type_param_predicates(
     tcx: TyCtxt<'_>,
     (item_def_id, def_id): (DefId, DefId),
@@ -260,8 +259,8 @@ fn type_param_predicates(
     use rustc::hir::*;
 
     // In the AST, bounds can derive from two places. Either
-    // written inline like `<T : Foo>` or in a where clause like
-    // `where T : Foo`.
+    // written inline like `<T: Foo>` or in a where-clause like
+    // `where T: Foo`.
 
     let param_id = tcx.hir().as_local_hir_id(def_id).unwrap();
     let param_owner = tcx.hir().ty_param_owner(param_id);
@@ -325,16 +324,23 @@ fn type_param_predicates(
     let icx = ItemCtxt::new(tcx, item_def_id);
     let mut result = (*result).clone();
     result.predicates.extend(extend.into_iter());
-    result.predicates
-          .extend(icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty,
-                  OnlySelfBounds(true)));
+    result.predicates.extend(
+        icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, OnlySelfBounds(true))
+            .into_iter()
+            .filter(|(predicate, _)| {
+                match predicate {
+                    ty::Predicate::Trait(ref data) => data.skip_binder().self_ty().is_param(index),
+                    _ => false,
+                }
+            })
+    );
     tcx.arena.alloc(result)
 }
 
 impl ItemCtxt<'tcx> {
     /// Finds bounds from `hir::Generics`. This requires scanning through the
     /// AST. We do this to avoid having to convert *all* the bounds, which
-    /// would create artificial cycles. Instead we can only convert the
+    /// would create artificial cycles. Instead, we can only convert the
     /// bounds for a type parameter `X` if `X::Foo` is used.
     fn type_parameter_bounds_in_generics(
         &self,
@@ -2192,15 +2198,12 @@ fn explicit_predicates_of(
                     match bound {
                         &hir::GenericBound::Trait(ref poly_trait_ref, _) => {
                             let mut bounds = Bounds::default();
-
-                            let (trait_ref, _) = AstConv::instantiate_poly_trait_ref(
+                            let _ = AstConv::instantiate_poly_trait_ref(
                                 &icx,
                                 poly_trait_ref,
                                 ty,
                                 &mut bounds,
                             );
-
-                            predicates.push((trait_ref.to_predicate(), poly_trait_ref.span));
                             predicates.extend(bounds.predicates(tcx, ty));
                         }
 
@@ -2292,7 +2295,7 @@ fn explicit_predicates_of(
 /// Converts a specific `GenericBound` from the AST into a set of
 /// predicates that apply to the self type. A vector is returned
 /// because this can be anywhere from zero predicates (`T: ?Sized` adds no
-/// predicates) to one (`T: Foo`) to many (`T: Bar<X=i32>` adds `T: Bar`
+/// predicates) to one (`T: Foo`) to many (`T: Bar<X = i32>` adds `T: Bar`
 /// and `<T as Bar>::X == i32`).
 fn predicates_from_bound<'tcx>(
     astconv: &dyn AstConv<'tcx>,
@@ -2302,10 +2305,12 @@ fn predicates_from_bound<'tcx>(
     match *bound {
         hir::GenericBound::Trait(ref tr, hir::TraitBoundModifier::None) => {
             let mut bounds = Bounds::default();
-            let (pred, _) = astconv.instantiate_poly_trait_ref(tr, param_ty, &mut bounds);
-            iter::once((pred.to_predicate(), tr.span))
-                .chain(bounds.predicates(astconv.tcx(), param_ty))
-                .collect()
+            let _ = astconv.instantiate_poly_trait_ref(
+                tr,
+                param_ty,
+                &mut bounds,
+            );
+            bounds.predicates(astconv.tcx(), param_ty)
         }
         hir::GenericBound::Outlives(ref lifetime) => {
             let region = astconv.ast_region_to_region(lifetime, None);
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index a34b137aca9..9d9a9d9b559 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -108,7 +108,7 @@ use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::query::Providers;
 use rustc::util;
-use syntax_pos::Span;
+use syntax_pos::{DUMMY_SP, Span};
 use util::common::time;
 
 use std::iter;
@@ -375,7 +375,7 @@ pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty) -> Ty<'tcx> {
 pub fn hir_trait_to_predicates<'tcx>(
     tcx: TyCtxt<'tcx>,
     hir_trait: &hir::TraitRef,
-) -> (ty::PolyTraitRef<'tcx>, Bounds<'tcx>) {
+) -> Bounds<'tcx> {
     // In case there are any projections, etc., find the "environment"
     // def-ID that will be used to determine the traits/predicates in
     // scope.  This is derived from the enclosing item-like thing.
@@ -383,11 +383,11 @@ pub fn hir_trait_to_predicates<'tcx>(
     let env_def_id = tcx.hir().local_def_id(env_hir_id);
     let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id);
     let mut bounds = Bounds::default();
-    let (principal, _) = AstConv::instantiate_poly_trait_ref_inner(
-        &item_cx, hir_trait, tcx.types.err, &mut bounds, true
+    let _ = AstConv::instantiate_poly_trait_ref_inner(
+        &item_cx, hir_trait, DUMMY_SP, tcx.types.err, &mut bounds, true
     );
 
-    (principal, bounds)
+    bounds
 }
 
 __build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }
diff --git a/src/test/ui/associated-type-bounds/ambiguous-associated-type.rs b/src/test/ui/associated-type-bounds/ambiguous-associated-type.rs
new file mode 100644
index 00000000000..9c47a003dfd
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/ambiguous-associated-type.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+#![feature(associated_type_bounds)]
+
+pub struct Flatten<I>
+where
+    I: Iterator<Item: IntoIterator>,
+{
+    inner: <I::Item as IntoIterator>::IntoIter,
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/issue-61752.rs b/src/test/ui/associated-type-bounds/issue-61752.rs
new file mode 100644
index 00000000000..f38ec640e17
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/issue-61752.rs
@@ -0,0 +1,24 @@
+// check-pass
+
+#![feature(associated_type_bounds)]
+
+trait Foo {
+    type Bar;
+}
+
+impl Foo for () {
+    type Bar = ();
+}
+
+fn a<F: Foo>() where F::Bar: Copy {}
+
+fn b<F: Foo>() where <F as Foo>::Bar: Copy {}
+
+// This used to complain about ambiguous associated types.
+fn c<F: Foo<Bar: Foo>>() where F::Bar: Copy {}
+
+fn main() {
+    a::<()>();
+    b::<()>();
+    c::<()>();
+}