about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlexander Regueiro <alexreg@me.com>2018-11-05 02:02:43 +0000
committerAlexander Regueiro <alexreg@me.com>2018-11-07 21:57:45 +0000
commit6d3ee4170d525612161fa7f4c34315316dd422c5 (patch)
tree3289b8f1d539ce6eb8ffae6e6c960361fd6a721e
parent0e89f570d224ee08b6e32aa9ea8ea44a4e9244f3 (diff)
downloadrust-6d3ee4170d525612161fa7f4c34315316dd422c5.tar.gz
rust-6d3ee4170d525612161fa7f4c34315316dd422c5.zip
Added error for duplicate bindings of associated type.
-rw-r--r--src/librustc/traits/mod.rs7
-rw-r--r--src/librustc/ty/mod.rs46
-rw-r--r--src/librustc/ty/sty.rs18
-rw-r--r--src/librustc/ty/subst.rs14
-rw-r--r--src/librustc_typeck/astconv.rs130
-rw-r--r--src/test/run-pass/traits/trait-alias-object.rs (renamed from src/test/run-pass/traits/trait-alias-objects.rs)2
-rw-r--r--src/test/ui/error-codes/E0719-trait-alias-object.rs (renamed from src/test/ui/traits/trait-alias-associated-type-rebound.rs)6
-rw-r--r--src/test/ui/error-codes/E0719-trait-alias-object.stderr12
-rw-r--r--src/test/ui/error-codes/E0719-trait-alias.rs18
-rw-r--r--src/test/ui/error-codes/E0719-trait-alias.stderr29
-rw-r--r--src/test/ui/error-codes/E0719.rs8
-rw-r--r--src/test/ui/error-codes/E0719.stderr11
-rw-r--r--src/test/ui/traits/trait-alias-object.rs (renamed from src/test/ui/traits/trait-alias-objects.rs)0
-rw-r--r--src/test/ui/traits/trait-alias-object.stderr (renamed from src/test/ui/traits/trait-alias-objects.stderr)0
14 files changed, 184 insertions, 117 deletions
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index b7512790bfb..33b689c60a1 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -50,11 +50,8 @@ pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError
 pub use self::specialize::{OverlapError, specialization_graph, translate_substs};
 pub use self::specialize::find_associated_item;
 pub use self::engine::{TraitEngine, TraitEngineExt};
