about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-12-26 03:42:59 +0000
committerbors <bors@rust-lang.org>2019-12-26 03:42:59 +0000
commitc0b16b4e6aa94cd83fd2c029356ba537dc4502c6 (patch)
treea96f943e2f0d94458b4e3d1e2db6d6ae48c86e10 /src
parentb13d65ab9274323de72539556f2c5f7eef29f4a1 (diff)
parent621d7e959b24ea8640584f0ced13ec016be35d16 (diff)
downloadrust-c0b16b4e6aa94cd83fd2c029356ba537dc4502c6.tar.gz
rust-c0b16b4e6aa94cd83fd2c029356ba537dc4502c6.zip
Auto merge of #67268 - estebank:assoc-types, r=oli-obk
Tweak errors for missing associated types and type parameters

* On `dyn Trait` missing associated types, provide a structured suggestion for them
* On missing type parameters, provide structured suggestion for them
* Point at trait definition when missing required type parameter
* Tweak output of E0658
* Tweak wording of E0719
* Account for `Trait1 + Trait2` case

Fix #66380, fix #60595. CC #63711.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_error_codes/error_codes.rs3
-rw-r--r--src/librustc_error_codes/error_codes/E0222.md51
-rw-r--r--src/librustc_passes/ast_validation.rs1
-rw-r--r--src/librustc_typeck/astconv.rs637
-rw-r--r--src/test/compile-fail/issue-23595-1.rs4
-rw-r--r--src/test/ui/associated-type-bounds/duplicate.rs138
-rw-r--r--src/test/ui/associated-type-bounds/duplicate.stderr138
-rw-r--r--src/test/ui/associated-type/associated-type-projection-ambig-between-bound-and-where-clause.stderr54
-rw-r--r--src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.rs13
-rw-r--r--src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr69
-rw-r--r--src/test/ui/associated-types/associated-types-incomplete-object.rs6
-rw-r--r--src/test/ui/associated-types/associated-types-incomplete-object.stderr21
-rw-r--r--src/test/ui/associated-types/associated-types-path-1.stderr13
-rw-r--r--src/test/ui/associated-types/missing-associated-types.rs27
-rw-r--r--src/test/ui/associated-types/missing-associated-types.stderr129
-rw-r--r--src/test/ui/error-codes/E0191.stderr6
-rw-r--r--src/test/ui/error-codes/E0220.stderr8
-rw-r--r--src/test/ui/error-codes/E0221.stderr20
-rw-r--r--src/test/ui/error-codes/E0393.stderr5
-rw-r--r--src/test/ui/error-codes/E0719.stderr4
-rw-r--r--src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr12
-rw-r--r--src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr4
-rw-r--r--src/test/ui/issues/issue-19482.rs2
-rw-r--r--src/test/ui/issues/issue-19482.stderr6
-rw-r--r--src/test/ui/issues/issue-21950.rs15
-rw-r--r--src/test/ui/issues/issue-21950.stderr22
-rw-r--r--src/test/ui/issues/issue-22370.stderr5
-rw-r--r--src/test/ui/issues/issue-22434.rs2
-rw-r--r--src/test/ui/issues/issue-22434.stderr6
-rw-r--r--src/test/ui/issues/issue-22560.rs19
-rw-r--r--src/test/ui/issues/issue-22560.stderr68
-rw-r--r--src/test/ui/issues/issue-23024.rs2
-rw-r--r--src/test/ui/issues/issue-23024.stderr10
-rw-r--r--src/test/ui/issues/issue-23595-2.stderr4
-rw-r--r--src/test/ui/issues/issue-28344.stderr8
-rw-r--r--src/test/ui/issues/issue-39211.stderr4
-rw-r--r--src/test/ui/issues/issue-59029-1.stderr4
-rw-r--r--src/test/ui/span/type-binding.stderr2
-rw-r--r--src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr11
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr6
-rw-r--r--src/test/ui/traits/trait-object-with-self-in-projection-output-bad.rs4
-rw-r--r--src/test/ui/traits/trait-object-with-self-in-projection-output-bad.stderr12
-rw-r--r--src/test/ui/type-alias-impl-trait/not_well_formed.stderr4
-rw-r--r--src/test/ui/type/type-parameter-defaults-referencing-Self.stderr9
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closure-feature-gate.stderr2
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr8
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closure-sugar-region.stderr2
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr2
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr4
-rw-r--r--src/test/ui/unspecified-self-in-trait-ref.stderr9
-rw-r--r--src/test/ui/where-clauses/where-equality-constraints.stderr4
51 files changed, 1160 insertions, 459 deletions
diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs
index fbcc976bd49..18d58d9d19e 100644
--- a/src/librustc_error_codes/error_codes.rs
+++ b/src/librustc_error_codes/error_codes.rs
@@ -116,6 +116,7 @@ E0211: include_str!("./error_codes/E0211.md"),
 E0214: include_str!("./error_codes/E0214.md"),
 E0220: include_str!("./error_codes/E0220.md"),
 E0221: include_str!("./error_codes/E0221.md"),
+E0222: include_str!("./error_codes/E0222.md"),
 E0223: include_str!("./error_codes/E0223.md"),
 E0225: include_str!("./error_codes/E0225.md"),
 E0229: include_str!("./error_codes/E0229.md"),
@@ -457,8 +458,6 @@ E0745: include_str!("./error_codes/E0745.md"),
 //  E0217, // ambiguous associated type, defined in multiple supertraits
 //  E0218, // no associated type defined
 //  E0219, // associated type defined in higher-ranked supertrait
-//  E0222, // Error code E0045 (variadic function must have C or cdecl calling
-           // convention) duplicate
     E0224, // at least one non-builtin train is required for an object type
     E0226, // only a single explicit lifetime bound is permitted
     E0227, // ambiguous lifetime bound, explicit lifetime bound required
diff --git a/src/librustc_error_codes/error_codes/E0222.md b/src/librustc_error_codes/error_codes/E0222.md
new file mode 100644
index 00000000000..66b6c4d712b
--- /dev/null
+++ b/src/librustc_error_codes/error_codes/E0222.md
@@ -0,0 +1,51 @@
+An attempt was made to constrain an associated type.
+For example:
+
+```compile_fail,E0222
+pub trait Vehicle {
+    type Color;
+}
+
+pub trait Box {
+    type Color;
+}
+
+pub trait BoxCar : Box + Vehicle {}
+
+fn dent_object<COLOR>(c: dyn BoxCar<Color=COLOR>) {} // Invalid constraint
+```
+
+In this example, `BoxCar` has two super-traits: `Vehicle` and `Box`. Both of
+these traits define an associated type `Color`. `BoxCar` inherits two types
+with that name from both super-traits. Because of this, we need to use the
+fully qualified path syntax to refer to the appropriate `Color` associated
+type, either `<BoxCar as Vehicle>::Color` or `<BoxCar as Box>::Color`, but this
+syntax is not allowed to be used in a function signature.
+
+In order to encode this kind of constraint, a `where` clause and a new type
+parameter are needed:
+
+```
+pub trait Vehicle {
+    type Color;
+}
+
+pub trait Box {
+    type Color;
+}
+
+pub trait BoxCar : Box + Vehicle {}
+
+// Introduce a new `CAR` type parameter
+fn foo<CAR, COLOR>(
+    c: CAR,
+) where
+    // Bind the type parameter `CAR` to the trait `BoxCar`
+    CAR: BoxCar,
+    // Further restrict `<BoxCar as Vehicle>::Color` to be the same as the
+    // type parameter `COLOR`
+    CAR: Vehicle<Color = COLOR>,
+    // We can also simultaneously restrict the other trait's associated type
+    CAR: Box<Color = COLOR>
+{}
+```
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index c3a5175abac..d89db403b15 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -804,6 +804,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                         predicate.span,
                         "equality constraints are not yet supported in `where` clauses",
                     )
+                    .span_label(predicate.span, "not supported")
                     .note(
                         "for more information, see https://github.com/rust-lang/rust/issues/20041",
                     )
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 5f0fbcc3b0f..d28af783c0b 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -4,9 +4,9 @@
 
 use crate::hir::def::{CtorOf, DefKind, Res};
 use crate::hir::def_id::DefId;
+use crate::hir::print;
 use crate::hir::ptr::P;
-use crate::hir::HirVec;
-use crate::hir::{self, ExprKind, GenericArg, GenericArgs};
+use crate::hir::{self, ExprKind, GenericArg, GenericArgs, HirVec};
 use crate::lint;
 use crate::middle::lang_items::SizedTraitLangItem;
 use crate::middle::resolve_lifetime as rl;
@@ -473,7 +473,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         self_ty: Option<Ty<'tcx>>,
         args_for_def_id: impl Fn(DefId) -> (Option<&'b GenericArgs>, bool),
         provided_kind: impl Fn(&GenericParamDef, &GenericArg) -> subst::GenericArg<'tcx>,
-        inferred_kind: impl Fn(
+        mut inferred_kind: impl FnMut(
             Option<&[subst::GenericArg<'tcx>]>,
             &GenericParamDef,
             bool,
@@ -674,6 +674,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             false
         };
 
+        let mut missing_type_params = vec![];
         let substs = Self::create_substs_for_generic_args(
             tcx,
             def_id,
@@ -709,19 +710,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                             // defaults. This will lead to an ICE if we are not
                             // careful!
                             if default_needs_object_self(param) {
-                                struct_span_err!(
-                                    tcx.sess,
-                                    span,
-                                    E0393,
-                                    "the type parameter `{}` must be explicitly specified",
-                                    param.name
-                                )
-                                .span_label(span, format!("missing reference to `{}`", param.name))
-                                .note(&format!(
-                                    "because of the default `Self` reference, type parameters \
-                                         must be specified on object types"
-                                ))
-                                .emit();
+                                missing_type_params.push(param.name.to_string());
                                 tcx.types.err.into()
                             } else {
                                 // This is a default type parameter.
@@ -760,6 +749,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             },
         );
 
+        self.complain_about_missing_type_params(
+            missing_type_params,
+            def_id,
+            span,
+            generic_args.args.is_empty(),
+        );
+
         // Convert associated-type bindings or constraints into a separate vector.
         // Example: Given this:
         //
@@ -818,6 +814,79 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         }
     }
 
+    /// On missing type parameters, emit an E0393 error and provide a structured suggestion using
+    /// the type parameter's name as a placeholder.
+    fn complain_about_missing_type_params(
+        &self,
+        missing_type_params: Vec<String>,
+        def_id: DefId,
+        span: Span,
+        empty_generic_args: bool,
+    ) {
+        if missing_type_params.is_empty() {
+            return;
+        }
+        let display =
+            missing_type_params.iter().map(|n| format!("`{}`", n)).collect::<Vec<_>>().join(", ");
+        let mut err = struct_span_err!(
+            self.tcx().sess,
+            span,
+            E0393,
+            "the type parameter{} {} must be explicitly specified",
+            pluralize!(missing_type_params.len()),
+            display,
+        );
+        err.span_label(
+            self.tcx().def_span(def_id),
+            &format!(
+                "type parameter{} {} must be specified for this",
+                pluralize!(missing_type_params.len()),
+                display,
+            ),
+        );
+        let mut suggested = false;
+        if let (Ok(snippet), true) = (
+            self.tcx().sess.source_map().span_to_snippet(span),
+            // Don't suggest setting the type params if there are some already: the order is
+            // tricky to get right and the user will already know what the syntax is.
+            empty_generic_args,
+        ) {
+            if snippet.ends_with('>') {
+                // The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion
+                // we would have to preserve the right order. For now, as clearly the user is
+                // aware of the syntax, we do nothing.
+            } else {
+                // The user wrote `Iterator`, so we don't have a type we can suggest, but at
+                // least we can clue them to the correct syntax `Iterator<Type>`.
+                err.span_suggestion(
+                    span,
+                    &format!(
+                        "set the type parameter{plural} to the desired type{plural}",
+                        plural = pluralize!(missing_type_params.len()),
+                    ),
+                    format!("{}<{}>", snippet, missing_type_params.join(", ")),
+                    Applicability::HasPlaceholders,
+                );
+                suggested = true;
+            }
+        }
+        if !suggested {
+            err.span_label(
+                span,
+                format!(
+                    "missing reference{} to {}",
+                    pluralize!(missing_type_params.len()),
+                    display,
+                ),
+            );
+        }
+        err.note(&format!(
+            "because of the default `Self` reference, type parameters must be \
+                            specified on object types"
+        ));
+        err.emit();
+    }
+
     /// Instantiates the path for the given trait reference, assuming that it's
     /// bound to a valid trait type. Returns the `DefId` of the defining trait.
     /// The type _cannot_ be a type other than a trait type.
@@ -854,8 +923,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
 
+        let path_span = if let [segment] = &trait_ref.path.segments[..] {
+            // FIXME: `trait_ref.path.span` can point to a full path with multiple
+            // segments, even though `trait_ref.path.segments` is of length `1`. Work
+            // around that bug here, even though it should be fixed elsewhere.
+            // This would otherwise cause an invalid suggestion. For an example, look at
+            // `src/test/ui/issues/issue-28344.rs`.
+            segment.ident.span
+        } else {
+            trait_ref.path.span
+        };
         let (substs, assoc_bindings, potential_assoc_types) = self.create_substs_for_ast_trait_ref(
-            trait_ref.path.span,
+            path_span,
             trait_def_id,
             self_ty,
             trait_ref.path.segments.last().unwrap(),
@@ -874,6 +953,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 bounds,
                 speculative,
                 &mut dup_bindings,
+                span,
             );
             // Okay to ignore `Err` because of `ErrorReported` (see above).
         }
@@ -932,29 +1012,75 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         ty::TraitRef::new(trait_def_id, substs)
     }
 
-    fn create_substs_for_ast_trait_ref<'a>(
+    /// When the code is using the `Fn` traits directly, instead of the `Fn(A) -> B` syntax, emit
+    /// an error and attempt to build a reasonable structured suggestion.
+    fn complain_about_internal_fn_trait(
         &self,
         span: Span,
         trait_def_id: DefId,
-        self_ty: Ty<'tcx>,
         trait_segment: &'a hir::PathSegment,
-    ) -> (SubstsRef<'tcx>, Vec<ConvertedBinding<'a, 'tcx>>, Option<Vec<Span>>) {
-        debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", trait_segment);
-
+    ) {
         let trait_def = self.tcx().trait_def(trait_def_id);
 
         if !self.tcx().features().unboxed_closures
             && trait_segment.generic_args().parenthesized != trait_def.paren_sugar
         {
             // For now, require that parenthetical notation be used only with `Fn()` etc.
-            let msg = if trait_def.paren_sugar {
-                "the precise format of `Fn`-family traits' type parameters is subject to change. \
-                 Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead"
+            let (msg, sugg) = if trait_def.paren_sugar {
+                (
+                    "the precise format of `Fn`-family traits' type parameters is subject to \
+                     change",
+                    Some(format!(
+                        "{}{} -> {}",
+                        trait_segment.ident,
+                        trait_segment
+                            .args
+                            .as_ref()
+                            .and_then(|args| args.args.get(0))
+                            .and_then(|arg| match arg {
+                                hir::GenericArg::Type(ty) => {
+                                    Some(print::to_string(print::NO_ANN, |s| s.print_type(ty)))
+                                }
+                                _ => None,
+                            })
+                            .unwrap_or_else(|| "()".to_string()),
+                        trait_segment
+                            .generic_args()
+                            .bindings
+                            .iter()
+                            .filter_map(|b| match (b.ident.as_str() == "Output", &b.kind) {
+                                (true, hir::TypeBindingKind::Equality { ty }) => {
+                                    Some(print::to_string(print::NO_ANN, |s| s.print_type(ty)))
+                                }
+                                _ => None,
+                            })
+                            .next()
+                            .unwrap_or_else(|| "()".to_string()),
+                    )),
+                )
             } else {
-                "parenthetical notation is only stable when used with `Fn`-family traits"
+                ("parenthetical notation is only stable when used with `Fn`-family traits", None)
             };
-            feature_err(&self.tcx().sess.parse_sess, sym::unboxed_closures, span, msg).emit();
+            let sess = &self.tcx().sess.parse_sess;
+            let mut err = feature_err(sess, sym::unboxed_closures, span, msg);
+            if let Some(sugg) = sugg {
+                let msg = "use parenthetical notation instead";
+                err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect);
+            }
+            err.emit();
         }
+    }
+
+    fn create_substs_for_ast_trait_ref<'a>(
+        &self,
+        span: Span,
+        trait_def_id: DefId,
+        self_ty: Ty<'tcx>,
+        trait_segment: &'a hir::PathSegment,
+    ) -> (SubstsRef<'tcx>, Vec<ConvertedBinding<'a, 'tcx>>, Option<Vec<Span>>) {
+        debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", trait_segment);
+
+        self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment);
 
         self.create_substs_for_ast_path(
             span,
@@ -1118,6 +1244,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         bounds: &mut Bounds<'tcx>,
         speculative: bool,
         dup_bindings: &mut FxHashMap<DefId, Span>,
+        path_span: Span,
     ) -> Result<(), ErrorReported> {
         let tcx = self.tcx();
 
@@ -1180,7 +1307,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         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.
-                Ok(trait_ref)
+                trait_ref
             } else {
                 // Otherwise, we have to walk through the supertraits to find
                 // those that do.
@@ -1188,9 +1315,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     || traits::supertraits(tcx, trait_ref),
                     &trait_ref.print_only_trait_path().to_string(),
                     binding.item_name,
-                    binding.span,
-                )
-            }?;
+                    path_span,
+                    match binding.kind {
+                        ConvertedBindingKind::Equality(ty) => Some(ty.to_string()),
+                        _ => None,
+                    },
+                )?
+            };
 
         let (assoc_ident, def_scope) =
             tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id);
@@ -1213,8 +1344,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         self.tcx().sess,
                         binding.span,
                         E0719,
-                        "the value of the associated type `{}` (from the trait `{}`) \
-                                      is already specified",
+                        "the value of the associated type `{}` (from trait `{}`) \
+                         is already specified",
                         binding.item_name,
                         tcx.def_path_str(assoc_ty.container.id())
                     )
@@ -1326,121 +1457,71 @@ 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 mut associated_types: FxHashMap<Span, BTreeSet<DefId>> = FxHashMap::default();
 
-        let regular_traits_refs = bounds
+        let regular_traits_refs_spans = bounds
             .trait_bounds
             .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())
-                            .filter(|item| item.kind == ty::AssocKind::Type)
-                            .map(|item| item.def_id),
-                    );
-                }
-                ty::Predicate::Projection(pred) => {
-                    // A `Self` within the original bound will be substituted with a
-                    // `trait_object_dummy_self`, so check for that.
-                    let references_self = pred.skip_binder().ty.walk().any(|t| t == dummy_self);
-
-                    // If the projection output contains `Self`, force the user to
-                    // elaborate it explicitly to avoid a lot of complexity.
-                    //
-                    // The "classicaly useful" case is the following:
-                    // ```
-                    //     trait MyTrait: FnMut() -> <Self as MyTrait>::MyOutput {
-                    //         type MyOutput;
-                    //     }
-                    // ```
-                    //
-                    // Here, the user could theoretically write `dyn MyTrait<Output = X>`,
-                    // but actually supporting that would "expand" to an infinitely-long type
-                    // `fix $ τ → dyn MyTrait<MyOutput = X, Output = <τ as MyTrait>::MyOutput`.
-                    //
-                    // Instead, we force the user to write `dyn MyTrait<MyOutput = X, Output = X>`,
-                    // which is uglier but works. See the discussion in #56288 for alternatives.
-                    if !references_self {
-                        // Include projections defined on supertraits.
-                        bounds.projection_bounds.push((pred, DUMMY_SP))
+            .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
+
+        for (base_trait_ref, span) in regular_traits_refs_spans {
+            for trait_ref in traits::elaborate_trait_ref(tcx, base_trait_ref) {
+                debug!(
+                    "conv_object_ty_poly_trait_ref: observing object predicate `{:?}`",
+                    trait_ref
+                );
+                match trait_ref {
+                    ty::Predicate::Trait(pred) => {
+                        associated_types.entry(span).or_default().extend(
+                            tcx.associated_items(pred.def_id())
+                                .filter(|item| item.kind == ty::AssocKind::Type)
+                                .map(|item| item.def_id),
+                        );
                     }
+                    ty::Predicate::Projection(pred) => {
+                        // A `Self` within the original bound will be substituted with a
+                        // `trait_object_dummy_self`, so check for that.
+                        let references_self = pred.skip_binder().ty.walk().any(|t| t == dummy_self);
+
+                        // If the projection output contains `Self`, force the user to
+                        // elaborate it explicitly to avoid a lot of complexity.
+                        //
+                        // The "classicaly useful" case is the following:
+                        // ```
+                        //     trait MyTrait: FnMut() -> <Self as MyTrait>::MyOutput {
+                        //         type MyOutput;
+                        //     }
+                        // ```
+                        //
+                        // Here, the user could theoretically write `dyn MyTrait<Output = X>`,
+                        // but actually supporting that would "expand" to an infinitely-long type
+                        // `fix $ τ → dyn MyTrait<MyOutput = X, Output = <τ as MyTrait>::MyOutput`.
+                        //
+                        // Instead, we force the user to write
+                        // `dyn MyTrait<MyOutput = X, Output = X>`, which is uglier but works. See
+                        // the discussion in #56288 for alternatives.
+                        if !references_self {
+                            // Include projections defined on supertraits.
+                            bounds.projection_bounds.push((pred, span));
+                        }
+                    }
+                    _ => (),
                 }
-                _ => (),
             }
         }
 
         for (projection_bound, _) in &bounds.projection_bounds {
-            associated_types.remove(&projection_bound.projection_def_id());
-        }
-
-        if !associated_types.is_empty() {
-            let names = associated_types
-                .iter()
-                .map(|item_def_id| {
-                    let assoc_item = tcx.associated_item(*item_def_id);
-                    let trait_def_id = assoc_item.container.id();
-                    format!(
-                        "`{}` (from the trait `{}`)",
-                        assoc_item.ident,
-                        tcx.def_path_str(trait_def_id),
-                    )
-                })
-                .collect::<Vec<_>>()
-                .join(", ");
-            let mut err = struct_span_err!(
-                tcx.sess,
-                span,
-                E0191,
-                "the value of the associated type{} {} must be specified",
-                pluralize!(associated_types.len()),
-                names,
-            );
-            let (suggest, potential_assoc_types_spans) =
-                if potential_assoc_types.len() == associated_types.len() {
-                    // 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>`.
-                    (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(
-                    span,
-                    format!("associated type `{}` must be specified", assoc_item.ident),
-                );
-                if let Some(sp) = tcx.hir().span_if_local(*item_def_id) {
-                    err.span_label(sp, format!("`{}` defined here", assoc_item.ident));
-                }
-                if suggest {
-                    if let Ok(snippet) =
-                        tcx.sess.source_map().span_to_snippet(potential_assoc_types_spans[i])
-                    {
-                        suggestions.push((
-                            potential_assoc_types_spans[i],
-                            format!("{} = {}", assoc_item.ident, snippet),
-                        ));
-                    }
-                }
-            }
-            if !suggestions.is_empty() {
-                let msg = format!(
-                    "if you meant to specify the associated {}, write",
-                    if suggestions.len() == 1 { "type" } else { "types" }
-                );
-                err.multipart_suggestion(&msg, suggestions, Applicability::MaybeIncorrect);
+            for (_, def_ids) in &mut associated_types {
+                def_ids.remove(&projection_bound.projection_def_id());
             }
-            err.emit();
         }
 
+        self.complain_about_missing_associated_types(
+            associated_types,
+            potential_assoc_types,
+            trait_bounds,
+        );
+
         // 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());
@@ -1528,6 +1609,198 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         ty
     }
 
+    /// When there are any missing associated types, emit an E0191 error and attempt to supply a
+    /// reasonable suggestion on how to write it. For the case of multiple associated types in the
+    /// same trait bound have the same name (as they come from different super-traits), we instead
+    /// emit a generic note suggesting using a `where` clause to constraint instead.
+    fn complain_about_missing_associated_types(
+        &self,
+        associated_types: FxHashMap<Span, BTreeSet<DefId>>,
+        potential_assoc_types: Vec<Span>,
+        trait_bounds: &[hir::PolyTraitRef],
+    ) {
+        if !associated_types.values().any(|v| v.len() > 0) {
+            return;
+        }
+        let tcx = self.tcx();
+        // FIXME: Marked `mut` so that we can replace the spans further below with a more
+        // appropriate one, but this should be handled earlier in the span assignment.
+        let mut associated_types: FxHashMap<Span, Vec<_>> = associated_types
+            .into_iter()
+            .map(|(span, def_ids)| {
+                (span, def_ids.into_iter().map(|did| tcx.associated_item(did)).collect())
+            })
+            .collect();
+        let mut names = vec![];
+
+        // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
+        // `issue-22560.rs`.
+        let mut trait_bound_spans: Vec<Span> = vec![];
+        for (span, items) in &associated_types {
+            if !items.is_empty() {
+                trait_bound_spans.push(*span);
+            }
+            for assoc_item in items {
+                let trait_def_id = assoc_item.container.id();
+                names.push(format!(
+                    "`{}` (from trait `{}`)",
+                    assoc_item.ident,
+                    tcx.def_path_str(trait_def_id),
+                ));
+            }
+        }
+
+        match (&potential_assoc_types[..], &trait_bounds) {
+            ([], [bound]) => match &bound.trait_ref.path.segments[..] {
+                // FIXME: `trait_ref.path.span` can point to a full path with multiple
+                // segments, even though `trait_ref.path.segments` is of length `1`. Work
+                // around that bug here, even though it should be fixed elsewhere.
+                // This would otherwise cause an invalid suggestion. For an example, look at
+                // `src/test/ui/issues/issue-28344.rs` where instead of the following:
+                //
+                //   error[E0191]: the value of the associated type `Output`
+                //                 (from trait `std::ops::BitXor`) must be specified
+                //   --> $DIR/issue-28344.rs:4:17
+                //    |
+                // LL |     let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
+                //    |                 ^^^^^^ help: specify the associated type:
+                //    |                              `BitXor<Output = Type>`
+                //
+                // we would output:
+                //
+                //   error[E0191]: the value of the associated type `Output`
+                //                 (from trait `std::ops::BitXor`) must be specified
+                //   --> $DIR/issue-28344.rs:4:17
+                //    |
+                // LL |     let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
+                //    |                 ^^^^^^^^^^^^^ help: specify the associated type:
+                //    |                                     `BitXor::bitor<Output = Type>`
+                [segment] if segment.args.is_none() => {
+                    trait_bound_spans = vec![segment.ident.span];
+                    associated_types = associated_types
+                        .into_iter()
+                        .map(|(_, items)| (segment.ident.span, items))
+                        .collect();
+                }
+                _ => {}
+            },
+            _ => {}
+        }
+        names.sort();
+        trait_bound_spans.sort();
+        let mut err = struct_span_err!(
+            tcx.sess,
+            trait_bound_spans,
+            E0191,
+            "the value of the associated type{} {} must be specified",
+            pluralize!(names.len()),
+            names.join(", "),
+        );
+        let mut suggestions = vec![];
+        let mut types_count = 0;
+        let mut where_constraints = vec![];
+        for (span, assoc_items) in &associated_types {
+            let mut names: FxHashMap<_, usize> = FxHashMap::default();
+            for item in assoc_items {
+                types_count += 1;
+                *names.entry(item.ident.name).or_insert(0) += 1;
+            }
+            let mut dupes = false;
+            for item in assoc_items {
+                let prefix = if names[&item.ident.name] > 1 {
+                    let trait_def_id = item.container.id();
+                    dupes = true;
+                    format!("{}::", tcx.def_path_str(trait_def_id))
+                } else {
+                    String::new()
+                };
+                if let Some(sp) = tcx.hir().span_if_local(item.def_id) {
+                    err.span_label(sp, format!("`{}{}` defined here", prefix, item.ident));
+                }
+            }
+            if potential_assoc_types.len() == assoc_items.len() {
+                // 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>`.
+                for (potential, item) in potential_assoc_types.iter().zip(assoc_items.iter()) {
+                    if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*potential) {
+                        suggestions.push((*potential, format!("{} = {}", item.ident, snippet)));
+                    }
+                }
+            } else if let (Ok(snippet), false) =
+                (tcx.sess.source_map().span_to_snippet(*span), dupes)
+            {
+                let types: Vec<_> =
+                    assoc_items.iter().map(|item| format!("{} = Type", item.ident)).collect();
+                let code = if snippet.ends_with(">") {
+                    // The user wrote `Trait<'a>` or similar and we don't have a type we can
+                    // suggest, but at least we can clue them to the correct syntax
+                    // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
+                    // suggestion.
+                    format!("{}, {}>", &snippet[..snippet.len() - 1], types.join(", "))
+                } else {
+                    // The user wrote `Iterator`, so we don't have a type we can suggest, but at
+                    // least we can clue them to the correct syntax `Iterator<Item = Type>`.
+                    format!("{}<{}>", snippet, types.join(", "))
+                };
+                suggestions.push((*span, code));
+            } else if dupes {
+                where_constraints.push(*span);
+            }
+        }
+        let where_msg = "consider introducing a new type parameter, adding `where` constraints \
+                         using the fully-qualified path to the associated types";
+        if !where_constraints.is_empty() && suggestions.is_empty() {
+            // If there are duplicates associated type names and a single trait bound do not
+            // use structured suggestion, it means that there are multiple super-traits with
+            // the same associated type name.
+            err.help(where_msg);
+        }
+        if suggestions.len() != 1 {
+            // We don't need this label if there's an inline suggestion, show otherwise.
+            for (span, assoc_items) in &associated_types {
+                let mut names: FxHashMap<_, usize> = FxHashMap::default();
+                for item in assoc_items {
+                    types_count += 1;
+                    *names.entry(item.ident.name).or_insert(0) += 1;
+                }
+                let mut label = vec![];
+                for item in assoc_items {
+                    let postfix = if names[&item.ident.name] > 1 {
+                        let trait_def_id = item.container.id();
+                        format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id))
+                    } else {
+                        String::new()
+                    };
+                    label.push(format!("`{}`{}", item.ident, postfix));
+                }
+                if !label.is_empty() {
+                    err.span_label(
+                        *span,
+                        format!(
+                            "associated type{} {} must be specified",
+                            pluralize!(label.len()),
+                            label.join(", "),
+                        ),
+                    );
+                }
+            }
+        }
+        if !suggestions.is_empty() {
+            err.multipart_suggestion(
+                &format!("specify the associated type{}", pluralize!(types_count)),
+                suggestions,
+                Applicability::HasPlaceholders,
+            );
+            if !where_constraints.is_empty() {
+                err.span_help(where_constraints, where_msg);
+            }
+        }
+        err.emit();
+    }
+
     fn report_ambiguous_associated_type(
         &self,
         span: Span,
@@ -1590,15 +1863,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             &param_name.as_str(),
             assoc_name,
             span,
+            None,
         )
     }
 