-pub use self::util::elaborate_predicates;
-pub use self::util::supertraits;
-pub use self::util::Supertraits;
-pub use self::util::supertrait_def_ids;
-pub use self::util::SupertraitDefIds;
+pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs};
+pub use self::util::{supertraits, supertrait_def_ids, Supertraits, SupertraitDefIds};
 pub use self::util::transitive_bounds;
 
 #[allow(dead_code)]
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 71d59750d6c..19fe8606a4d 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -544,14 +544,14 @@ impl<'tcx> TyS<'tcx> {
     pub fn is_primitive_ty(&self) -> bool {
         match self.sty {
             TyKind::Bool |
-                TyKind::Char |
-                TyKind::Int(_) |
-                TyKind::Uint(_) |
-                TyKind::Float(_) |
-                TyKind::Infer(InferTy::IntVar(_)) |
-                TyKind::Infer(InferTy::FloatVar(_)) |
-                TyKind::Infer(InferTy::FreshIntTy(_)) |
-                TyKind::Infer(InferTy::FreshFloatTy(_)) => true,
+            TyKind::Char |
+            TyKind::Int(_) |
+            TyKind::Uint(_) |
+            TyKind::Float(_) |
+            TyKind::Infer(InferTy::IntVar(_)) |
+            TyKind::Infer(InferTy::FloatVar(_)) |
+            TyKind::Infer(InferTy::FreshIntTy(_)) |
+            TyKind::Infer(InferTy::FreshFloatTy(_)) => true,
             TyKind::Ref(_, x, _) => x.is_primitive_ty(),
             _ => false,
         }
@@ -1042,15 +1042,15 @@ impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> {
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub enum Predicate<'tcx> {
-    /// Corresponds to `where Foo : Bar<A,B,C>`. `Foo` here would be
+    /// Corresponds to `where Foo: Bar<A,B,C>`. `Foo` here would be
     /// the `Self` type of the trait reference and `A`, `B`, and `C`
     /// would be the type parameters.
     Trait(PolyTraitPredicate<'tcx>),
 
-    /// where `'a : 'b`
+    /// where `'a: 'b`
     RegionOutlives(PolyRegionOutlivesPredicate<'tcx>),
 
-    /// where `T : 'a`
+    /// where `T: 'a`
     TypeOutlives(PolyTypeOutlivesPredicate<'tcx>),
 
     /// where `<T as TraitRef>::Name == X`, approximately.
@@ -1063,7 +1063,7 @@ pub enum Predicate<'tcx> {
     /// trait must be object-safe
     ObjectSafe(DefId),
 
-    /// No direct syntax. May be thought of as `where T : FnFoo<...>`
+    /// No direct syntax. May be thought of as `where T: FnFoo<...>`
     /// for some substitutions `...` and `T` being a closure type.
     /// Satisfied (or refuted) once we know the closure's kind.
     ClosureKind(DefId, ClosureSubsts<'tcx>, ClosureKind),
@@ -1112,11 +1112,11 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> {
         //
         // Let's start with an easy case. Consider two traits:
         //
-        //     trait Foo<'a> : Bar<'a,'a> { }
+        //     trait Foo<'a>: Bar<'a,'a> { }
         //     trait Bar<'b,'c> { }
         //
-        // Now, if we have a trait reference `for<'x> T : Foo<'x>`, then
-        // we can deduce that `for<'x> T : Bar<'x,'x>`. Basically, if we
+        // Now, if we have a trait reference `for<'x> T: Foo<'x>`, then
+        // we can deduce that `for<'x> T: Bar<'x,'x>`. Basically, if we
         // knew that `Foo<'x>` (for any 'x) then we also know that
         // `Bar<'x,'x>` (for any 'x). This more-or-less falls out from
         // normal substitution.
@@ -1129,21 +1129,21 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> {
         //
         // Another example to be careful of is this:
         //
-        //     trait Foo1<'a> : for<'b> Bar1<'a,'b> { }
+        //     trait Foo1<'a>: for<'b> Bar1<'a,'b> { }
         //     trait Bar1<'b,'c> { }
         //
-        // Here, if we have `for<'x> T : Foo1<'x>`, then what do we know?
-        // The answer is that we know `for<'x,'b> T : Bar1<'x,'b>`. The
+        // Here, if we have `for<'x> T: Foo1<'x>`, then what do we know?
+        // The answer is that we know `for<'x,'b> T: Bar1<'x,'b>`. The
         // reason is similar to the previous example: any impl of
-        // `T:Foo1<'x>` must show that `for<'b> T : Bar1<'x, 'b>`.  So
+        // `T:Foo1<'x>` must show that `for<'b> T: Bar1<'x, 'b>`.  So
         // basically we would want to collapse the bound lifetimes from
         // the input (`trait_ref`) and the supertraits.
         //
         // To achieve this in practice is fairly straightforward. Let's
         // consider the more complicated scenario:
         //
-        // - We start out with `for<'x> T : Foo1<'x>`. In this case, `'x`
-        //   has a De Bruijn index of 1. We want to produce `for<'x,'b> T : Bar1<'x,'b>`,
+        // - We start out with `for<'x> T: Foo1<'x>`. In this case, `'x`
+        //   has a De Bruijn index of 1. We want to produce `for<'x,'b> T: Bar1<'x,'b>`,
         //   where both `'x` and `'b` would have a DB index of 1.
         //   The substitution from the input trait-ref is therefore going to be
         //   `'a => 'x` (where `'x` has a DB index of 1).
@@ -1219,7 +1219,7 @@ impl<'tcx> PolyTraitPredicate<'tcx> {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
-pub struct OutlivesPredicate<A,B>(pub A, pub B); // `A : B`
+pub struct OutlivesPredicate<A,B>(pub A, pub B); // `A: B`
 pub type PolyOutlivesPredicate<A,B> = ty::Binder<OutlivesPredicate<A,B>>;
 pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>,
                                                            ty::Region<'tcx>>;
@@ -2476,7 +2476,7 @@ impl<'tcx> TyS<'tcx> {
     ///
     /// Note: prefer `ty.walk()` where possible.
     pub fn maybe_walk<F>(&'tcx self, mut f: F)
-        where F : FnMut(Ty<'tcx>) -> bool
+        where F: FnMut(Ty<'tcx>) -> bool
     {
         let mut walker = self.walk();
         while let Some(ty) = walker.next() {
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 28b58d62175..5c8549cba23 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -627,7 +627,7 @@ impl<'tcx> Binder<&'tcx List<ExistentialPredicate<'tcx>>> {
 /// A complete reference to a trait. These take numerous guises in syntax,
 /// but perhaps the most recognizable form is in a where clause:
 ///
-///     T : Foo<U>
+///     T: Foo<U>
 ///
 /// This would be represented by a trait-reference where the def-id is the
 /// def-id for the trait `Foo` and the substs define `T` as parameter 0,
@@ -637,8 +637,8 @@ impl<'tcx> Binder<&'tcx List<ExistentialPredicate<'tcx>>> {
 /// that case the `Self` parameter is absent from the substitutions.
 ///
 /// Note that a `TraitRef` introduces a level of region binding, to
-/// account for higher-ranked trait bounds like `T : for<'a> Foo<&'a
-/// U>` or higher-ranked object types.
+/// account for higher-ranked trait bounds like `T: for<'a> Foo<&'a U>`
+/// or higher-ranked object types.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct TraitRef<'tcx> {
     pub def_id: DefId,
@@ -663,7 +663,7 @@ impl<'tcx> TraitRef<'tcx> {
         self.substs.type_at(0)
     }
 
-    pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
+    pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'a {
         // Select only the "input types" from a trait-reference. For
         // now this is all the types that appear in the
         // trait-reference, but it should eventually exclude
@@ -886,16 +886,16 @@ pub struct ProjectionTy<'tcx> {
     /// The parameters of the associated item.
     pub substs: &'tcx Substs<'tcx>,
 
-    /// The DefId of the TraitItem for the associated type N.
+    /// The `DefId` of the `TraitItem` for the associated type `N`.
     ///
-    /// Note that this is not the DefId of the TraitRef containing this
-    /// associated type, which is in tcx.associated_item(item_def_id).container.
+    /// Note that this is not the `DefId` of the `TraitRef` containing this
+    /// associated type, which is in `tcx.associated_item(item_def_id).container`.
     pub item_def_id: DefId,
 }
 
 impl<'a, 'tcx> ProjectionTy<'tcx> {
-    /// Construct a ProjectionTy by searching the trait from trait_ref for the
-    /// associated item named item_name.
+    /// Construct a `ProjectionTy` by searching the trait from `trait_ref` for the
+    /// associated item named `item_name`.
     pub fn from_ref_and_name(
         tcx: TyCtxt<'_, '_, '_>, trait_ref: ty::TraitRef<'tcx>, item_name: Ident
     ) -> ProjectionTy<'tcx> {
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index c1aed36c92d..b28e7c9fb19 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -27,7 +27,7 @@ use std::marker::PhantomData;
 use std::mem;
 use std::num::NonZeroUsize;
 
-/// An entity in the Rust typesystem, which can be one of
+/// An entity in the Rust type system, which can be one of
 /// several kinds (only types and lifetimes for now).
 /// To reduce memory usage, a `Kind` is a interned pointer,
 /// with the lowest 2 bits being reserved for a tag to
@@ -171,7 +171,7 @@ impl<'tcx> Decodable for Kind<'tcx> {
 pub type Substs<'tcx> = List<Kind<'tcx>>;
 
 impl<'a, 'gcx, 'tcx> Substs<'tcx> {
-    /// Creates a Substs that maps each generic parameter to itself.
+    /// Creates a `Substs` that maps each generic parameter to itself.
     pub fn identity_for_item(tcx: TyCtxt<'a, 'gcx, 'tcx>, def_id: DefId)
                              -> &'tcx Substs<'tcx> {
         Substs::for_item(tcx, def_id, |param, _| {
@@ -179,9 +179,9 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
         })
     }
 
-    /// Creates a Substs for generic parameter definitions,
+    /// Creates a `Substs` for generic parameter definitions,
     /// by calling closures to obtain each kind.
-    /// The closures get to observe the Substs as they're
+    /// The closures get to observe the `Substs` as they're
     /// being built, which can be used to correctly
     /// substitute defaults of generic parameters.
     pub fn for_item<F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
@@ -242,7 +242,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
     }
 
     #[inline]
-    pub fn types(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
+    pub fn types(&'a self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'a {
         self.iter().filter_map(|k| {
             if let UnpackedKind::Type(ty) = k.unpack() {
                 Some(ty)
@@ -253,7 +253,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
     }
 
     #[inline]
-    pub fn regions(&'a self) -> impl DoubleEndedIterator<Item=ty::Region<'tcx>> + 'a {
+    pub fn regions(&'a self) -> impl DoubleEndedIterator<Item = ty::Region<'tcx>> + 'a {
         self.iter().filter_map(|k| {
             if let UnpackedKind::Lifetime(lt) = k.unpack() {
                 Some(lt)
@@ -332,7 +332,7 @@ impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Substs<'tcx> {}
 // `foo`. Or use `foo.subst_spanned(tcx, substs, Some(span))` when
 // there is more information available (for better errors).
 
-pub trait Subst<'tcx> : Sized {
+pub trait Subst<'tcx>: Sized {
     fn subst<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
                        substs: &[Kind<'tcx>]) -> Self {
         self.subst_spanned(tcx, substs, None)
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 3aaa5810eab..f3f42516938 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -37,7 +37,7 @@ use std::iter;
 use syntax::ast;
 use syntax::ptr::P;
 use syntax::feature_gate::{GateIssue, emit_feature_err};
-use syntax_pos::{Span, MultiSpan};
+use syntax_pos::{DUMMY_SP, Span, MultiSpan};
 
 pub trait AstConv<'gcx, 'tcx> {
     fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>;
@@ -719,6 +719,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
         speculative: bool)
         -> ty::PolyTraitRef<'tcx>
     {
+        let tcx = self.tcx();
+
         let trait_def_id = self.trait_def_id(trait_ref);
 
         debug!("instantiate_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id);
@@ -732,16 +734,74 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
                                                  trait_ref.path.segments.last().unwrap());
         let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs));
 
-        let mut dup_bindings = FxHashMap::default();
         poly_projections.extend(assoc_bindings.iter().filter_map(|binding| {
             // specify type to assert that error was already reported in Err case:
             let predicate: Result<_, ErrorReported> =
                 self.ast_type_binding_to_poly_projection_predicate(
-                    trait_ref.ref_id, poly_trait_ref, binding, speculative, &mut dup_bindings);
+                    trait_ref.ref_id, poly_trait_ref, binding, speculative);
             // okay to ignore Err because of ErrorReported (see above)
             Some((predicate.ok()?, binding.span))
         }));
 
+        // make flat_map:
+        // for tr in traits::supertraits(tcx, poly_trait_ref) {
+        //     let sup_trait_ref = tr.skip_binder();
+        //     poly_projections.extend(sup_trait_ref.substs.types().filter_map(|t| {
+        //         if let TyKind::Projection(proj) = t.sty {
+        //             Some((proj, span))
+        //         } else {
+        //             None
+        //         }
+        //     });
+        // }
+
+        // Include all projections from associated type bindings of supertraits.
+        poly_projections.extend(traits::elaborate_trait_ref(tcx, poly_trait_ref)
+            .into_iter()
+            .filter_map(|pred| {
+                if let ty::Predicate::Projection(proj) = pred {
+                    Some(proj)
+                } else {
+                    None
+                }
+            })
+            .map(|proj| (proj, DUMMY_SP))
+        );
+
+        // // Include associated type bindings from supertraits.
+        // let mut foo = poly_projections.clone();
+        // foo.extend(tcx.predicates_of(trait_def_id)
+        //     .predicates.into_iter()
+        //     .filter_map(|(pred, span)| {
+        //         debug!("pred: {:?}", pred);
+        //         if let ty::Predicate::Projection(proj) = pred {
+        //             Some((proj, span))
+        //         } else {
+        //             None
+        //         }
+        //     }));
+
+        // Check for multiple bindings of associated types.
+        let mut seen_projection_bounds = FxHashMap::default();
+        for (projection_bound, span) in poly_projections.iter().rev() {
+            let bound_def_id = projection_bound.projection_def_id();
+            let assoc_item = tcx.associated_item(bound_def_id);
+            let trait_def_id = assoc_item.container.id();
+            // let trait_ref = tcx.associated_item(proj.projection_type.item_def_id).container;
+            seen_projection_bounds.entry((assoc_item.def_id, bound_def_id))
+                .and_modify(|prev_span| {
+                    struct_span_err!(tcx.sess, *span, E0719,
+                                     "the value of the associated type `{}` (from the trait `{}`) \
+                                      is already specified",
+                                     assoc_item.ident,
+                                     tcx.item_path_str(trait_def_id))
+                        .span_label(*span, "re-bound here")
+                        .span_label(*prev_span, format!("`{}` bound here first", assoc_item.ident))
+                        .emit();
+                })
+                .or_insert(*span);
+        }
+
         debug!("instantiate_poly_trait_ref({:?}, projections={:?}) -> {:?}",
                trait_ref, poly_projections, poly_trait_ref);
         poly_trait_ref
@@ -824,8 +884,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
         ref_id: ast::NodeId,
         trait_ref: ty::PolyTraitRef<'tcx>,
         binding: &ConvertedBinding<'tcx>,
-        speculative: bool,
-        dup_bindings: &mut FxHashMap<DefId, Span>)
+        speculative: bool)
         -> Result<ty::PolyProjectionPredicate<'tcx>, ErrorReported>
     {
         let tcx = self.tcx();
@@ -879,7 +938,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
             }
         }
 
-        let supertraits = traits::supertraits(tcx, trait_ref);
         let candidate = if self.trait_defines_associated_type_named(trait_ref.def_id(),
                                                                     binding.item_name) {
             // Simple case: X is defined in the current trait.
@@ -887,11 +945,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
         } else {
             // Otherwise, we have to walk through the supertraits to find
             // those that do.
-            let candidates = supertraits.filter(|r| {
+            let candidates = traits::supertraits(tcx, trait_ref).filter(|r| {
                 self.trait_defines_associated_type_named(r.def_id(), binding.item_name)
             });
-            let candidates = candidates.collect::<Vec<_>>();
-            debug!("foo: candidates: {:?}", candidates);
             self.one_bound_for_assoc_type(candidates.into_iter(), &trait_ref.to_string(),
                                           binding.item_name, binding.span)
         }?;
@@ -908,31 +964,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
         }
         tcx.check_stability(assoc_ty.def_id, Some(ref_id), binding.span);
 
-        debug!("foo: info: {:?} {:?} {:?} {:?} {:?}", trait_ref, binding.item_name, speculative, assoc_ty.def_id, dup_bindings);
-        if !speculative {
-            dup_bindings.entry(assoc_ty.def_id)
-                .and_modify(|prev_span| {
-                    let mut err = self.tcx().struct_span_lint_node(
-                        ::rustc::lint::builtin::DUPLICATE_ASSOCIATED_TYPE_BINDINGS,
-                        ref_id,
-                        binding.span,
-                        &format!("associated type binding `{}` specified more than once",
-                                 binding.item_name)
-                    );
-                    err.span_label(binding.span, "used more than once");
-                    err.span_label(*prev_span, format!("first use of `{}`", binding.item_name));
-                    err.emit();
-                })
-                .or_insert(binding.span);
-        }
-        static mut ABC: u32 = 0;
-        unsafe {
-            ABC += 1;
-            if ABC == 3 {
-                assert!(false);
-            }
-        };
-
         Ok(candidate.map_bound(|trait_ref| {
             ty::ProjectionPredicate {
                 projection_ty: ty::ProjectionTy::from_ref_and_name(
@@ -1016,37 +1047,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
             associated_types.extend(tcx.associated_items(tr.def_id())
                 .filter(|item| item.kind == ty::AssociatedKind::Type)
                 .map(|item| item.def_id));
-
-            projection_bounds.extend(tcx.predicates_of(tr.def_id())
-                .predicates.into_iter()
-                .filter_map(|(pred, span)| {
-                    if let ty::Predicate::Projection(proj) = pred {
-                        Some((proj, span))
-                    } else {
-                        None
-                    }
-                }));
         }
 
-        let mut seen_projection_bounds = FxHashMap::default();
-        for (projection_bound, span) in projection_bounds.iter().rev() {
-            let bound_def_id = projection_bound.projection_def_id();
-            seen_projection_bounds.entry(bound_def_id)
-                .and_modify(|prev_span| {
-                    let assoc_item = tcx.associated_item(bound_def_id);
-                    let trait_def_id = assoc_item.container.id();
-                    struct_span_err!(tcx.sess, *span, E0719,
-                                     "the value of the associated type `{}` (from the trait `{}`) \
-                                      is already specified",
-                                     assoc_item.ident,
-                                     tcx.item_path_str(trait_def_id))
-                        .span_label(*span, "re-bound here")
-                        .span_label(*prev_span, format!("binding for `{}`", assoc_item.ident))
-                        .emit();
-                })
-                .or_insert(*span);
-
-            associated_types.remove(&bound_def_id);
+        for (projection_bound, _) in projection_bounds.iter().rev() {
+            associated_types.remove(&projection_bound.projection_def_id());
         }
 
         for item_def_id in associated_types {
diff --git a/src/test/run-pass/traits/trait-alias-objects.rs b/src/test/run-pass/traits/trait-alias-object.rs
index a5bb0cac251..adac28eeb12 100644
--- a/src/test/run-pass/traits/trait-alias-objects.rs
+++ b/src/test/run-pass/traits/trait-alias-object.rs
@@ -21,6 +21,6 @@ pub fn main() {
     let b = Box::new(456) as Box<dyn Foo>;
     assert!(*b == 456);
 
-    let c: &mut dyn I32Iterator<Item = u32> = &mut vec![123].into_iter();
+    let c: &mut dyn I32Iterator = &mut vec![123].into_iter();
     assert_eq!(c.next(), Some(123));
 }
diff --git a/src/test/ui/traits/trait-alias-associated-type-rebound.rs b/src/test/ui/error-codes/E0719-trait-alias-object.rs
index 32f707e192d..1e842e5b508 100644
--- a/src/test/ui/traits/trait-alias-associated-type-rebound.rs
+++ b/src/test/ui/error-codes/E0719-trait-alias-object.rs
@@ -11,7 +11,7 @@
 #![feature(trait_alias)]
 
 trait I32Iterator = Iterator<Item = i32>;
-trait I32Iterator2 = I32Iterator<Item = i32>;
-trait U32Iterator = I32Iterator2<Item = i32>;
 
-pub fn main() {}
+fn main() {
+    let _: &I32Iterator<Item = u32>; //~ ERROR E0719
+}
diff --git a/src/test/ui/error-codes/E0719-trait-alias-object.stderr b/src/test/ui/error-codes/E0719-trait-alias-object.stderr
new file mode 100644
index 00000000000..17ebf5901c4
--- /dev/null
+++ b/src/test/ui/error-codes/E0719-trait-alias-object.stderr
@@ -0,0 +1,12 @@
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/E0719-trait-alias-object.rs:16:25
+   |
+LL | trait I32Iterator = Iterator<Item = i32>;
+   |                              ---------- `Item` bound here first
+...
+LL |     let _: &I32Iterator<Item = u32>; //~ ERROR E0719
+   |                         ^^^^^^^^^^ re-bound here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0719`.
diff --git a/src/test/ui/error-codes/E0719-trait-alias.rs b/src/test/ui/error-codes/E0719-trait-alias.rs
new file mode 100644
index 00000000000..4232cafa58b
--- /dev/null
+++ b/src/test/ui/error-codes/E0719-trait-alias.rs
@@ -0,0 +1,18 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(trait_alias)]
+
+trait I32Iterator = Iterator<Item = i32>;
+trait I32Iterator2 = I32Iterator<Item = i32>; //~ ERROR E0719
+trait U32Iterator = I32Iterator2<Item = i32>; //~ ERROR E0719
+trait U32Iterator2 = U32Iterator<Item = u32>; //~ ERROR E0719
+
+fn main() {}
diff --git a/src/test/ui/error-codes/E0719-trait-alias.stderr b/src/test/ui/error-codes/E0719-trait-alias.stderr
new file mode 100644
index 00000000000..6bb1a541f4d
--- /dev/null
+++ b/src/test/ui/error-codes/E0719-trait-alias.stderr
@@ -0,0 +1,29 @@
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/E0719-trait-alias.rs:14:34
+   |
+LL | trait I32Iterator = Iterator<Item = i32>;
+   |                              ---------- `Item` bound here first
+LL | trait I32Iterator2 = I32Iterator<Item = i32>; //~ ERROR E0719
+   |                                  ^^^^^^^^^^ re-bound here
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/E0719-trait-alias.rs:15:34
+   |
+LL | trait I32Iterator = Iterator<Item = i32>;
+   |                              ---------- `Item` bound here first
+LL | trait I32Iterator2 = I32Iterator<Item = i32>; //~ ERROR E0719
+LL | trait U32Iterator = I32Iterator2<Item = i32>; //~ ERROR E0719
+   |                                  ^^^^^^^^^^ re-bound here
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/E0719-trait-alias.rs:16:34
+   |
+LL | trait I32Iterator = Iterator<Item = i32>;
+   |                              ---------- `Item` bound here first
+...
+LL | trait U32Iterator2 = U32Iterator<Item = u32>; //~ ERROR E0719
+   |                                  ^^^^^^^^^^ re-bound here
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0719`.
diff --git a/src/test/ui/error-codes/E0719.rs b/src/test/ui/error-codes/E0719.rs
index 951041124bb..2177d29110a 100644
--- a/src/test/ui/error-codes/E0719.rs
+++ b/src/test/ui/error-codes/E0719.rs
@@ -8,10 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(trait_alias)]
-
-trait I32Iterator = Iterator<Item = i32>;
-
-pub fn main() {
-    let _: &I32Iterator<Item = f32>; //~ ERROR E0719
+fn main() {
+    let _: &Iterator<Item = i32, Item = i32>; //~ ERROR E0719
 }
diff --git a/src/test/ui/error-codes/E0719.stderr b/src/test/ui/error-codes/E0719.stderr
new file mode 100644
index 00000000000..78a71b6faab
--- /dev/null
+++ b/src/test/ui/error-codes/E0719.stderr
@@ -0,0 +1,11 @@
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/E0719.rs:12:22
+   |
+LL |     let _: &Iterator<Item = i32, Item = i32>; //~ ERROR E0719
+   |                      ^^^^^^^^^^  ---------- `Item` bound here first
+   |                      |
+   |                      re-bound here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0719`.
diff --git a/src/test/ui/traits/trait-alias-objects.rs b/src/test/ui/traits/trait-alias-object.rs
index 3adcd8436d8..3adcd8436d8 100644
--- a/src/test/ui/traits/trait-alias-objects.rs
+++ b/src/test/ui/traits/trait-alias-object.rs
diff --git a/src/test/ui/traits/trait-alias-objects.stderr b/src/test/ui/traits/trait-alias-object.stderr
index 8f9681e898f..8f9681e898f 100644
--- a/src/test/ui/traits/trait-alias-objects.stderr
+++ b/src/test/ui/traits/trait-alias-object.stderr