+    // Checks that `bounds` contains exactly one element and reports appropriate
+    // errors otherwise.
     fn one_bound_for_assoc_type<I>(
         &self,
         all_candidates: impl Fn() -> I,
         ty_param_name: &str,
         assoc_name: ast::Ident,
         span: Span,
+        is_equality: Option<String>,
     ) -> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
     where
         I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
@@ -1625,16 +1902,29 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2);
 
             let bounds = iter::once(bound).chain(iter::once(bound2)).chain(matching_candidates);
-            let mut err = struct_span_err!(
-                self.tcx().sess,
-                span,
-                E0221,
-                "ambiguous associated type `{}` in bounds of `{}`",
-                assoc_name,
-                ty_param_name
-            );
+            let mut err = if is_equality.is_some() {
+                // More specific Error Index entry.
+                struct_span_err!(
+                    self.tcx().sess,
+                    span,
+                    E0222,
+                    "ambiguous associated type `{}` in bounds of `{}`",
+                    assoc_name,
+                    ty_param_name
+                )
+            } else {
+                struct_span_err!(
+                    self.tcx().sess,
+                    span,
+                    E0221,
+                    "ambiguous associated type `{}` in bounds of `{}`",
+                    assoc_name,
+                    ty_param_name
+                )
+            };
             err.span_label(span, format!("ambiguous associated type `{}`", assoc_name));
 
+            let mut where_bounds = vec![];
             for bound in bounds {
                 let bound_span = self
                     .tcx()
@@ -1645,28 +1935,56 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     })
                     .and_then(|item| self.tcx().hir().span_if_local(item.def_id));
 
-                if let Some(span) = bound_span {
+                if let Some(bound_span) = bound_span {
                     err.span_label(
-                        span,
+                        bound_span,
                         format!(
                             "ambiguous `{}` from `{}`",
                             assoc_name,
-                            bound.print_only_trait_path()
+                            bound.print_only_trait_path(),
                         ),
                     );
+                    if let Some(constraint) = &is_equality {
+                        where_bounds.push(format!(
+                            "        T: {trait}::{assoc} = {constraint}",
+                            trait=bound.print_only_trait_path(),
+                            assoc=assoc_name,
+                            constraint=constraint,
+                        ));
+                    } else {
+                        err.span_suggestion(
+                            span,
+                            "use fully qualified syntax to disambiguate",
+                            format!(
+                                "<{} as {}>::{}",
+                                ty_param_name,
+                                bound.print_only_trait_path(),
+                                assoc_name,
+                            ),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
                 } else {
-                    span_note!(
-                        &mut err,
-                        span,
+                    err.note(&format!(
                         "associated type `{}` could derive from `{}`",
                         ty_param_name,
-                        bound.print_only_trait_path()
-                    );
+                        bound.print_only_trait_path(),
+                    ));
                 }
             }
+            if !where_bounds.is_empty() {
+                err.help(&format!(
+                    "consider introducing a new type parameter `T` and adding `where` constraints:\
+                     \n    where\n        T: {},\n{}",
+                    ty_param_name,
+                    where_bounds.join(",\n"),
+                ));
+            }
             err.emit();
+            if !where_bounds.is_empty() {
+                return Err(ErrorReported);
+            }
         }
-
         return Ok(bound);
     }
 
@@ -1679,6 +1997,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     ) where
         I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
     {
+        // The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
+        // valid span, so we point at the whole path segment instead.
+        let span = if assoc_name.span != DUMMY_SP { assoc_name.span } else { span };
         let mut err = struct_span_err!(
             self.tcx().sess,
             span,
@@ -1696,11 +2017,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             )
             .collect();
 
-        if let Some(suggested_name) =
-            find_best_match_for_name(all_candidate_names.iter(), &assoc_name.as_str(), None)
-        {
+        if let (Some(suggested_name), true) = (
+            find_best_match_for_name(all_candidate_names.iter(), &assoc_name.as_str(), None),
+            assoc_name.span != DUMMY_SP,
+        ) {
             err.span_suggestion(
-                span,
+                assoc_name.span,
                 "there is an associated type with a similar name",
                 suggested_name.to_string(),
                 Applicability::MaybeIncorrect,
@@ -1771,6 +2093,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     "Self",
                     assoc_ident,
                     span,
+                    None,
                 )?
             }
             (&ty::Param(_), Res::SelfTy(Some(param_did), None))
diff --git a/src/test/compile-fail/issue-23595-1.rs b/src/test/compile-fail/issue-23595-1.rs
index 2912c4ead7a..483c205f42d 100644
--- a/src/test/compile-fail/issue-23595-1.rs
+++ b/src/test/compile-fail/issue-23595-1.rs
@@ -1,12 +1,12 @@
 #![feature(associated_type_defaults)]
 
-use std::ops::{Index};
+use std::ops::Index;
 
 trait Hierarchy {
     type Value;
     type ChildKey;
     type Children = dyn Index<Self::ChildKey, Output=dyn Hierarchy>;
-    //~^ ERROR: the value of the associated types `Value` (from the trait `Hierarchy`), `ChildKey`
+    //~^ ERROR: the value of the associated types
 
     fn data(&self) -> Option<(Self::Value, Self::Children)>;
 }
diff --git a/src/test/ui/associated-type-bounds/duplicate.rs b/src/test/ui/associated-type-bounds/duplicate.rs
index a89fd9807da..64bc9eeec25 100644
--- a/src/test/ui/associated-type-bounds/duplicate.rs
+++ b/src/test/ui/associated-type-bounds/duplicate.rs
@@ -9,175 +9,175 @@
 use std::iter;
 
 struct SI1<T: Iterator<Item: Copy, Item: Send>> { f: T }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 struct SI2<T: Iterator<Item: Copy, Item: Copy>> { f: T }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 struct SI3<T: Iterator<Item: 'static, Item: 'static>> { f: T }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 struct SW1<T> where T: Iterator<Item: Copy, Item: Send> { f: T }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 struct SW2<T> where T: Iterator<Item: Copy, Item: Copy> { f: T }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 struct SW3<T> where T: Iterator<Item: 'static, Item: 'static> { f: T }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 
 enum EI1<T: Iterator<Item: Copy, Item: Send>> { V(T) }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 enum EI2<T: Iterator<Item: Copy, Item: Copy>> { V(T) }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 enum EI3<T: Iterator<Item: 'static, Item: 'static>> { V(T) }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 enum EW1<T> where T: Iterator<Item: Copy, Item: Send> { V(T) }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 enum EW2<T> where T: Iterator<Item: Copy, Item: Copy> { V(T) }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 enum EW3<T> where T: Iterator<Item: 'static, Item: 'static> { V(T) }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 
 union UI1<T: Iterator<Item: Copy, Item: Send>> { f: T }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 union UI2<T: Iterator<Item: Copy, Item: Copy>> { f: T }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 union UI3<T: Iterator<Item: 'static, Item: 'static>> { f: T }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 union UW1<T> where T: Iterator<Item: Copy, Item: Send> { f: T }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 union UW2<T> where T: Iterator<Item: Copy, Item: Copy> { f: T }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 union UW3<T> where T: Iterator<Item: 'static, Item: 'static> { f: T }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 
 fn FI1<T: Iterator<Item: Copy, Item: Send>>() {}
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 fn FI2<T: Iterator<Item: Copy, Item: Copy>>() {}
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 fn FI3<T: Iterator<Item: 'static, Item: 'static>>() {}
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 fn FW1<T>() where T: Iterator<Item: Copy, Item: Send> {}
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 fn FW2<T>() where T: Iterator<Item: Copy, Item: Copy> {}
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 fn FW3<T>() where T: Iterator<Item: 'static, Item: 'static> {}
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 
 fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> { iter::empty() }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> { iter::empty() }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> { iter::empty() }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 fn FAPIT1(_: impl Iterator<Item: Copy, Item: Send>) {}
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 fn FAPIT2(_: impl Iterator<Item: Copy, Item: Copy>) {}
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 fn FAPIT3(_: impl Iterator<Item: 'static, Item: 'static>) {}
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 
 const CIT1: impl Iterator<Item: Copy, Item: Send> = iter::empty();
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 const CIT2: impl Iterator<Item: Copy, Item: Copy> = iter::empty();
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 const CIT3: impl Iterator<Item: 'static, Item: 'static> = iter::empty();
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 static SIT1: impl Iterator<Item: Copy, Item: Send> = iter::empty();
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 static SIT2: impl Iterator<Item: Copy, Item: Copy> = iter::empty();
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 static SIT3: impl Iterator<Item: 'static, Item: 'static> = iter::empty();
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 
 fn lit1() { let _: impl Iterator<Item: Copy, Item: Send> = iter::empty(); }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 fn lit2() { let _: impl Iterator<Item: Copy, Item: Copy> = iter::empty(); }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 fn lit3() { let _: impl Iterator<Item: 'static, Item: 'static> = iter::empty(); }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 
 type TAI1<T: Iterator<Item: Copy, Item: Send>> = T;
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 type TAI2<T: Iterator<Item: Copy, Item: Copy>> = T;
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 type TAI3<T: Iterator<Item: 'static, Item: 'static>> = T;
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 type TAW1<T> where T: Iterator<Item: Copy, Item: Send> = T;
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 type TAW2<T> where T: Iterator<Item: Copy, Item: Copy> = T;
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 type TAW3<T> where T: Iterator<Item: 'static, Item: 'static> = T;
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 
 type ETAI1<T: Iterator<Item: Copy, Item: Send>> = impl Copy;
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 //~| ERROR could not find defining uses
 //~| ERROR could not find defining uses
 //~| ERROR could not find defining uses
 type ETAI2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy;
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 //~| ERROR could not find defining uses
 //~| ERROR could not find defining uses
 //~| ERROR could not find defining uses
 type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy;
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 //~| ERROR could not find defining uses
 //~| ERROR could not find defining uses
 //~| ERROR could not find defining uses
 type ETAI4 = impl Iterator<Item: Copy, Item: Send>;
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 //~| ERROR could not find defining uses
 //~| ERROR could not find defining uses
 //~| ERROR could not find defining uses
 type ETAI5 = impl Iterator<Item: Copy, Item: Copy>;
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 //~| ERROR could not find defining uses
 //~| ERROR could not find defining uses
 //~| ERROR could not find defining uses
 type ETAI6 = impl Iterator<Item: 'static, Item: 'static>;
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 //~| ERROR could not find defining uses
 //~| ERROR could not find defining uses
 //~| ERROR could not find defining uses
 
 trait TRI1<T: Iterator<Item: Copy, Item: Send>> {}
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 trait TRI2<T: Iterator<Item: Copy, Item: Copy>> {}
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 trait TRI3<T: Iterator<Item: 'static, Item: 'static>> {}
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 trait TRS1: Iterator<Item: Copy, Item: Send> {}
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 trait TRS2: Iterator<Item: Copy, Item: Copy> {}
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 trait TRS3: Iterator<Item: 'static, Item: 'static> {}
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 trait TRW1<T> where T: Iterator<Item: Copy, Item: Send> {}
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 trait TRW2<T> where T: Iterator<Item: Copy, Item: Copy> {}
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 trait TRW3<T> where T: Iterator<Item: 'static, Item: 'static> {}
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 trait TRSW1 where Self: Iterator<Item: Copy, Item: Send> {}
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 trait TRSW2 where Self: Iterator<Item: Copy, Item: Copy> {}
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 trait TRSW3 where Self: Iterator<Item: 'static, Item: 'static> {}
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 trait TRA1 { type A: Iterator<Item: Copy, Item: Send>; }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 trait TRA2 { type A: Iterator<Item: Copy, Item: Copy>; }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 trait TRA3 { type A: Iterator<Item: 'static, Item: 'static>; }
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 
 type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 //~| ERROR could not find defining uses
 //~| ERROR could not find defining uses
 type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 //~| ERROR could not find defining uses
 //~| ERROR could not find defining uses
 type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
-//~^ ERROR the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 //~| ERROR could not find defining uses
 //~| ERROR could not find defining uses
 
diff --git a/src/test/ui/associated-type-bounds/duplicate.stderr b/src/test/ui/associated-type-bounds/duplicate.stderr
index e5e85d6856f..caecc5e85f6 100644
--- a/src/test/ui/associated-type-bounds/duplicate.stderr
+++ b/src/test/ui/associated-type-bounds/duplicate.stderr
@@ -6,7 +6,7 @@ LL | #![feature(impl_trait_in_bindings)]
    |
    = note: `#[warn(incomplete_features)]` on by default
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:11:36
    |
 LL | struct SI1<T: Iterator<Item: Copy, Item: Send>> { f: T }
@@ -14,7 +14,7 @@ LL | struct SI1<T: Iterator<Item: Copy, Item: Send>> { f: T }
    |                        |
    |                        `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:13:36
    |
 LL | struct SI2<T: Iterator<Item: Copy, Item: Copy>> { f: T }
@@ -22,7 +22,7 @@ LL | struct SI2<T: Iterator<Item: Copy, Item: Copy>> { f: T }
    |                        |
    |                        `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:15:39
    |
 LL | struct SI3<T: Iterator<Item: 'static, Item: 'static>> { f: T }
@@ -30,7 +30,7 @@ LL | struct SI3<T: Iterator<Item: 'static, Item: 'static>> { f: T }
    |                        |
    |                        `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:17:45
    |
 LL | struct SW1<T> where T: Iterator<Item: Copy, Item: Send> { f: T }
@@ -38,7 +38,7 @@ LL | struct SW1<T> where T: Iterator<Item: Copy, Item: Send> { f: T }
    |                                 |
    |                                 `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:19:45
    |
 LL | struct SW2<T> where T: Iterator<Item: Copy, Item: Copy> { f: T }
@@ -46,7 +46,7 @@ LL | struct SW2<T> where T: Iterator<Item: Copy, Item: Copy> { f: T }
    |                                 |
    |                                 `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:21:48
    |
 LL | struct SW3<T> where T: Iterator<Item: 'static, Item: 'static> { f: T }
@@ -54,7 +54,7 @@ LL | struct SW3<T> where T: Iterator<Item: 'static, Item: 'static> { f: T }
    |                                 |
    |                                 `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:24:34
    |
 LL | enum EI1<T: Iterator<Item: Copy, Item: Send>> { V(T) }
@@ -62,7 +62,7 @@ LL | enum EI1<T: Iterator<Item: Copy, Item: Send>> { V(T) }
    |                      |
    |                      `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:26:34
    |
 LL | enum EI2<T: Iterator<Item: Copy, Item: Copy>> { V(T) }
@@ -70,7 +70,7 @@ LL | enum EI2<T: Iterator<Item: Copy, Item: Copy>> { V(T) }
    |                      |
    |                      `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:28:37
    |
 LL | enum EI3<T: Iterator<Item: 'static, Item: 'static>> { V(T) }
@@ -78,7 +78,7 @@ LL | enum EI3<T: Iterator<Item: 'static, Item: 'static>> { V(T) }
    |                      |
    |                      `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:30:43
    |
 LL | enum EW1<T> where T: Iterator<Item: Copy, Item: Send> { V(T) }
@@ -86,7 +86,7 @@ LL | enum EW1<T> where T: Iterator<Item: Copy, Item: Send> { V(T) }
    |                               |
    |                               `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:32:43
    |
 LL | enum EW2<T> where T: Iterator<Item: Copy, Item: Copy> { V(T) }
@@ -94,7 +94,7 @@ LL | enum EW2<T> where T: Iterator<Item: Copy, Item: Copy> { V(T) }
    |                               |
    |                               `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:34:46
    |
 LL | enum EW3<T> where T: Iterator<Item: 'static, Item: 'static> { V(T) }
@@ -102,7 +102,7 @@ LL | enum EW3<T> where T: Iterator<Item: 'static, Item: 'static> { V(T) }
    |                               |
    |                               `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:37:35
    |
 LL | union UI1<T: Iterator<Item: Copy, Item: Send>> { f: T }
@@ -110,7 +110,7 @@ LL | union UI1<T: Iterator<Item: Copy, Item: Send>> { f: T }
    |                       |
    |                       `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:39:35
    |
 LL | union UI2<T: Iterator<Item: Copy, Item: Copy>> { f: T }
@@ -118,7 +118,7 @@ LL | union UI2<T: Iterator<Item: Copy, Item: Copy>> { f: T }
    |                       |
    |                       `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:41:38
    |
 LL | union UI3<T: Iterator<Item: 'static, Item: 'static>> { f: T }
@@ -126,7 +126,7 @@ LL | union UI3<T: Iterator<Item: 'static, Item: 'static>> { f: T }
    |                       |
    |                       `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:43:44
    |
 LL | union UW1<T> where T: Iterator<Item: Copy, Item: Send> { f: T }
@@ -134,7 +134,7 @@ LL | union UW1<T> where T: Iterator<Item: Copy, Item: Send> { f: T }
    |                                |
    |                                `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:45:44
    |
 LL | union UW2<T> where T: Iterator<Item: Copy, Item: Copy> { f: T }
@@ -142,7 +142,7 @@ LL | union UW2<T> where T: Iterator<Item: Copy, Item: Copy> { f: T }
    |                                |
    |                                `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:47:47
    |
 LL | union UW3<T> where T: Iterator<Item: 'static, Item: 'static> { f: T }
@@ -150,7 +150,7 @@ LL | union UW3<T> where T: Iterator<Item: 'static, Item: 'static> { f: T }
    |                                |
    |                                `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:50:32
    |
 LL | fn FI1<T: Iterator<Item: Copy, Item: Send>>() {}
@@ -158,7 +158,7 @@ LL | fn FI1<T: Iterator<Item: Copy, Item: Send>>() {}
    |                    |
    |                    `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:52:32
    |
 LL | fn FI2<T: Iterator<Item: Copy, Item: Copy>>() {}
@@ -166,7 +166,7 @@ LL | fn FI2<T: Iterator<Item: Copy, Item: Copy>>() {}
    |                    |
    |                    `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:54:35
    |
 LL | fn FI3<T: Iterator<Item: 'static, Item: 'static>>() {}
@@ -174,7 +174,7 @@ LL | fn FI3<T: Iterator<Item: 'static, Item: 'static>>() {}
    |                    |
    |                    `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:56:43
    |
 LL | fn FW1<T>() where T: Iterator<Item: Copy, Item: Send> {}
@@ -182,7 +182,7 @@ LL | fn FW1<T>() where T: Iterator<Item: Copy, Item: Send> {}
    |                               |
    |                               `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:58:43
    |
 LL | fn FW2<T>() where T: Iterator<Item: Copy, Item: Copy> {}
@@ -190,7 +190,7 @@ LL | fn FW2<T>() where T: Iterator<Item: Copy, Item: Copy> {}
    |                               |
    |                               `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:60:46
    |
 LL | fn FW3<T>() where T: Iterator<Item: 'static, Item: 'static> {}
@@ -198,7 +198,7 @@ LL | fn FW3<T>() where T: Iterator<Item: 'static, Item: 'static> {}
    |                               |
    |                               `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:69:40
    |
 LL | fn FAPIT1(_: impl Iterator<Item: Copy, Item: Send>) {}
@@ -206,7 +206,7 @@ LL | fn FAPIT1(_: impl Iterator<Item: Copy, Item: Send>) {}
    |                            |
    |                            `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:71:40
    |
 LL | fn FAPIT2(_: impl Iterator<Item: Copy, Item: Copy>) {}
@@ -214,7 +214,7 @@ LL | fn FAPIT2(_: impl Iterator<Item: Copy, Item: Copy>) {}
    |                            |
    |                            `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:73:43
    |
 LL | fn FAPIT3(_: impl Iterator<Item: 'static, Item: 'static>) {}
@@ -222,7 +222,7 @@ LL | fn FAPIT3(_: impl Iterator<Item: 'static, Item: 'static>) {}
    |                            |
    |                            `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:63:42
    |
 LL | fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> { iter::empty() }
@@ -230,7 +230,7 @@ LL | fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> { iter::empty() }
    |                              |
    |                              `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:65:42
    |
 LL | fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> { iter::empty() }
@@ -238,7 +238,7 @@ LL | fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> { iter::empty() }
    |                              |
    |                              `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:67:45
    |
 LL | fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> { iter::empty() }
@@ -246,7 +246,7 @@ LL | fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> { iter::empty()
    |                              |
    |                              `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:76:39
    |
 LL | const CIT1: impl Iterator<Item: Copy, Item: Send> = iter::empty();
@@ -254,7 +254,7 @@ LL | const CIT1: impl Iterator<Item: Copy, Item: Send> = iter::empty();
    |                           |
    |                           `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:78:39
    |
 LL | const CIT2: impl Iterator<Item: Copy, Item: Copy> = iter::empty();
@@ -262,7 +262,7 @@ LL | const CIT2: impl Iterator<Item: Copy, Item: Copy> = iter::empty();
    |                           |
    |                           `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:80:42
    |
 LL | const CIT3: impl Iterator<Item: 'static, Item: 'static> = iter::empty();
@@ -270,7 +270,7 @@ LL | const CIT3: impl Iterator<Item: 'static, Item: 'static> = iter::empty();
    |                           |
    |                           `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:82:40
    |
 LL | static SIT1: impl Iterator<Item: Copy, Item: Send> = iter::empty();
@@ -278,7 +278,7 @@ LL | static SIT1: impl Iterator<Item: Copy, Item: Send> = iter::empty();
    |                            |
    |                            `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:84:40
    |
 LL | static SIT2: impl Iterator<Item: Copy, Item: Copy> = iter::empty();
@@ -286,7 +286,7 @@ LL | static SIT2: impl Iterator<Item: Copy, Item: Copy> = iter::empty();
    |                            |
    |                            `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:86:43
    |
 LL | static SIT3: impl Iterator<Item: 'static, Item: 'static> = iter::empty();
@@ -294,7 +294,7 @@ LL | static SIT3: impl Iterator<Item: 'static, Item: 'static> = iter::empty();
    |                            |
    |                            `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:89:46
    |
 LL | fn lit1() { let _: impl Iterator<Item: Copy, Item: Send> = iter::empty(); }
@@ -302,7 +302,7 @@ LL | fn lit1() { let _: impl Iterator<Item: Copy, Item: Send> = iter::empty(); }
    |                                  |
    |                                  `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:91:46
    |
 LL | fn lit2() { let _: impl Iterator<Item: Copy, Item: Copy> = iter::empty(); }
@@ -310,7 +310,7 @@ LL | fn lit2() { let _: impl Iterator<Item: Copy, Item: Copy> = iter::empty(); }
    |                                  |
    |                                  `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:93:49
    |
 LL | fn lit3() { let _: impl Iterator<Item: 'static, Item: 'static> = iter::empty(); }
@@ -318,7 +318,7 @@ LL | fn lit3() { let _: impl Iterator<Item: 'static, Item: 'static> = iter::empt
    |                                  |
    |                                  `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:96:35
    |
 LL | type TAI1<T: Iterator<Item: Copy, Item: Send>> = T;
@@ -326,7 +326,7 @@ LL | type TAI1<T: Iterator<Item: Copy, Item: Send>> = T;
    |                       |
    |                       `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:98:35
    |
 LL | type TAI2<T: Iterator<Item: Copy, Item: Copy>> = T;
@@ -334,7 +334,7 @@ LL | type TAI2<T: Iterator<Item: Copy, Item: Copy>> = T;
    |                       |
    |                       `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:100:38
    |
 LL | type TAI3<T: Iterator<Item: 'static, Item: 'static>> = T;
@@ -342,7 +342,7 @@ LL | type TAI3<T: Iterator<Item: 'static, Item: 'static>> = T;
    |                       |
    |                       `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:102:44
    |
 LL | type TAW1<T> where T: Iterator<Item: Copy, Item: Send> = T;
@@ -350,7 +350,7 @@ LL | type TAW1<T> where T: Iterator<Item: Copy, Item: Send> = T;
    |                                |
    |                                `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:104:44
    |
 LL | type TAW2<T> where T: Iterator<Item: Copy, Item: Copy> = T;
@@ -358,7 +358,7 @@ LL | type TAW2<T> where T: Iterator<Item: Copy, Item: Copy> = T;
    |                                |
    |                                `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:106:47
    |
 LL | type TAW3<T> where T: Iterator<Item: 'static, Item: 'static> = T;
@@ -372,7 +372,7 @@ error: could not find defining uses
 LL | type ETAI1<T: Iterator<Item: Copy, Item: Send>> = impl Copy;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:109:36
    |
 LL | type ETAI1<T: Iterator<Item: Copy, Item: Send>> = impl Copy;
@@ -386,7 +386,7 @@ error: could not find defining uses
 LL | type ETAI2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:114:36
    |
 LL | type ETAI2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy;
@@ -400,7 +400,7 @@ error: could not find defining uses
 LL | type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:119:39
    |
 LL | type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy;
@@ -414,7 +414,7 @@ error: could not find defining uses
 LL | type ETAI4 = impl Iterator<Item: Copy, Item: Send>;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:124:40
    |
 LL | type ETAI4 = impl Iterator<Item: Copy, Item: Send>;
@@ -428,7 +428,7 @@ error: could not find defining uses
 LL | type ETAI5 = impl Iterator<Item: Copy, Item: Copy>;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:129:40
    |
 LL | type ETAI5 = impl Iterator<Item: Copy, Item: Copy>;
@@ -442,7 +442,7 @@ error: could not find defining uses
 LL | type ETAI6 = impl Iterator<Item: 'static, Item: 'static>;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:134:43
    |
 LL | type ETAI6 = impl Iterator<Item: 'static, Item: 'static>;
@@ -450,7 +450,7 @@ LL | type ETAI6 = impl Iterator<Item: 'static, Item: 'static>;
    |                            |
    |                            `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:140:36
    |
 LL | trait TRI1<T: Iterator<Item: Copy, Item: Send>> {}
@@ -458,7 +458,7 @@ LL | trait TRI1<T: Iterator<Item: Copy, Item: Send>> {}
    |                        |
    |                        `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:142:36
    |
 LL | trait TRI2<T: Iterator<Item: Copy, Item: Copy>> {}
@@ -466,7 +466,7 @@ LL | trait TRI2<T: Iterator<Item: Copy, Item: Copy>> {}
    |                        |
    |                        `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:144:39
    |
 LL | trait TRI3<T: Iterator<Item: 'static, Item: 'static>> {}
@@ -474,7 +474,7 @@ LL | trait TRI3<T: Iterator<Item: 'static, Item: 'static>> {}
    |                        |
    |                        `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:146:34
    |
 LL | trait TRS1: Iterator<Item: Copy, Item: Send> {}
@@ -482,7 +482,7 @@ LL | trait TRS1: Iterator<Item: Copy, Item: Send> {}
    |                      |
    |                      `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:148:34
    |
 LL | trait TRS2: Iterator<Item: Copy, Item: Copy> {}
@@ -490,7 +490,7 @@ LL | trait TRS2: Iterator<Item: Copy, Item: Copy> {}
    |                      |
    |                      `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:150:37
    |
 LL | trait TRS3: Iterator<Item: 'static, Item: 'static> {}
@@ -498,7 +498,7 @@ LL | trait TRS3: Iterator<Item: 'static, Item: 'static> {}
    |                      |
    |                      `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:152:45
    |
 LL | trait TRW1<T> where T: Iterator<Item: Copy, Item: Send> {}
@@ -506,7 +506,7 @@ LL | trait TRW1<T> where T: Iterator<Item: Copy, Item: Send> {}
    |                                 |
    |                                 `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:154:45
    |
 LL | trait TRW2<T> where T: Iterator<Item: Copy, Item: Copy> {}
@@ -514,7 +514,7 @@ LL | trait TRW2<T> where T: Iterator<Item: Copy, Item: Copy> {}
    |                                 |
    |                                 `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:156:48
    |
 LL | trait TRW3<T> where T: Iterator<Item: 'static, Item: 'static> {}
@@ -522,7 +522,7 @@ LL | trait TRW3<T> where T: Iterator<Item: 'static, Item: 'static> {}
    |                                 |
    |                                 `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:158:46
    |
 LL | trait TRSW1 where Self: Iterator<Item: Copy, Item: Send> {}
@@ -530,7 +530,7 @@ LL | trait TRSW1 where Self: Iterator<Item: Copy, Item: Send> {}
    |                                  |
    |                                  `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:160:46
    |
 LL | trait TRSW2 where Self: Iterator<Item: Copy, Item: Copy> {}
@@ -538,7 +538,7 @@ LL | trait TRSW2 where Self: Iterator<Item: Copy, Item: Copy> {}
    |                                  |
    |                                  `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:162:49
    |
 LL | trait TRSW3 where Self: Iterator<Item: 'static, Item: 'static> {}
@@ -546,7 +546,7 @@ LL | trait TRSW3 where Self: Iterator<Item: 'static, Item: 'static> {}
    |                                  |
    |                                  `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:164:43
    |
 LL | trait TRA1 { type A: Iterator<Item: Copy, Item: Send>; }
@@ -554,7 +554,7 @@ LL | trait TRA1 { type A: Iterator<Item: Copy, Item: Send>; }
    |                               |
    |                               `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:166:43
    |
 LL | trait TRA2 { type A: Iterator<Item: Copy, Item: Copy>; }
@@ -562,7 +562,7 @@ LL | trait TRA2 { type A: Iterator<Item: Copy, Item: Copy>; }
    |                               |
    |                               `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:168:46
    |
 LL | trait TRA3 { type A: Iterator<Item: 'static, Item: 'static>; }
@@ -570,7 +570,7 @@ LL | trait TRA3 { type A: Iterator<Item: 'static, Item: 'static>; }
    |                               |
    |                               `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:171:40
    |
 LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
@@ -578,7 +578,7 @@ LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
    |                            |
    |                            `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:175:44
    |
 LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
@@ -586,7 +586,7 @@ LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
    |                                |
    |                                `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:179:43
    |
 LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
diff --git a/src/test/ui/associated-type/associated-type-projection-ambig-between-bound-and-where-clause.stderr b/src/test/ui/associated-type/associated-type-projection-ambig-between-bound-and-where-clause.stderr
index 9ec6ffb0565..6de8459954c 100644
--- a/src/test/ui/associated-type/associated-type-projection-ambig-between-bound-and-where-clause.stderr
+++ b/src/test/ui/associated-type/associated-type-projection-ambig-between-bound-and-where-clause.stderr
@@ -9,6 +9,15 @@ LL |     type Color;
 ...
 LL | fn a<C:Vehicle+Box>(_: C::Color) {
    |                        ^^^^^^^^ ambiguous associated type `Color`
+   |
+help: use fully qualified syntax to disambiguate
+   |
+LL | fn a<C:Vehicle+Box>(_: <C as Box>::Color) {
+   |                        ^^^^^^^^^^^^^^^^^
+help: use fully qualified syntax to disambiguate
+   |
+LL | fn a<C:Vehicle+Box>(_: <C as Vehicle>::Color) {
+   |                        ^^^^^^^^^^^^^^^^^^^^^
 
 error[E0221]: ambiguous associated type `Color` in bounds of `C`
   --> $DIR/associated-type-projection-ambig-between-bound-and-where-clause.rs:20:12
@@ -21,6 +30,15 @@ LL |     type Color;
 ...
 LL | fn b<C>(_: C::Color) where C : Vehicle+Box {
    |            ^^^^^^^^ ambiguous associated type `Color`
+   |
+help: use fully qualified syntax to disambiguate
+   |
+LL | fn b<C>(_: <C as Box>::Color) where C : Vehicle+Box {
+   |            ^^^^^^^^^^^^^^^^^
+help: use fully qualified syntax to disambiguate
+   |
+LL | fn b<C>(_: <C as Vehicle>::Color) where C : Vehicle+Box {
+   |            ^^^^^^^^^^^^^^^^^^^^^
 
 error[E0221]: ambiguous associated type `Color` in bounds of `C`
   --> $DIR/associated-type-projection-ambig-between-bound-and-where-clause.rs:24:12
@@ -33,6 +51,15 @@ LL |     type Color;
 ...
 LL | fn c<C>(_: C::Color) where C : Vehicle, C : Box {
    |            ^^^^^^^^ ambiguous associated type `Color`
+   |
+help: use fully qualified syntax to disambiguate
+   |
+LL | fn c<C>(_: <C as Box>::Color) where C : Vehicle, C : Box {
+   |            ^^^^^^^^^^^^^^^^^
+help: use fully qualified syntax to disambiguate
+   |
+LL | fn c<C>(_: <C as Vehicle>::Color) where C : Vehicle, C : Box {
+   |            ^^^^^^^^^^^^^^^^^^^^^
 
 error[E0221]: ambiguous associated type `Color` in bounds of `X`
   --> $DIR/associated-type-projection-ambig-between-bound-and-where-clause.rs:35:20
@@ -45,6 +72,15 @@ LL |     type Color;
 ...
 LL |     fn e(&self, _: X::Color) where X : Box;
    |                    ^^^^^^^^ ambiguous associated type `Color`
+   |
+help: use fully qualified syntax to disambiguate
+   |
+LL |     fn e(&self, _: <X as Box>::Color) where X : Box;
+   |                    ^^^^^^^^^^^^^^^^^
+help: use fully qualified syntax to disambiguate
+   |
+LL |     fn e(&self, _: <X as Vehicle>::Color) where X : Box;
+   |                    ^^^^^^^^^^^^^^^^^^^^^
 
 error[E0221]: ambiguous associated type `Color` in bounds of `X`
   --> $DIR/associated-type-projection-ambig-between-bound-and-where-clause.rs:38:20
@@ -57,6 +93,15 @@ LL |     type Color;
 ...
 LL |     fn f(&self, _: X::Color) where X : Box { }
    |                    ^^^^^^^^ ambiguous associated type `Color`
+   |
+help: use fully qualified syntax to disambiguate
+   |
+LL |     fn f(&self, _: <X as Box>::Color) where X : Box { }
+   |                    ^^^^^^^^^^^^^^^^^
+help: use fully qualified syntax to disambiguate
+   |
+LL |     fn f(&self, _: <X as Vehicle>::Color) where X : Box { }
+   |                    ^^^^^^^^^^^^^^^^^^^^^
 
 error[E0221]: ambiguous associated type `Color` in bounds of `X`
   --> $DIR/associated-type-projection-ambig-between-bound-and-where-clause.rs:30:20
@@ -69,6 +114,15 @@ LL |     type Color;
 ...
 LL |     fn d(&self, _: X::Color) where X : Box { }
    |                    ^^^^^^^^ ambiguous associated type `Color`
+   |
+help: use fully qualified syntax to disambiguate
+   |
+LL |     fn d(&self, _: <X as Box>::Color) where X : Box { }
+   |                    ^^^^^^^^^^^^^^^^^
+help: use fully qualified syntax to disambiguate
+   |
+LL |     fn d(&self, _: <X as Vehicle>::Color) where X : Box { }
+   |                    ^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.rs b/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.rs
index 7a678445796..df19332b645 100644
--- a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.rs
+++ b/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.rs
@@ -22,11 +22,22 @@ fn dent<C:BoxCar>(c: C, color: C::Color) {
 
 fn dent_object<COLOR>(c: dyn BoxCar<Color=COLOR>) {
     //~^ ERROR ambiguous associated type
-    //~| ERROR the value of the associated type `Color` (from the trait `Vehicle`) must be specified
+    //~| ERROR the value of the associated types
 }
 
 fn paint<C:BoxCar>(c: C, d: C::Color) {
     //~^ ERROR ambiguous associated type `Color` in bounds of `C`
 }
 
+fn dent_object_2<COLOR>(c: dyn BoxCar) where <dyn BoxCar as Vehicle>::Color = COLOR {
+    //~^ ERROR the value of the associated types
+    //~| ERROR equality constraints are not yet supported in `where` clauses
+}
+
+fn dent_object_3<X, COLOR>(c: X)
+where X: BoxCar,
+    X: Vehicle<Color = COLOR>,
+    X: Box<Color = COLOR>
+{} // OK!
+
 pub fn main() { }
diff --git a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr b/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr
index 6118ebef125..c60d5f8f2c8 100644
--- a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr
+++ b/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr
@@ -1,3 +1,11 @@
+error: equality constraints are not yet supported in `where` clauses
+  --> $DIR/associated-type-projection-from-multiple-supertraits.rs:32:46
+   |
+LL | fn dent_object_2<COLOR>(c: dyn BoxCar) where <dyn BoxCar as Vehicle>::Color = COLOR {
+   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not supported
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/20041
+
 error[E0221]: ambiguous associated type `Color` in bounds of `C`
   --> $DIR/associated-type-projection-from-multiple-supertraits.rs:19:32
    |
@@ -9,9 +17,18 @@ LL |     type Color;
 ...
 LL | fn dent<C:BoxCar>(c: C, color: C::Color) {
    |                                ^^^^^^^^ ambiguous associated type `Color`
+   |
+help: use fully qualified syntax to disambiguate
+   |
+LL | fn dent<C:BoxCar>(c: C, color: <C as Box>::Color) {
+   |                                ^^^^^^^^^^^^^^^^^
+help: use fully qualified syntax to disambiguate
+   |
+LL | fn dent<C:BoxCar>(c: C, color: <C as Vehicle>::Color) {
+   |                                ^^^^^^^^^^^^^^^^^^^^^
 
-error[E0221]: ambiguous associated type `Color` in bounds of `BoxCar`
-  --> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:37
+error[E0222]: ambiguous associated type `Color` in bounds of `BoxCar`
+  --> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:30
    |
 LL |     type Color;
    |     ----------- ambiguous `Color` from `Vehicle`
@@ -20,16 +37,27 @@ LL |     type Color;
    |     ----------- ambiguous `Color` from `Box`
 ...
 LL | fn dent_object<COLOR>(c: dyn BoxCar<Color=COLOR>) {
-   |                                     ^^^^^^^^^^^ ambiguous associated type `Color`
+   |                              ^^^^^^^^^^^^^^^^^^^ ambiguous associated type `Color`
+   |
+   = help: consider introducing a new type parameter `T` and adding `where` constraints:
+               where
+                   T: BoxCar,
+                   T: Box::Color = COLOR,
+                   T: Vehicle::Color = COLOR
 
-error[E0191]: the value of the associated type `Color` (from the trait `Vehicle`) must be specified
-  --> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:26
+error[E0191]: the value of the associated types `Color` (from trait `Box`), `Color` (from trait `Vehicle`) must be specified
+  --> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:30
    |
 LL |     type Color;
-   |     ----------- `Color` defined here
+   |     ----------- `Vehicle::Color` defined here
+...
+LL |     type Color;
+   |     ----------- `Box::Color` defined here
 ...
 LL | fn dent_object<COLOR>(c: dyn BoxCar<Color=COLOR>) {
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^ associated type `Color` must be specified
+   |                              ^^^^^^^^^^^^^^^^^^^ associated types `Color` (from trait `Vehicle`), `Color` (from trait `Box`) must be specified
+   |
+   = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types
 
 error[E0221]: ambiguous associated type `Color` in bounds of `C`
   --> $DIR/associated-type-projection-from-multiple-supertraits.rs:28:29
@@ -42,8 +70,31 @@ LL |     type Color;
 ...
 LL | fn paint<C:BoxCar>(c: C, d: C::Color) {
    |                             ^^^^^^^^ ambiguous associated type `Color`
+   |
+help: use fully qualified syntax to disambiguate
+   |
+LL | fn paint<C:BoxCar>(c: C, d: <C as Box>::Color) {
+   |                             ^^^^^^^^^^^^^^^^^
+help: use fully qualified syntax to disambiguate
+   |
+LL | fn paint<C:BoxCar>(c: C, d: <C as Vehicle>::Color) {
+   |                             ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0191]: the value of the associated types `Color` (from trait `Box`), `Color` (from trait `Vehicle`) must be specified
+  --> $DIR/associated-type-projection-from-multiple-supertraits.rs:32:32
+   |
+LL |     type Color;
+   |     ----------- `Vehicle::Color` defined here
+...
+LL |     type Color;
+   |     ----------- `Box::Color` defined here
+...
+LL | fn dent_object_2<COLOR>(c: dyn BoxCar) where <dyn BoxCar as Vehicle>::Color = COLOR {
+   |                                ^^^^^^ associated types `Color` (from trait `Vehicle`), `Color` (from trait `Box`) must be specified
+   |
+   = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types
 
-error: aborting due to 4 previous errors
+error: aborting due to 6 previous errors
 
-Some errors have detailed explanations: E0191, E0221.
+Some errors have detailed explanations: E0191, E0221, E0222.
 For more information about an error, try `rustc --explain E0191`.
diff --git a/src/test/ui/associated-types/associated-types-incomplete-object.rs b/src/test/ui/associated-types/associated-types-incomplete-object.rs
index 4993b131215..4627dfd2b78 100644
--- a/src/test/ui/associated-types/associated-types-incomplete-object.rs
+++ b/src/test/ui/associated-types/associated-types-incomplete-object.rs
@@ -21,11 +21,11 @@ pub fn main() {
     let a = &42isize as &dyn Foo<A=usize, B=char>;
 
     let b = &42isize as &dyn Foo<A=usize>;
-    //~^ ERROR the value of the associated type `B` (from the trait `Foo`) must be specified
+    //~^ ERROR the value of the associated type `B` (from trait `Foo`) must be specified
 
     let c = &42isize as &dyn Foo<B=char>;
-    //~^ ERROR the value of the associated type `A` (from the trait `Foo`) must be specified
+    //~^ ERROR the value of the associated type `A` (from trait `Foo`) must be specified
 
     let d = &42isize as &dyn Foo;
-    //~^ ERROR the value of the associated types `A` (from the trait `Foo`), `B` (from the trait
+    //~^ ERROR the value of the associated types `A` (from trait `Foo`), `B` (from trait
 }
diff --git a/src/test/ui/associated-types/associated-types-incomplete-object.stderr b/src/test/ui/associated-types/associated-types-incomplete-object.stderr
index b4c08f4a4cc..24732271c42 100644
--- a/src/test/ui/associated-types/associated-types-incomplete-object.stderr
+++ b/src/test/ui/associated-types/associated-types-incomplete-object.stderr
@@ -1,23 +1,23 @@
-error[E0191]: the value of the associated type `B` (from the trait `Foo`) must be specified
-  --> $DIR/associated-types-incomplete-object.rs:23:26
+error[E0191]: the value of the associated type `B` (from trait `Foo`) must be specified
+  --> $DIR/associated-types-incomplete-object.rs:23:30
    |
 LL |     type B;
    |     ------- `B` defined here
 ...
 LL |     let b = &42isize as &dyn Foo<A=usize>;
-   |                          ^^^^^^^^^^^^^^^^ associated type `B` must be specified
+   |                              ^^^^^^^^^^^^ help: specify the associated type: `Foo<A=usize, B = Type>`
 
-error[E0191]: the value of the associated type `A` (from the trait `Foo`) must be specified
-  --> $DIR/associated-types-incomplete-object.rs:26:26
+error[E0191]: the value of the associated type `A` (from trait `Foo`) must be specified
+  --> $DIR/associated-types-incomplete-object.rs:26:30
    |
 LL |     type A;
    |     ------- `A` defined here
 ...
 LL |     let c = &42isize as &dyn Foo<B=char>;
-   |                          ^^^^^^^^^^^^^^^ associated type `A` must be specified
+   |                              ^^^^^^^^^^^ help: specify the associated type: `Foo<B=char, A = Type>`
 
-error[E0191]: the value of the associated types `A` (from the trait `Foo`), `B` (from the trait `Foo`) must be specified
-  --> $DIR/associated-types-incomplete-object.rs:29:26
+error[E0191]: the value of the associated types `A` (from trait `Foo`), `B` (from trait `Foo`) must be specified
+  --> $DIR/associated-types-incomplete-object.rs:29:30
    |
 LL |     type A;
    |     ------- `A` defined here
@@ -25,10 +25,7 @@ LL |     type B;
    |     ------- `B` defined here
 ...
 LL |     let d = &42isize as &dyn Foo;
-   |                          ^^^^^^^
-   |                          |
-   |                          associated type `A` must be specified
-   |                          associated type `B` must be specified
+   |                              ^^^ help: specify the associated types: `Foo<A = Type, B = Type>`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/associated-types/associated-types-path-1.stderr b/src/test/ui/associated-types/associated-types-path-1.stderr
index a10cf7f890c..60db7749082 100644
--- a/src/test/ui/associated-types/associated-types-path-1.stderr
+++ b/src/test/ui/associated-types/associated-types-path-1.stderr
@@ -1,8 +1,8 @@
 error[E0220]: associated type `A` not found for `T`
-  --> $DIR/associated-types-path-1.rs:10:23
+  --> $DIR/associated-types-path-1.rs:10:26
    |
 LL | pub fn f1<T>(a: T, x: T::A) {}
-   |                       ^^^^ associated type `A` not found
+   |                          ^ associated type `A` not found
 
 error[E0221]: ambiguous associated type `A` in bounds of `T`
   --> $DIR/associated-types-path-1.rs:11:34
@@ -15,6 +15,15 @@ LL |     type A;
 ...
 LL | pub fn f2<T: Foo + Bar>(a: T, x: T::A) {}
    |                                  ^^^^ ambiguous associated type `A`
+   |
+help: use fully qualified syntax to disambiguate
+   |
+LL | pub fn f2<T: Foo + Bar>(a: T, x: <T as Bar>::A) {}
+   |                                  ^^^^^^^^^^^^^
+help: use fully qualified syntax to disambiguate
+   |
+LL | pub fn f2<T: Foo + Bar>(a: T, x: <T as Foo>::A) {}
+   |                                  ^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/associated-types/missing-associated-types.rs b/src/test/ui/associated-types/missing-associated-types.rs
new file mode 100644
index 00000000000..3c8410e39bd
--- /dev/null
+++ b/src/test/ui/associated-types/missing-associated-types.rs
@@ -0,0 +1,27 @@
+use std::ops::{Add, Sub, Mul, Div};
+trait X<Rhs>: Mul<Rhs> + Div<Rhs> {}
+trait Y<Rhs>: Div<Rhs, Output = Rhs> {
+    type A;
+}
+trait Z<Rhs>: Div<Rhs> {
+    type A;
+    type B;
+}
+trait Fine<Rhs>: Div<Rhs, Output = Rhs> {}
+
+type Foo<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Y<Rhs>;
+//~^ ERROR only auto traits can be used as additional traits in a trait object
+//~| ERROR the value of the associated types
+type Bar<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs>;
+//~^ ERROR only auto traits can be used as additional traits in a trait object
+//~| ERROR the value of the associated types
+type Baz<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Y<Rhs>;
+//~^ ERROR only auto traits can be used as additional traits in a trait object
+//~| ERROR the value of the associated types
+type Bat<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Fine<Rhs>;
+//~^ ERROR only auto traits can be used as additional traits in a trait object
+//~| ERROR the value of the associated types
+type Bal<Rhs> = dyn X<Rhs>;
+//~^ ERROR the value of the associated types
+
+fn main() {}
diff --git a/src/test/ui/associated-types/missing-associated-types.stderr b/src/test/ui/associated-types/missing-associated-types.stderr
new file mode 100644
index 00000000000..f9951170acd
--- /dev/null
+++ b/src/test/ui/associated-types/missing-associated-types.stderr
@@ -0,0 +1,129 @@
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/missing-associated-types.rs:12:32
+   |
+LL | type Foo<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Y<Rhs>;
+   |                     --------   ^^^^^^^^
+   |                     |          |
+   |                     |          additional non-auto trait
+   |                     |          trait alias used in trait object type (additional use)
+   |                     first non-auto trait
+   |                     trait alias used in trait object type (first use)
+
+error[E0191]: the value of the associated types `A` (from trait `Y`), `Output` (from trait `std::ops::Add`), `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Sub`) must be specified
+  --> $DIR/missing-associated-types.rs:12:21
+   |
+LL |     type A;
+   |     ------- `A` defined here
+...
+LL | type Foo<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Y<Rhs>;
+   |                     ^^^^^^^^   ^^^^^^^^   ^^^^^^   ^^^^^^ associated type `A` must be specified
+   |                     |          |          |
+   |                     |          |          associated type `Output` must be specified
+   |                     |          associated type `Output` must be specified
+   |                     associated type `Output` must be specified
+   |
+help: specify the associated types
+   |
+LL | type Foo<Rhs> = dyn Add<Rhs, Output = Type> + Sub<Rhs, Output = Type> + X<Rhs, Output = Type> + Y<Rhs, A = Type>;
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/missing-associated-types.rs:15:32
+   |
+LL | type Bar<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs>;
+   |                     --------   ^^^^^^^^
+   |                     |          |
+   |                     |          additional non-auto trait
+   |                     |          trait alias used in trait object type (additional use)
+   |                     first non-auto trait
+   |                     trait alias used in trait object type (first use)
+
+error[E0191]: the value of the associated types `A` (from trait `Z`), `B` (from trait `Z`), `Output` (from trait `std::ops::Add`), `Output` (from trait `std::ops::Div`), `Output` (from trait `std::ops::Div`), `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Sub`) must be specified
+  --> $DIR/missing-associated-types.rs:15:21
+   |
+LL |     type A;
+   |     ------- `A` defined here
+LL |     type B;
+   |     ------- `B` defined here
+...
+LL | type Bar<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs>;
+   |                     ^^^^^^^^   ^^^^^^^^   ^^^^^^   ^^^^^^ associated types `A`, `B`, `Output` must be specified
+   |                     |          |          |
+   |                     |          |          associated types `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Div`) must be specified
+   |                     |          associated type `Output` must be specified
+   |                     associated type `Output` must be specified
+   |
+help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types
+  --> $DIR/missing-associated-types.rs:15:43
+   |
+LL | type Bar<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs>;
+   |                                           ^^^^^^
+help: specify the associated types
+   |
+LL | type Bar<Rhs> = dyn Add<Rhs, Output = Type> + Sub<Rhs, Output = Type> + X<Rhs> + Z<Rhs, A = Type, B = Type, Output = Type>;
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^^^            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/missing-associated-types.rs:18:32
+   |
+LL | type Baz<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Y<Rhs>;
+   |                     --------   ^^^^^^^^
+   |                     |          |
+   |                     |          additional non-auto trait
+   |                     |          trait alias used in trait object type (additional use)
+   |                     first non-auto trait
+   |                     trait alias used in trait object type (first use)
+
+error[E0191]: the value of the associated types `A` (from trait `Y`), `Output` (from trait `std::ops::Add`), `Output` (from trait `std::ops::Sub`) must be specified
+  --> $DIR/missing-associated-types.rs:18:21
+   |
+LL |     type A;
+   |     ------- `A` defined here
+...
+LL | type Baz<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Y<Rhs>;
+   |                     ^^^^^^^^   ^^^^^^^^   ^^^^^^ associated type `A` must be specified
+   |                     |          |
+   |                     |          associated type `Output` must be specified
+   |                     associated type `Output` must be specified
+   |
+help: specify the associated types
+   |
+LL | type Baz<Rhs> = dyn Add<Rhs, Output = Type> + Sub<Rhs, Output = Type> + Y<Rhs, A = Type>;
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/missing-associated-types.rs:21:32
+   |
+LL | type Bat<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Fine<Rhs>;
+   |                     --------   ^^^^^^^^
+   |                     |          |
+   |                     |          additional non-auto trait
+   |                     |          trait alias used in trait object type (additional use)
+   |                     first non-auto trait
+   |                     trait alias used in trait object type (first use)
+
+error[E0191]: the value of the associated types `Output` (from trait `std::ops::Add`), `Output` (from trait `std::ops::Sub`) must be specified
+  --> $DIR/missing-associated-types.rs:21:21
+   |
+LL | type Bat<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Fine<Rhs>;
+   |                     ^^^^^^^^   ^^^^^^^^ associated type `Output` must be specified
+   |                     |
+   |                     associated type `Output` must be specified
+   |
+help: specify the associated types
+   |
+LL | type Bat<Rhs> = dyn Add<Rhs, Output = Type> + Sub<Rhs, Output = Type> + Fine<Rhs>;
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0191]: the value of the associated types `Output` (from trait `std::ops::Div`), `Output` (from trait `std::ops::Mul`) must be specified
+  --> $DIR/missing-associated-types.rs:24:21
+   |
+LL | type Bal<Rhs> = dyn X<Rhs>;
+   |                     ^^^^^^ associated types `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Div`) must be specified
+   |
+   = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0191, E0225.
+For more information about an error, try `rustc --explain E0191`.
diff --git a/src/test/ui/error-codes/E0191.stderr b/src/test/ui/error-codes/E0191.stderr
index 92fa85bca0e..d69a14916e1 100644
--- a/src/test/ui/error-codes/E0191.stderr
+++ b/src/test/ui/error-codes/E0191.stderr
@@ -1,11 +1,11 @@
-error[E0191]: the value of the associated type `Bar` (from the trait `Trait`) must be specified
-  --> $DIR/E0191.rs:5:12
+error[E0191]: the value of the associated type `Bar` (from trait `Trait`) must be specified
+  --> $DIR/E0191.rs:5:16
    |
 LL |     type Bar;
    |     --------- `Bar` defined here
 ...
 LL | type Foo = dyn Trait;
-   |            ^^^^^^^^^ associated type `Bar` must be specified
+   |                ^^^^^ help: specify the associated type: `Trait<Bar = Type>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0220.stderr b/src/test/ui/error-codes/E0220.stderr
index 5da302748cd..4fa83d8bf6e 100644
--- a/src/test/ui/error-codes/E0220.stderr
+++ b/src/test/ui/error-codes/E0220.stderr
@@ -2,16 +2,16 @@ error[E0220]: associated type `F` not found for `Trait`
   --> $DIR/E0220.rs:5:22
    |
 LL | type Foo = dyn Trait<F=i32>;
-   |                      ^^^^^ associated type `F` not found
+   |                      ^ associated type `F` not found
 
-error[E0191]: the value of the associated type `Bar` (from the trait `Trait`) must be specified
-  --> $DIR/E0220.rs:5:12
+error[E0191]: the value of the associated type `Bar` (from trait `Trait`) must be specified
+  --> $DIR/E0220.rs:5:16
    |
 LL |     type Bar;
    |     --------- `Bar` defined here
 ...
 LL | type Foo = dyn Trait<F=i32>;
-   |            ^^^^^^^^^^^^^^^^ associated type `Bar` must be specified
+   |                ^^^^^^^^^^^^ help: specify the associated type: `Trait<F=i32, Bar = Type>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/error-codes/E0221.stderr b/src/test/ui/error-codes/E0221.stderr
index 043f0c68bbc..0b4819143ce 100644
--- a/src/test/ui/error-codes/E0221.stderr
+++ b/src/test/ui/error-codes/E0221.stderr
@@ -9,6 +9,15 @@ LL |     type A: T2;
 LL |     fn do_something() {
 LL |         let _: Self::A;
    |                ^^^^^^^ ambiguous associated type `A`
+   |
+help: use fully qualified syntax to disambiguate
+   |
+LL |         let _: <Self as Foo>::A;
+   |                ^^^^^^^^^^^^^^^^
+help: use fully qualified syntax to disambiguate
+   |
+LL |         let _: <Self as Bar>::A;
+   |                ^^^^^^^^^^^^^^^^
 
 error[E0221]: ambiguous associated type `Err` in bounds of `Self`
   --> $DIR/E0221.rs:21:16
@@ -17,13 +26,12 @@ LL |     type Err: T3;
    |     ------------- ambiguous `Err` from `My`
 LL |     fn test() {
 LL |         let _: Self::Err;
-   |                ^^^^^^^^^ ambiguous associated type `Err`
-   |
-note: associated type `Self` could derive from `std::str::FromStr`
-  --> $DIR/E0221.rs:21:16
-   |
-LL |         let _: Self::Err;
    |                ^^^^^^^^^
+   |                |
+   |                ambiguous associated type `Err`
+   |                help: use fully qualified syntax to disambiguate: `<Self as My>::Err`
+   |
+   = note: associated type `Self` could derive from `std::str::FromStr`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/error-codes/E0393.stderr b/src/test/ui/error-codes/E0393.stderr
index 543e3213633..7771bacc9ed 100644
--- a/src/test/ui/error-codes/E0393.stderr
+++ b/src/test/ui/error-codes/E0393.stderr
@@ -1,8 +1,11 @@
 error[E0393]: the type parameter `T` must be explicitly specified
   --> $DIR/E0393.rs:3:47
    |
+LL | trait A<T=Self> {}
+   | ------------------ type parameter `T` must be specified for this
+LL | 
 LL | fn together_we_will_rule_the_galaxy(son: &dyn A) {}
-   |                                               ^ missing reference to `T`
+   |                                               ^ help: set the type parameter to the desired type: `A<T>`
    |
    = note: because of the default `Self` reference, type parameters must be specified on object types
 
diff --git a/src/test/ui/error-codes/E0719.stderr b/src/test/ui/error-codes/E0719.stderr
index c5b9a71c659..a046fbfc3d0 100644
--- a/src/test/ui/error-codes/E0719.stderr
+++ b/src/test/ui/error-codes/E0719.stderr
@@ -1,4 +1,4 @@
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/E0719.rs:1:33
    |
 LL | trait Foo: Iterator<Item = i32, Item = i32> {}
@@ -6,7 +6,7 @@ LL | trait Foo: Iterator<Item = i32, Item = i32> {}
    |                     |
    |                     `Item` bound here first
 
-error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
   --> $DIR/E0719.rs:6:42
    |
 LL | fn test() -> Box<dyn Iterator<Item = (), Item = Unit>> {
diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr
index 657bf13c873..4addd16649e 100644
--- a/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr
+++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr
@@ -34,11 +34,11 @@ LL |     extern "rust-call" fn call_once(&self, args: ()) -> () {}
    = note: for more information, see https://github.com/rust-lang/rust/issues/29625
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead
+error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change
   --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:9:6
    |
 LL | impl Fn<()> for Foo {
-   |      ^^^^^^
+   |      ^^^^^^ help: use parenthetical notation instead: `Fn() -> ()`
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/29625
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
@@ -49,20 +49,20 @@ error[E0229]: associated type bindings are not allowed here
 LL | impl FnOnce() for Foo1 {
    |      ^^^^^^^^ associated type not allowed here
 
-error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead
+error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change
   --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:21:6
    |
 LL | impl FnMut<()> for Bar {
-   |      ^^^^^^^^^
+   |      ^^^^^^^^^ help: use parenthetical notation instead: `FnMut() -> ()`
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/29625
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead
+error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change
   --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:27:6
    |
 LL | impl FnOnce<()> for Baz {
-   |      ^^^^^^^^^^
+   |      ^^^^^^^^^^ help: use parenthetical notation instead: `FnOnce() -> ()`
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/29625
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr
index f343a42eb8f..005ff06e688 100644
--- a/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr
+++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr
@@ -7,11 +7,11 @@ LL |     extern "rust-call" fn call_once(self, (a, b): (u32, u32)) -> u32 {
    = note: for more information, see https://github.com/rust-lang/rust/issues/29625
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead
+error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change
   --> $DIR/feature-gate-unboxed-closures.rs:5:6
    |
 LL | impl FnOnce<(u32, u32)> for Test {
-   |      ^^^^^^^^^^^^^^^^^^
+   |      ^^^^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `FnOnce(u32, u32) -> ()`
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/29625
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
diff --git a/src/test/ui/issues/issue-19482.rs b/src/test/ui/issues/issue-19482.rs
index 9e4b77d87f8..3f3c5de9b14 100644
--- a/src/test/ui/issues/issue-19482.rs
+++ b/src/test/ui/issues/issue-19482.rs
@@ -8,6 +8,6 @@ trait Foo {
 }
 
 fn bar(x: &dyn Foo) {}
-//~^ ERROR the associated type `A` (from the trait `Foo`) must be specified
+//~^ ERROR the associated type `A` (from trait `Foo`) must be specified
 
 pub fn main() {}
diff --git a/src/test/ui/issues/issue-19482.stderr b/src/test/ui/issues/issue-19482.stderr
index f1e5419c712..42a5a015969 100644
--- a/src/test/ui/issues/issue-19482.stderr
+++ b/src/test/ui/issues/issue-19482.stderr
@@ -1,11 +1,11 @@
-error[E0191]: the value of the associated type `A` (from the trait `Foo`) must be specified
-  --> $DIR/issue-19482.rs:10:12
+error[E0191]: the value of the associated type `A` (from trait `Foo`) must be specified
+  --> $DIR/issue-19482.rs:10:16
    |
 LL |     type A;
    |     ------- `A` defined here
 ...
 LL | fn bar(x: &dyn Foo) {}
-   |            ^^^^^^^ associated type `A` must be specified
+   |                ^^^ help: specify the associated type: `Foo<A = Type>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-21950.rs b/src/test/ui/issues/issue-21950.rs
index 0bc87824cce..72a98bd8ddd 100644
--- a/src/test/ui/issues/issue-21950.rs
+++ b/src/test/ui/issues/issue-21950.rs
@@ -1,8 +1,13 @@
-use std::ops::Add;
+trait Add<Rhs=Self> {
+    type Output;
+}
+
+impl Add for i32 {
+    type Output = i32;
+}
 
 fn main() {
-    let x = &10 as
-            &dyn Add;
-            //~^ ERROR E0393
-            //~| ERROR E0191
+    let x = &10 as &dyn Add;
+    //~^ ERROR E0393
+    //~| ERROR E0191
 }
diff --git a/src/test/ui/issues/issue-21950.stderr b/src/test/ui/issues/issue-21950.stderr
index 9be7b052da3..93c2444f884 100644
--- a/src/test/ui/issues/issue-21950.stderr
+++ b/src/test/ui/issues/issue-21950.stderr
@@ -1,16 +1,24 @@
 error[E0393]: the type parameter `Rhs` must be explicitly specified
-  --> $DIR/issue-21950.rs:5:18
+  --> $DIR/issue-21950.rs:10:25
    |
-LL |             &dyn Add;
-   |                  ^^^ missing reference to `Rhs`
+LL | / trait Add<Rhs=Self> {
+LL | |     type Output;
+LL | | }
+   | |_- type parameter `Rhs` must be specified for this
+...
+LL |       let x = &10 as &dyn Add;
+   |                           ^^^ help: set the type parameter to the desired type: `Add<Rhs>`
    |
    = note: because of the default `Self` reference, type parameters must be specified on object types
 
-error[E0191]: the value of the associated type `Output` (from the trait `std::ops::Add`) must be specified
-  --> $DIR/issue-21950.rs:5:14
+error[E0191]: the value of the associated type `Output` (from trait `Add`) must be specified
+  --> $DIR/issue-21950.rs:10:25
    |
-LL |             &dyn Add;
-   |              ^^^^^^^ associated type `Output` must be specified
+LL |     type Output;
+   |     ------------ `Output` defined here
+...
+LL |     let x = &10 as &dyn Add;
+   |                         ^^^ help: specify the associated type: `Add<Output = Type>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-22370.stderr b/src/test/ui/issues/issue-22370.stderr
index 3ce164e9548..950c12ef7a2 100644
--- a/src/test/ui/issues/issue-22370.stderr
+++ b/src/test/ui/issues/issue-22370.stderr
@@ -1,8 +1,11 @@
 error[E0393]: the type parameter `T` must be explicitly specified
   --> $DIR/issue-22370.rs:3:14
    |
+LL | trait A<T=Self> {}
+   | ------------------ type parameter `T` must be specified for this
+LL | 
 LL | fn f(a: &dyn A) {}
-   |              ^ missing reference to `T`
+   |              ^ help: set the type parameter to the desired type: `A<T>`
    |
    = note: because of the default `Self` reference, type parameters must be specified on object types
 
diff --git a/src/test/ui/issues/issue-22434.rs b/src/test/ui/issues/issue-22434.rs
index 3e800a2b61d..34057b46ecd 100644
--- a/src/test/ui/issues/issue-22434.rs
+++ b/src/test/ui/issues/issue-22434.rs
@@ -3,6 +3,6 @@ pub trait Foo {
 }
 
 type I<'a> = &'a (dyn Foo + 'a);
-//~^ ERROR the value of the associated type `A` (from the trait `Foo`) must be specified
+//~^ ERROR the value of the associated type `A` (from trait `Foo`) must be specified
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-22434.stderr b/src/test/ui/issues/issue-22434.stderr
index eb78c4fc311..79b9d85610b 100644
--- a/src/test/ui/issues/issue-22434.stderr
+++ b/src/test/ui/issues/issue-22434.stderr
@@ -1,11 +1,11 @@
-error[E0191]: the value of the associated type `A` (from the trait `Foo`) must be specified
-  --> $DIR/issue-22434.rs:5:19
+error[E0191]: the value of the associated type `A` (from trait `Foo`) must be specified
+  --> $DIR/issue-22434.rs:5:23
    |
 LL |     type A;
    |     ------- `A` defined here
 ...
 LL | type I<'a> = &'a (dyn Foo + 'a);
-   |                   ^^^^^^^^^^^^ associated type `A` must be specified
+   |                       ^^^ help: specify the associated type: `Foo<A = Type>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-22560.rs b/src/test/ui/issues/issue-22560.rs
index acee99dbedc..44be8817b08 100644
--- a/src/test/ui/issues/issue-22560.rs
+++ b/src/test/ui/issues/issue-22560.rs
@@ -1,10 +1,15 @@
-use std::ops::{Add, Sub};
+trait Add<Rhs=Self> {
+    type Output;
+}
 
-type Test = dyn Add +
-            //~^ ERROR E0393
-            //~| ERROR E0191
-            Sub;
-            //~^ ERROR E0393
-            //~| ERROR E0225
+trait Sub<Rhs=Self> {
+    type Output;
+}
+
+type Test = dyn Add + Sub;
+//~^ ERROR E0393
+//~| ERROR E0191
+//~| ERROR E0393
+//~| ERROR E0225
 
 fn main() { }
diff --git a/src/test/ui/issues/issue-22560.stderr b/src/test/ui/issues/issue-22560.stderr
index 5b58adb197c..e5e50ddd155 100644
--- a/src/test/ui/issues/issue-22560.stderr
+++ b/src/test/ui/issues/issue-22560.stderr
@@ -1,48 +1,58 @@
 error[E0393]: the type parameter `Rhs` must be explicitly specified
-  --> $DIR/issue-22560.rs:6:13
+  --> $DIR/issue-22560.rs:9:23
    |
-LL |             Sub;
-   |             ^^^ missing reference to `Rhs`
+LL | / trait Sub<Rhs=Self> {
+LL | |     type Output;
+LL | | }
+   | |_- type parameter `Rhs` must be specified for this
+LL | 
+LL |   type Test = dyn Add + Sub;
+   |                         ^^^ help: set the type parameter to the desired type: `Sub<Rhs>`
    |
    = note: because of the default `Self` reference, type parameters must be specified on object types
 
 error[E0393]: the type parameter `Rhs` must be explicitly specified
-  --> $DIR/issue-22560.rs:3:17
+  --> $DIR/issue-22560.rs:9:17
    |
-LL | type Test = dyn Add +
-   |                 ^^^ missing reference to `Rhs`
+LL | / trait Add<Rhs=Self> {
+LL | |     type Output;
+LL | | }
+   | |_- type parameter `Rhs` must be specified for this
+...
+LL |   type Test = dyn Add + Sub;
+   |                   ^^^ help: set the type parameter to the desired type: `Add<Rhs>`
    |
    = note: because of the default `Self` reference, type parameters must be specified on object types
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/issue-22560.rs:6:13
+  --> $DIR/issue-22560.rs:9:23
    |
-LL | type Test = dyn Add +
-   |                 ---
-   |                 |
+LL | type Test = dyn Add + Sub;
+   |                 ---   ^^^
+   |                 |     |
+   |                 |     additional non-auto trait
+   |                 |     trait alias used in trait object type (additional use)
    |                 first non-auto trait
    |                 trait alias used in trait object type (first use)
-...
-LL |             Sub;
-   |             ^^^
-   |             |
-   |             additional non-auto trait
-   |             trait alias used in trait object type (additional use)
 
-error[E0191]: the value of the associated types `Output` (from the trait `std::ops::Add`), `Output` (from the trait `std::ops::Sub`) must be specified
-  --> $DIR/issue-22560.rs:3:13
-   |
-LL |   type Test = dyn Add +
-   |  _____________^
-   | |_____________|
-   | |
-LL | |
-LL | |
-LL | |             Sub;
-   | |               ^
-   | |_______________|
-   | |_______________associated type `Output` must be specified
+error[E0191]: the value of the associated types `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified
+  --> $DIR/issue-22560.rs:9:17
+   |
+LL |     type Output;
+   |     ------------ `Output` defined here
+...
+LL |     type Output;
+   |     ------------ `Output` defined here
+...
+LL | type Test = dyn Add + Sub;
+   |                 ^^^   ^^^ associated type `Output` must be specified
+   |                 |
    |                 associated type `Output` must be specified
+   |
+help: specify the associated types
+   |
+LL | type Test = dyn Add<Output = Type> + Sub<Output = Type>;
+   |                 ^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/issues/issue-23024.rs b/src/test/ui/issues/issue-23024.rs
index 2638e15f0ea..63675368162 100644
--- a/src/test/ui/issues/issue-23024.rs
+++ b/src/test/ui/issues/issue-23024.rs
@@ -9,5 +9,5 @@ fn main()
     println!("{:?}",(vfnfer[0] as dyn Fn)(3));
     //~^ ERROR the precise format of `Fn`-family traits'
     //~| ERROR wrong number of type arguments: expected 1, found 0 [E0107]
-    //~| ERROR the value of the associated type `Output` (from the trait `std::ops::FnOnce`)
+    //~| ERROR the value of the associated type `Output` (from trait `std::ops::FnOnce`)
 }
diff --git a/src/test/ui/issues/issue-23024.stderr b/src/test/ui/issues/issue-23024.stderr
index 43561938ef1..1c6dd28ce53 100644
--- a/src/test/ui/issues/issue-23024.stderr
+++ b/src/test/ui/issues/issue-23024.stderr
@@ -1,8 +1,8 @@
-error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead
+error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change
   --> $DIR/issue-23024.rs:9:39
    |
 LL |     println!("{:?}",(vfnfer[0] as dyn Fn)(3));
-   |                                       ^^
+   |                                       ^^ help: use parenthetical notation instead: `Fn() -> ()`
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/29625
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
@@ -13,11 +13,11 @@ error[E0107]: wrong number of type arguments: expected 1, found 0
 LL |     println!("{:?}",(vfnfer[0] as dyn Fn)(3));
    |                                       ^^ expected 1 type argument
 
-error[E0191]: the value of the associated type `Output` (from the trait `std::ops::FnOnce`) must be specified
-  --> $DIR/issue-23024.rs:9:35
+error[E0191]: the value of the associated type `Output` (from trait `std::ops::FnOnce`) must be specified
+  --> $DIR/issue-23024.rs:9:39
    |
 LL |     println!("{:?}",(vfnfer[0] as dyn Fn)(3));
-   |                                   ^^^^^^ associated type `Output` must be specified
+   |                                       ^^ help: specify the associated type: `Fn<Output = Type>`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/issues/issue-23595-2.stderr b/src/test/ui/issues/issue-23595-2.stderr
index f1004db0b09..dded673f6ee 100644
--- a/src/test/ui/issues/issue-23595-2.stderr
+++ b/src/test/ui/issues/issue-23595-2.stderr
@@ -1,8 +1,8 @@
 error[E0220]: associated type `anything_here_kills_it` not found for `Self`
-  --> $DIR/issue-23595-2.rs:6:16
+  --> $DIR/issue-23595-2.rs:6:22
    |
 LL |     type B = C<Self::anything_here_kills_it>;
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated type `anything_here_kills_it` not found
+   |                      ^^^^^^^^^^^^^^^^^^^^^^ associated type `anything_here_kills_it` not found
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-28344.stderr b/src/test/ui/issues/issue-28344.stderr
index 34ce2358a0a..e315317c98a 100644
--- a/src/test/ui/issues/issue-28344.stderr
+++ b/src/test/ui/issues/issue-28344.stderr
@@ -1,8 +1,8 @@
-error[E0191]: the value of the associated type `Output` (from the trait `std::ops::BitXor`) must be specified
+error[E0191]: the value of the associated type `Output` (from trait `std::ops::BitXor`) must be specified
   --> $DIR/issue-28344.rs:4:17
    |
 LL |     let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
-   |                 ^^^^^^^^^^^^^ associated type `Output` must be specified
+   |                 ^^^^^^ help: specify the associated type: `BitXor<Output = Type>`
 
 error[E0599]: no function or associated item named `bitor` found for type `dyn std::ops::BitXor<_>` in the current scope
   --> $DIR/issue-28344.rs:4:25
@@ -13,11 +13,11 @@ LL |     let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
    |                         function or associated item not found in `dyn std::ops::BitXor<_>`
    |                         help: there is a method with a similar name: `bitxor`
 
-error[E0191]: the value of the associated type `Output` (from the trait `std::ops::BitXor`) must be specified
+error[E0191]: the value of the associated type `Output` (from trait `std::ops::BitXor`) must be specified
   --> $DIR/issue-28344.rs:8:13
    |
 LL |     let g = BitXor::bitor;
-   |             ^^^^^^^^^^^^^ associated type `Output` must be specified
+   |             ^^^^^^ help: specify the associated type: `BitXor<Output = Type>`
 
 error[E0599]: no function or associated item named `bitor` found for type `dyn std::ops::BitXor<_>` in the current scope
   --> $DIR/issue-28344.rs:8:21
diff --git a/src/test/ui/issues/issue-39211.stderr b/src/test/ui/issues/issue-39211.stderr
index ea850ea57d5..c14c663e5a1 100644
--- a/src/test/ui/issues/issue-39211.stderr
+++ b/src/test/ui/issues/issue-39211.stderr
@@ -1,8 +1,8 @@
 error[E0220]: associated type `Row` not found for `M`
-  --> $DIR/issue-39211.rs:11:17
+  --> $DIR/issue-39211.rs:11:20
    |
 LL |     let a = [3; M::Row::DIM];
-   |                 ^^^^^^^^^^^ associated type `Row` not found
+   |                    ^^^ associated type `Row` not found
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-59029-1.stderr b/src/test/ui/issues/issue-59029-1.stderr
index ed1d98c40d1..fb1de9759c5 100644
--- a/src/test/ui/issues/issue-59029-1.stderr
+++ b/src/test/ui/issues/issue-59029-1.stderr
@@ -1,8 +1,8 @@
 error[E0220]: associated type `Res` not found for `Self`
-  --> $DIR/issue-59029-1.rs:5:46
+  --> $DIR/issue-59029-1.rs:5:52
    |
 LL | trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>;
-   |                                              ^^^^^^^^^ associated type `Res` not found
+   |                                                    ^^^ associated type `Res` not found
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/span/type-binding.stderr b/src/test/ui/span/type-binding.stderr
index c3e95455532..f6989933553 100644
--- a/src/test/ui/span/type-binding.stderr
+++ b/src/test/ui/span/type-binding.stderr
@@ -2,7 +2,7 @@ error[E0220]: associated type `Trget` not found for `std::ops::Deref`
   --> $DIR/type-binding.rs:6:20
    |
 LL | fn homura<T: Deref<Trget = i32>>(_: T) {}
-   |                    ^^^^^^^^^^^ help: there is an associated type with a similar name: `Target`
+   |                    ^^^^^ help: there is an associated type with a similar name: `Target`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr b/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr
index 098d76a5c48..58a73187fb1 100644
--- a/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr
+++ b/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr
@@ -6,8 +6,8 @@ LL |     i: Box<dyn T<usize, usize, usize, usize, B=usize>>,
    |                                |
    |                                unexpected type argument
 
-error[E0191]: the value of the associated types `A` (from the trait `T`), `C` (from the trait `T`) must be specified
-  --> $DIR/use-type-argument-instead-of-assoc-type.rs:7:12
+error[E0191]: the value of the associated types `A` (from trait `T`), `C` (from trait `T`) must be specified
+  --> $DIR/use-type-argument-instead-of-assoc-type.rs:7:16
    |
 LL |     type A;
    |     ------- `A` defined here
@@ -16,12 +16,9 @@ LL |     type C;
    |     ------- `C` defined here
 ...
 LL |     i: Box<dyn T<usize, usize, usize, usize, B=usize>>,
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |            |
-   |            associated type `A` must be specified
-   |            associated type `C` must be specified
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated types `A`, `C` must be specified
    |
-help: if you meant to specify the associated types, write
+help: specify the associated types
    |
 LL |     i: Box<dyn T<usize, usize, A = usize, C = usize, B=usize>>,
    |                                ^^^^^^^^^  ^^^^^^^^^
diff --git a/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr b/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr
index 9a9b9177030..5551b1303b9 100644
--- a/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr
+++ b/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr
@@ -6,11 +6,11 @@ LL |     let _: &dyn EqAlias = &123;
    |
    = note: the trait cannot use `Self` as a type parameter in the supertraits or where-clauses
 
-error[E0191]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified
-  --> $DIR/trait-alias-object-fail.rs:9:13
+error[E0191]: the value of the associated type `Item` (from trait `std::iter::Iterator`) must be specified
+  --> $DIR/trait-alias-object-fail.rs:9:17
    |
 LL |     let _: &dyn IteratorAlias = &vec![123].into_iter();
-   |             ^^^^^^^^^^^^^^^^^ associated type `Item` must be specified
+   |                 ^^^^^^^^^^^^^ help: specify the associated type: `IteratorAlias<Item = Type>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/traits/trait-object-with-self-in-projection-output-bad.rs b/src/test/ui/traits/trait-object-with-self-in-projection-output-bad.rs
index 766bd147431..f34fa80a0ce 100644
--- a/src/test/ui/traits/trait-object-with-self-in-projection-output-bad.rs
+++ b/src/test/ui/traits/trait-object-with-self-in-projection-output-bad.rs
@@ -43,8 +43,8 @@ impl NormalizableHelper for u32
 
 fn main() {
     let _x: Box<dyn Helper<Target=i32>> = Box::new(2u32);
-    //~^ ERROR the value of the associated type `Output` (from the trait `Base`) must be specified
+    //~^ ERROR the value of the associated type `Output` (from trait `Base`) must be specified
 
     let _y: Box<dyn NormalizableHelper<Target=i32>> = Box::new(2u32);
-    //~^ ERROR the value of the associated type `Output` (from the trait `Base`) must be specified
+    //~^ ERROR the value of the associated type `Output` (from trait `Base`) must be specified
 }
diff --git a/src/test/ui/traits/trait-object-with-self-in-projection-output-bad.stderr b/src/test/ui/traits/trait-object-with-self-in-projection-output-bad.stderr
index 350f8ea8507..79eb27e101a 100644
--- a/src/test/ui/traits/trait-object-with-self-in-projection-output-bad.stderr
+++ b/src/test/ui/traits/trait-object-with-self-in-projection-output-bad.stderr
@@ -1,20 +1,20 @@
-error[E0191]: the value of the associated type `Output` (from the trait `Base`) must be specified
-  --> $DIR/trait-object-with-self-in-projection-output-bad.rs:45:17
+error[E0191]: the value of the associated type `Output` (from trait `Base`) must be specified
+  --> $DIR/trait-object-with-self-in-projection-output-bad.rs:45:21
    |
 LL |     type Output;
    |     ------------ `Output` defined here
 ...
 LL |     let _x: Box<dyn Helper<Target=i32>> = Box::new(2u32);
-   |                 ^^^^^^^^^^^^^^^^^^^^^^ associated type `Output` must be specified
+   |                     ^^^^^^^^^^^^^^^^^^ help: specify the associated type: `Helper<Target=i32, Output = Type>`
 
-error[E0191]: the value of the associated type `Output` (from the trait `Base`) must be specified
-  --> $DIR/trait-object-with-self-in-projection-output-bad.rs:48:17
+error[E0191]: the value of the associated type `Output` (from trait `Base`) must be specified
+  --> $DIR/trait-object-with-self-in-projection-output-bad.rs:48:21
    |
 LL |     type Output;
    |     ------------ `Output` defined here
 ...
 LL |     let _y: Box<dyn NormalizableHelper<Target=i32>> = Box::new(2u32);
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated type `Output` must be specified
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: specify the associated type: `NormalizableHelper<Target=i32, Output = Type>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/type-alias-impl-trait/not_well_formed.stderr b/src/test/ui/type-alias-impl-trait/not_well_formed.stderr
index d374d6d33ee..c2b6f7eae9f 100644
--- a/src/test/ui/type-alias-impl-trait/not_well_formed.stderr
+++ b/src/test/ui/type-alias-impl-trait/not_well_formed.stderr
@@ -1,8 +1,8 @@
 error[E0220]: associated type `Assoc` not found for `V`
-  --> $DIR/not_well_formed.rs:10:26
+  --> $DIR/not_well_formed.rs:10:29
    |
 LL | type Foo<V> = impl Trait<V::Assoc>;
-   |                          ^^^^^^^^ associated type `Assoc` not found
+   |                             ^^^^^ associated type `Assoc` not found
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type/type-parameter-defaults-referencing-Self.stderr b/src/test/ui/type/type-parameter-defaults-referencing-Self.stderr
index 0d6ca9d9dcd..eafd3cf79db 100644
--- a/src/test/ui/type/type-parameter-defaults-referencing-Self.stderr
+++ b/src/test/ui/type/type-parameter-defaults-referencing-Self.stderr
@@ -1,8 +1,13 @@
 error[E0393]: the type parameter `T` must be explicitly specified
   --> $DIR/type-parameter-defaults-referencing-Self.rs:10:16
    |
-LL | fn foo(x: &dyn Foo) { }
-   |                ^^^ missing reference to `T`
+LL | / trait Foo<T=Self> {
+LL | |     fn method(&self);
+LL | | }
+   | |_- type parameter `T` must be specified for this
+LL | 
+LL |   fn foo(x: &dyn Foo) { }
+   |                  ^^^ help: set the type parameter to the desired type: `Foo<T>`
    |
    = note: because of the default `Self` reference, type parameters must be specified on object types
 
diff --git a/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.stderr b/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.stderr
index a76954287e4..7ae8caee6f8 100644
--- a/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.stderr
@@ -2,7 +2,7 @@ error[E0658]: parenthetical notation is only stable when used with `Fn`-family t
   --> $DIR/unboxed-closure-feature-gate.rs:13:20
    |
 LL |     let x: Box<dyn Foo(isize)>;
-   |                    ^^^^^^^^^^
+   |                    ^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/29625
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr
index c116728190f..ba9d984e703 100644
--- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr
@@ -1,17 +1,17 @@
-error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead
+error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change
   --> $DIR/unboxed-closure-sugar-not-used-on-fn.rs:3:17
    |
 LL | fn bar1(x: &dyn Fn<(), Output=()>) {
-   |                 ^^^^^^^^^^^^^^^^^
+   |                 ^^ help: use parenthetical notation instead: `Fn() -> ()`
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/29625
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead
+error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change
   --> $DIR/unboxed-closure-sugar-not-used-on-fn.rs:7:28
    |
 LL | fn bar2<T>(x: &T) where T: Fn<()> {
-   |                            ^^^^^^
+   |                            ^^ help: use parenthetical notation instead: `Fn() -> ()`
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/29625
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.stderr
index e9d51983a7a..b92f054498b 100644
--- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.stderr
@@ -2,7 +2,7 @@ error[E0107]: wrong number of lifetime arguments: expected 1, found 0
   --> $DIR/unboxed-closure-sugar-region.rs:30:51
    |
 LL | fn test2(x: &dyn Foo<(isize,),Output=()>, y: &dyn Foo(isize)) {
-   |                                                   ^^^^^^^^^^ expected 1 lifetime argument
+   |                                                   ^^^ expected 1 lifetime argument
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr
index f42ac38d370..f482098cbff 100644
--- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr
@@ -2,7 +2,7 @@ error[E0107]: wrong number of type arguments: expected 3, found 1
   --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs:5:16
    |
 LL | fn foo(_: &dyn Three())
-   |                ^^^^^^^ expected 3 type arguments
+   |                ^^^^^ expected 3 type arguments
 
 error[E0220]: associated type `Output` not found for `Three<(), [type error], [type error]>`
   --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs:5:16
diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr
index c81402a3dcc..ff65fd968c5 100644
--- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr
@@ -5,10 +5,10 @@ LL | fn f<F:Trait(isize) -> isize>(x: F) {}
    |        ^^^^^^^^^^^^ unexpected type argument
 
 error[E0220]: associated type `Output` not found for `Trait`
-  --> $DIR/unboxed-closure-sugar-wrong-trait.rs:5:24
+  --> $DIR/unboxed-closure-sugar-wrong-trait.rs:5:8
    |
 LL | fn f<F:Trait(isize) -> isize>(x: F) {}
-   |                        ^^^^^ associated type `Output` not found
+   |        ^^^^^^^^^^^^^^^^^^^^^ associated type `Output` not found
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/unspecified-self-in-trait-ref.stderr b/src/test/ui/unspecified-self-in-trait-ref.stderr
index 06370cec90e..b72d45ebdbf 100644
--- a/src/test/ui/unspecified-self-in-trait-ref.stderr
+++ b/src/test/ui/unspecified-self-in-trait-ref.stderr
@@ -25,8 +25,13 @@ LL |     let d = Bar::<usize, _>::lol();
 error[E0393]: the type parameter `A` must be explicitly specified
   --> $DIR/unspecified-self-in-trait-ref.rs:18:13
    |
-LL |     let e = Bar::<usize>::lol();
-   |             ^^^^^^^^^^^^^^^^^ missing reference to `A`
+LL | / pub trait Bar<X=usize, A=Self> {
+LL | |     fn foo(&self);
+LL | | }
+   | |_- type parameter `A` must be specified for this
+...
+LL |       let e = Bar::<usize>::lol();
+   |               ^^^ missing reference to `A`
    |
    = note: because of the default `Self` reference, type parameters must be specified on object types
 
diff --git a/src/test/ui/where-clauses/where-equality-constraints.stderr b/src/test/ui/where-clauses/where-equality-constraints.stderr
index c0241fe708f..54d6ad6a136 100644
--- a/src/test/ui/where-clauses/where-equality-constraints.stderr
+++ b/src/test/ui/where-clauses/where-equality-constraints.stderr
@@ -2,7 +2,7 @@ error: equality constraints are not yet supported in `where` clauses
   --> $DIR/where-equality-constraints.rs:1:14
    |
 LL | fn f() where u8 = u16 {}
-   |              ^^^^^^^^
+   |              ^^^^^^^^ not supported
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/20041
 
@@ -10,7 +10,7 @@ error: equality constraints are not yet supported in `where` clauses
   --> $DIR/where-equality-constraints.rs:3:14
    |
 LL | fn g() where for<'a> &'static (u8,) == u16, {}
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not supported
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/20041